fix typo
[software/lv2-mdametapiano.git] / src / mdaPiano.cpp
index 04174c5..7341ee9 100644 (file)
  * ==================================================
  */
 
-#include "mdaPianoData.h"
+#include "mdaPianoCommon.h"
 #include "mdaPiano.h"
+#include <cstdlib> //for exit
 
-#include <stdio.h>
-#include <math.h>
+#define STRING_BUF 2048
 
+mdaPiano::mdaPiano(double rate)
+  : LV2::Synth<mdaPianoVoice, mdaPiano>(p_n_ports, p_midi) {
 
-//#include "AEffEditor.hpp" ////for GUI
+  static const char* sample_names[] =
+    { "0c.raw", "0e.raw", "0g.raw"
+    , "1c.raw", "1e.raw", "1g.raw"
+    , "2c.raw", "2e.raw", "2g.raw"
+    , "3c.raw", "3e.raw", "3g.raw"
+    , "4c.raw", "4e.raw", "4a.raw"
+    };
 
-AudioEffect *createEffectInstance(audioMasterCallback audioMaster)
-{
-  return new mdaPiano(audioMaster);
-}
-
-mdaPianoProgram::mdaPianoProgram()
-{
-  param[0]  = 0.50f; //Decay
-  param[1]  = 0.50f; //Release
-  param[2]  = 0.50f; //Hardness
-
-  param[3]  = 0.50f; //Vel>Hard
-  param[4]  = 1.00f; //Muffle
-  param[5]  = 0.50f; //Vel>Muff
-
-  param[6]  = 0.33f; //Vel Curve
-  param[7]  = 0.50f; //Stereo
-  param[8]  = 0.33f; //Max Poly
-
-  param[9]  = 0.50f; //Tune
-  param[10] = 0.00f; //Random
-  param[11] = 0.50f; //Stretch
-
-  strcpy (name, "mda Piano");
-}
-
-
-mdaPiano::mdaPiano(audioMasterCallback audioMaster) : AudioEffectX(audioMaster, NPROGS, NPARAMS)
-{
-  Fs = 44100.0f;  iFs = 1.0f/Fs;  cmax = 0x7F;  //just in case...
-
-  programs = new mdaPianoProgram[NPROGS];
-  if(programs)
-  {
-    //fill patches...
-    VstInt32 i=0;
-    //TODO: load initial values from default preset
-    fillpatch(i++, "mda Piano",        0.500f, 0.500f, 0.500f, 0.5f, 0.803f, 0.251f, 0.376f, 0.500f, 0.330f, 0.500f, 0.246f, 0.500f);
-    setProgram(0);
+  for (unsigned char i=0; i<15; ++i) {
+    load_sample(&samples[i], sample_names[i]);
   }
 
-  if(audioMaster)
-  {
-    setNumInputs(0);
-    setNumOutputs(NOUTS);
-    canProcessReplacing();
-    isSynth();
-    setUniqueID('MDAp');  ///
-  }
+  load_kgrp(kgrp);
 
-  waves = pianoData;
-
-
-  //Waveform data and keymapping is hard-wired in *this* version
-  kgrp[ 0].root = 36;  kgrp[ 0].high = 37;  kgrp[ 0].pos = 0;       kgrp[ 0].end = 36275;   kgrp[ 0].loop = 14774;
-  kgrp[ 1].root = 40;  kgrp[ 1].high = 41;  kgrp[ 1].pos = 36278;   kgrp[ 1].end = 83135;   kgrp[ 1].loop = 16268;
-  kgrp[ 2].root = 43;  kgrp[ 2].high = 45;  kgrp[ 2].pos = 83137;   kgrp[ 2].end = 146756;  kgrp[ 2].loop = 33541;
-  kgrp[ 3].root = 48;  kgrp[ 3].high = 49;  kgrp[ 3].pos = 146758;  kgrp[ 3].end = 204997;  kgrp[ 3].loop = 21156;
-  kgrp[ 4].root = 52;  kgrp[ 4].high = 53;  kgrp[ 4].pos = 204999;  kgrp[ 4].end = 244908;  kgrp[ 4].loop = 17191;
-  kgrp[ 5].root = 55;  kgrp[ 5].high = 57;  kgrp[ 5].pos = 244910;  kgrp[ 5].end = 290978;  kgrp[ 5].loop = 23286;
-  kgrp[ 6].root = 60;  kgrp[ 6].high = 61;  kgrp[ 6].pos = 290980;  kgrp[ 6].end = 342948;  kgrp[ 6].loop = 18002;
-  kgrp[ 7].root = 64;  kgrp[ 7].high = 65;  kgrp[ 7].pos = 342950;  kgrp[ 7].end = 391750;  kgrp[ 7].loop = 19746;
-  kgrp[ 8].root = 67;  kgrp[ 8].high = 69;  kgrp[ 8].pos = 391752;  kgrp[ 8].end = 436915;  kgrp[ 8].loop = 22253;
-  kgrp[ 9].root = 72;  kgrp[ 9].high = 73;  kgrp[ 9].pos = 436917;  kgrp[ 9].end = 468807;  kgrp[ 9].loop = 8852;
-  kgrp[10].root = 76;  kgrp[10].high = 77;  kgrp[10].pos = 468809;  kgrp[10].end = 492772;  kgrp[10].loop = 9693;
-  kgrp[11].root = 79;  kgrp[11].high = 81;  kgrp[11].pos = 492774;  kgrp[11].end = 532293;  kgrp[11].loop = 10596;
-  kgrp[12].root = 84;  kgrp[12].high = 85;  kgrp[12].pos = 532295;  kgrp[12].end = 560192;  kgrp[12].loop = 6011;
-  kgrp[13].root = 88;  kgrp[13].high = 89;  kgrp[13].pos = 560194;  kgrp[13].end = 574121;  kgrp[13].loop = 3414;
-  kgrp[14].root = 93;  kgrp[14].high = 999; kgrp[14].pos = 574123;  kgrp[14].end = 586343;  kgrp[14].loop = 2399;
-
-  //initialise...
-  for(VstInt32 v=0; v<NVOICES; v++)
-  {
-    voice[v].env = 0.0f;
-    voice[v].dec = 0.99f; //all notes off
+  for(uint32_t i=0; i<NVOICES; ++i) {
+    voices[i] = new mdaPianoVoice(rate, samples, kgrp);
+    add_voices(voices[i]);
   }
-  notes[0] = EVENTS_DONE;
-  volume = 0.2f;
-  muff = 160.0f;
-  cpos = sustain = activevoices = 0;
-  comb = new float[256];
-
-  guiUpdate = 0;
-
-  update();
-  suspend();
-}
-
-
-void mdaPiano::update()  //parameter change
-{
-  float * param = programs[curProgram].param;
-  size = (VstInt32)(12.0f * param[2] - 6.0f);
-  sizevel = 0.12f * param[3];
-  muffvel = param[5] * param[5] * 5.0f;
-
-  velsens = 1.0f + param[6] + param[6];
-  if(param[6] < 0.25f) velsens -= 0.75f - 3.0f * param[6];
 
-  fine = param[9] - 0.5f;
-  random = 0.077f * param[10] * param[10];
-  stretch = 0.000434f * (param[11] - 0.5f);
+  sustain = 0;
 
-  cdep = param[7] * param[7];
-  trim = 1.50f - 0.79f * cdep;
-  width = 0.04f * param[7];  if(width > 0.03f) width = 0.03f;
-
-  poly = 8 + (VstInt32)(24.9f * param[8]);
+  add_audio_outputs(p_left, p_right);
 }
 
-
-void mdaPiano::resume()
-{
-  Fs = getSampleRate();
-  iFs = 1.0f / Fs;
-  if(Fs > 64000.0f) cmax = 0xFF; else cmax = 0x7F;
-  memset(comb, 0, sizeof(float) * 256);
-
-  DECLARE_VST_DEPRECATED (wantEvents) ();
-}
-
-
-mdaPiano::~mdaPiano ()  //destroy any buffers...
-{
-  if(programs) delete [] programs;
-  if(comb) delete[] comb;
-}
-
-
-void mdaPiano::setProgram(VstInt32 program)
-{
-  curProgram = program;
-  update();
-
-  // TODO: guiUpdate ???
-}
-
-
-void mdaPiano::setParameter(VstInt32 index, float value)
-{
-  programs[curProgram].param[index] = value;
-  update();
-
-//  if(editor) editor->postUpdate(); //For GUI
-
-  guiUpdate = index + 0x100 + (guiUpdate & 0xFFFF00);
-}
-
-
-void mdaPiano::fillpatch(VstInt32 p, char *name, float p0, float p1, float p2, float p3, float p4,
-                      float p5, float p6, float p7, float p8, float p9, float p10,float p11)
-{
-  strcpy(programs[p].name, name);
-  programs[p].param[0] = p0;  programs[p].param[1] = p1;
-  programs[p].param[2] = p2;  programs[p].param[3] = p3;
-  programs[p].param[4] = p4;  programs[p].param[5] = p5;
-  programs[p].param[6] = p6;  programs[p].param[7] = p7;
-  programs[p].param[8] = p8;  programs[p].param[9] = p9;
-  programs[p].param[10]= p10; programs[p].param[11] = p11;
-}
-
-
-float mdaPiano::getParameter(VstInt32 index)     { return programs[curProgram].param[index]; }
-void  mdaPiano::setProgramName(char *name)   { strcpy(programs[curProgram].name, name); }
-void  mdaPiano::getProgramName(char *name)   { strcpy(name, programs[curProgram].name); }
-void  mdaPiano::setBlockSize(VstInt32 blockSize) {  AudioEffectX::setBlockSize(blockSize); }
-bool  mdaPiano::getEffectName(char* name)    { strcpy(name, "Piano"); return true; }
-bool  mdaPiano::getVendorString(char* text)  {  strcpy(text, "mda"); return true; }
-bool  mdaPiano::getProductString(char* text) { strcpy(text, "mda Piano"); return true; }
-
-
-bool mdaPiano::getOutputProperties(VstInt32 index, VstPinProperties* properties)
-{
-  if(index<NOUTS)
-  {
-    if(index) sprintf(properties->label, "Piano R");
-         else sprintf(properties->label, "Piano L");
-    properties->flags = kVstPinIsActive;
-    if(index<2) properties->flags |= kVstPinIsStereo; //make channel 1+2 stereo
-    return true;
+//parameter change
+void mdaPiano::update() {
+  for (uint32_t v=0; v<NVOICES; ++v) {
+    voices[v]->update(Current);
   }
-  return false;
 }
 
 
-bool mdaPiano::getProgramNameIndexed(VstInt32 category, VstInt32 index, char* text)
-{
-  if ((unsigned int)index < NPROGS)
-  {
-    strcpy(text, programs[index].name);
-    return true;
-  }
-  return false;
-}
-
-
-bool mdaPiano::copyProgram(VstInt32 destination)
-{
-  if(destination<NPROGS)
-  {
-    programs[destination] = programs[curProgram];
-    return true;
+unsigned mdaPiano::find_free_voice(unsigned char key, unsigned char velocity) {
+  //is this a retriggered note during sustain?
+  if (sustain) {
+    for (unsigned i = 0; i < NVOICES; ++i) {
+      if ((voices[i]->get_key() == key) && (voices[i]->is_sustained())) {
+        return i;
+      }
+    }
   }
-  return false;
-}
-
-
-VstInt32 mdaPiano::canDo(char* text)
-{
-  if(strcmp(text, "receiveVstEvents") == 0) return 1;
-  if(strcmp(text, "receiveVstMidiEvent") == 0) return 1;
-  return -1;
-}
-
-
-void mdaPiano::getParameterName(VstInt32 index, char *label)
-{
-  switch (index)
-  {
-    case  0: strcpy(label, "Envelope Decay"); break;
-    case  1: strcpy(label, "Envelope Release"); break;
-    case  2: strcpy(label, "Hardness Offset"); break;
-
-    case  3: strcpy(label, "Velocity to Hardness"); break;
-    case  4: strcpy(label, "Muffling Filter"); break;
-    case  5: strcpy(label, "Velocity to Muffling"); break;
-
-    case  6: strcpy(label, "Velocity Sensitivity"); break;
-    case  7: strcpy(label, "Stereo Width"); break;
-    case  8: strcpy(label, "Polyphony"); break;
-
-    case  9: strcpy(label, "Fine Tuning"); break;
-    case 10: strcpy(label, "Random Detuning"); break;
-    default: strcpy(label, "Stretch Tuning"); break;
-   }
-}
-
 
-void mdaPiano::getParameterDisplay(VstInt32 index, char *text)
-{
-  char string[16];
-  float * param = programs[curProgram].param;
-
-  switch(index)
-  {
-    case  4: sprintf(string, "%.0f", 100.0f - 100.0f * param[index]); break;
-    case  7: sprintf(string, "%.0f", 200.0f * param[index]); break;
-    case  8: sprintf(string, "%d", poly); break;
-    case 10: sprintf(string, "%.1f",  50.0f * param[index] * param[index]); break;
-    case  2:
-    case  9:
-    case 11: sprintf(string, "%+.1f", 100.0f * param[index] -  50.0f); break;
-    default: sprintf(string, "%.0f", 100.0f * param[index]);
+  //take the next free voice if
+  // ... notes are sustained but not this new one
+  // ... notes are not sustained
+  for (unsigned i = 0; i < NVOICES; ++i) {
+    if (voices[i]->get_key() == LV2::INVALID_KEY)
+    {
+      return i;
+    }
   }
-  string[8] = 0;
-  strcpy(text, (char *)string);
-}
-
 
-void mdaPiano::getParameterLabel(VstInt32 index, char *label)
-{
-  switch(index)
-  {
-    case  8: strcpy(label, "voices"); break;
-    case  9:
-    case 10:
-    case 11: strcpy(label, "cents"); break;
-    default: strcpy(label, "%");
-  }
+  //TODO: steal quietest note if all voices are used up
+  return 0;
 }
 
 
-void mdaPiano::guiGetDisplay(VstInt32 index, char *label)
+void mdaPiano::setVolume(float value)
 {
-  getParameterName(index,  label);
-  strcat(label, " = ");
-  getParameterDisplay(index, label + strlen(label));
-  getParameterLabel(index, label + strlen(label));
+  for (uint32_t v=0; v<NVOICES; ++v)
+    voices[v]->set_volume(value);
 }
 
 
+void mdaPiano::handle_midi(uint32_t size, unsigned char* data) {
+#ifdef DEBUG
+  printf("%d\n", data[1]);
+#endif
 
-void mdaPiano::process(float **inputs, float **outputs, VstInt32 sampleFrames)
-{
-  float* out0 = outputs[0];
-  float* out1 = outputs[1];
-  VstInt32 event=0, frame=0, frames, v;
-  float x, l, r;
-  VstInt32 i;
+  //discard invalid midi messages
+  if (size != 3)
+    return;
 
-  while(frame<sampleFrames)
+  //receive on all channels
+  switch(data[0] & 0xf0)
   {
-    frames = notes[event++];
-    if(frames>sampleFrames) frames = sampleFrames;
-    frames -= frame;
-    frame += frames;
-
-    while(--frames>=0)
-    {
-      VOICE *V = voice;
-      l = r = 0.0f;
+    case 0x80: //note off
+      for (unsigned i = 0; i < NVOICES; ++i) {
+        if (voices[i]->get_key() == data[1]) {
+          voices[i]->release(data[2]);
+          break;
+        }
+      }
+      break;
 
-      for(v=0; v<activevoices; v++)
+    case 0x90: //note on
       {
-        V->frac += V->delta;  //integer-based linear interpolation
-        V->pos += V->frac >> 16;
-        V->frac &= 0xFFFF;
-        if(V->pos > V->end) V->pos -= V->loop;
-        i = waves[V->pos];
-        i = (i << 7) + (V->frac >> 9) * (waves[V->pos + 1] - i) + 0x40400000;
-        x = V->env * (*(float *)&i - 3.0f);  //fast int->float
-
-        V->env = V->env * V->dec;  //envelope
-        V->f0 += V->ff * (x + V->f1 - V->f0);  //muffle filter
-        V->f1 = x;
-
-        l += V->outl * V->f0;
-        r += V->outr * V->f0;
-
-        V++;
+        unsigned int v = find_free_voice(data[1], data[2]);
+        if (v < NVOICES) {
+          voices[v]->on(data[1], data[2]);
+        }
+        break;
       }
-      comb[cpos] = l + r;
-      ++cpos &= cmax;
-      x = cdep * comb[cpos];  //stereo simulator
-
-      *out0++ += l + x;
-      *out1++ += r - x;
-    }
-
-    if(frame<sampleFrames)
-    {
-      VstInt32 note = notes[event++];
-      VstInt32 vel  = notes[event++];
-      noteOn(note, vel);
-    }
-  }
-  for(v=0; v<activevoices; v++) if(voice[v].env < SILENCE) voice[v] = voice[--activevoices];
-  notes[0] = EVENTS_DONE;  //mark events buffer as done
-}
 
+    case 0xB0: //controller
+      switch(data[1])
+      {
+        case 0x01:  //mod wheel
+        case 0x43:  //soft pedal
+          {
+            float muff = 0.01f * (float)((127 - data[2]) * (127 - data[2]));
+            for (unsigned i = 0; i < NVOICES; ++i) {
+              voices[i]->set_muff(muff);
+            }
+            break;
+          }
 
-void mdaPiano::processReplacing(float **inputs, float **outputs, VstInt32 sampleFrames)
-{
-  float* out0 = outputs[0];
-  float* out1 = outputs[1];
-  VstInt32 event=0, frame=0, frames, v;
-  float x, l, r;
-  VstInt32 i;
+        case 0x07:  //volume
+          setVolume(0.00002f * (float)(data[2] * data[2]));
+          break;
 
-  while(frame<sampleFrames)
-  {
-    frames = notes[event++];
-    if(frames>sampleFrames) frames = sampleFrames;
-    frames -= frame;
-    frame += frames;
+        case 0x40:  //sustain pedal
+        case 0x42:  //sostenuto pedal
+          sustain = data[2] & 0x40;
 
-    while(--frames>=0)
-    {
-      VOICE *V = voice;
-      l = r = 0.0f;
-
-      for(v=0; v<activevoices; v++)
-      {
-        V->frac += V->delta;  //integer-based linear interpolation
-        V->pos += V->frac >> 16;
-        V->frac &= 0xFFFF;
-        if(V->pos > V->end) V->pos -= V->loop;
-        //i = (i << 7) + (V->frac >> 9) * (waves[V->pos + 1] - i) + 0x40400000;   //not working on intel mac !?!
-  i = waves[V->pos] + ((V->frac * (waves[V->pos + 1] - waves[V->pos])) >> 16);
-  x = V->env * (float)i / 32768.0f;
-        //x = V->env * (*(float *)&i - 3.0f);  //fast int->float
-
-        V->env = V->env * V->dec;  //envelope
-        V->f0 += V->ff * (x + V->f1 - V->f0);  //muffle filter
-        V->f1 = x;
-
-        l += V->outl * V->f0;
-        r += V->outr * V->f0;
-
- if(!(l > -2.0f) || !(l < 2.0f))
- {
-   printf("what is this shit?   %d,  %f,  %f\n", i, x, V->f0);
-   l = 0.0f;
- }
-if(!(r > -2.0f) || !(r < 2.0f))
- {
-   r = 0.0f;
- }
-
-        V++;
+          for (unsigned i = 0; i < NVOICES; ++i) {
+            voices[i]->set_sustain(sustain);
+            //if pedal was released: dampen sustained notes
+            if((sustain==0) && (voices[i]->is_sustained())) {
+              voices[i]->release(0);
+            }
+          }
+          break;
+
+        //all sound off
+        case 0x78:
+        //all notes off
+        case 0x7b:
+        default:
+          for(short v=0; v<NVOICES; v++) {
+            voices[v]->reset();
+          }
+          break;
       }
-      comb[cpos] = l + r;
-      ++cpos &= cmax;
-      x = cdep * comb[cpos];  //stereo simulator
+      break;
 
-      *out0++ = l + x;
-      *out1++ = r - x;
-    }
-
-    if(frame<sampleFrames)
-    {
-      VstInt32 note = notes[event++];
-      VstInt32 vel  = notes[event++];
-      noteOn(note, vel);
-    }
+    default: break;
   }
-  for(v=0; v<activevoices; v++) if(voice[v].env < SILENCE) voice[v] = voice[--activevoices];
-  notes[0] = EVENTS_DONE;  //mark events buffer as done
 }
 
 
-void mdaPiano::noteOn(VstInt32 note, VstInt32 velocity)
+// TODO: load keymapping from a file
+void mdaPiano::load_kgrp(KGRP *kgrp)
 {
-  float * param = programs[curProgram].param;
-  float l=99.0f;
-  VstInt32  v, vl=0, k, s;
-
-  if(velocity>0)
-  {
-    if(activevoices < poly) //add a note
-    {
-      vl = activevoices;
-      activevoices++;
-    }
-    else //steal a note
-    {
-      for(v=0; v<poly; v++)  //find quietest voice
-      {
-        if(voice[v].env < l) { l = voice[v].env;  vl = v; }
-      }
-    }
-
-    k = (note - 60) * (note - 60);
-    l = fine + random * ((float)(k % 13) - 6.5f);  //random & fine tune
-    if(note > 60) l += stretch * (float)k; //stretch
-
-    s = size;
-    if(velocity > 40) s += (VstInt32)(sizevel * (float)(velocity - 40));
-
-    k = 0;
-    while(note > (kgrp[k].high + s)) k++;  //find keygroup
-
-    l += (float)(note - kgrp[k].root); //pitch
-    l = 22050.0f * iFs * (float)exp(0.05776226505 * l);
-    voice[vl].delta = (VstInt32)(65536.0f * l);
-    voice[vl].frac = 0;
-    voice[vl].pos = kgrp[k].pos;
-    voice[vl].end = kgrp[k].end;
-    voice[vl].loop = kgrp[k].loop;
-
-    voice[vl].env = (0.5f + velsens) * (float)pow(0.0078f * velocity, velsens); //velocity
-
-    l = 50.0f + param[4] * param[4] * muff + muffvel * (float)(velocity - 64); //muffle
-    if(l < (55.0f + 0.25f * (float)note)) l = 55.0f + 0.25f * (float)note;
-    if(l > 210.0f) l = 210.0f;
-    voice[vl].ff = l * l * iFs;
-    voice[vl].f0 = voice[vl].f1 = 0.0f;
-
-    voice[vl].note = note; //note->pan
-    if(note <  12) note = 12;
-    if(note > 108) note = 108;
-    l = volume * trim;
-    voice[vl].outr = l + l * width * (float)(note - 60);
-    voice[vl].outl = l + l - voice[vl].outr;
-
-    if(note < 44) note = 44; //limit max decay length
-    l = 2.0f * param[0];
-    if(l < 1.0f) l += 0.25f - 0.5f * param[0];
-    voice[vl].dec = (float)exp(-iFs * exp(-0.6 + 0.033 * (double)note - l));
-  }
-  else //note off
-  {
-    for(v=0; v<NVOICES; v++) if(voice[v].note==note) //any voices playing that note?
-    {
-      if(sustain==0)
-      {
-        if(note < 94 || note == SUSTAIN) //no release on highest notes
-          voice[v].dec = (float)exp(-iFs * exp(2.0 + 0.017 * (double)note - 2.0 * param[1]));
-      }
-      else voice[v].note = SUSTAIN;
-    }
-  }
+  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;
+  kgrp[ 3].root = 48;  kgrp[ 3].high = 49;  kgrp[ 3].loop = 21156;
+  kgrp[ 4].root = 52;  kgrp[ 4].high = 53;  kgrp[ 4].loop = 17191;
+  kgrp[ 5].root = 55;  kgrp[ 5].high = 57;  kgrp[ 5].loop = 23286;
+  kgrp[ 6].root = 60;  kgrp[ 6].high = 61;  kgrp[ 6].loop = 18002;
+  kgrp[ 7].root = 64;  kgrp[ 7].high = 65;  kgrp[ 7].loop = 19746;
+  kgrp[ 8].root = 67;  kgrp[ 8].high = 69;  kgrp[ 8].loop = 22253;
+  kgrp[ 9].root = 72;  kgrp[ 9].high = 73;  kgrp[ 9].loop = 8852;
+  kgrp[10].root = 76;  kgrp[10].high = 77;  kgrp[10].loop = 9693;
+  kgrp[11].root = 79;  kgrp[11].high = 81;  kgrp[11].loop = 10596;
+  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;
 }
 
 
-VstInt32 mdaPiano::processEvents(VstEvents* ev)
+void mdaPiano::load_sample(Sample *s, const char* name)
 {
-  VstInt32 npos=0;
+  FILE *f;
+  long num, size;
+  char filepath[STRING_BUF];
 
-  for (VstInt32 i=0; i<ev->numEvents; i++)
-  {
-    if((ev->events[i])->type != kVstMidiType) continue;
-    VstMidiEvent* event = (VstMidiEvent*)ev->events[i];
-    char* midiData = event->midiData;
-
-    switch(midiData[0] & 0xf0) //status byte (all channels)
-    {
-      case 0x80: //note off
-        notes[npos++] = event->deltaFrames; //delta
-        notes[npos++] = midiData[1] & 0x7F; //note
-        notes[npos++] = 0;                  //vel
-        break;
-
-      case 0x90: //note on
-        notes[npos++] = event->deltaFrames; //delta
-        notes[npos++] = midiData[1] & 0x7F; //note
-        notes[npos++] = midiData[2] & 0x7F; //vel
-        break;
-
-      case 0xB0: //controller
-        switch(midiData[1])
-        {
-          case 0x01:  //mod wheel
-          case 0x43:  //soft pedal
-            muff = 0.01f * (float)((127 - midiData[2]) * (127 - midiData[2]));
-            break;
-
-          case 0x07:  //volume
-            volume = 0.00002f * (float)(midiData[2] * midiData[2]);
-            break;
+  strncpy(filepath, bundle_path(), STRING_BUF);
+  strncat(filepath,
+          name,
+          STRING_BUF - strlen(filepath));
+  f = fopen(filepath, "rb");
+  if (f == NULL) {
+    fputs("File error", stderr);
+    exit(1);
+  }
 
-          case 0x40:  //sustain pedal
-          case 0x42:  //sustenuto pedal
-            sustain = midiData[2] & 0x40;
-            if(sustain==0)
-            {
-              notes[npos++] = event->deltaFrames;
-              notes[npos++] = SUSTAIN; //end all sustained notes
-              notes[npos++] = 0;
-            }
-            break;
+  // obtain file size
+  fseek(f, 0, SEEK_END);
+  size = ftell(f);
+  rewind(f);
 
-          default:  //all notes off
-            if(midiData[1]>0x7A)
-            {
-              for(VstInt32 v=0; v<NVOICES; v++) voice[v].dec=0.99f;
-              sustain = 0;
-              muff = 160.0f;
-            }
-            break;
-        }
-        break;
+  // allocate memory to contain the whole file
+  s->buffer = (short*) malloc (sizeof(short)*size);
+  if (s->buffer == NULL) {
+    fputs("Memory error", stderr);
+    exit(2);
+  }
 
-      case 0xC0: //program change
-        if(midiData[1]<NPROGS) setProgram(midiData[1]);
-        break;
+  // copy the file into the buffer
+  num = fread(s->buffer, 1, size, f);
+  if (num != size) {
+    fputs ("Reading error", stderr);
+    exit (3);
+  }
+  fclose (f);
 
-      default: break;
-    }
+  // 16 bit
+  s->size = size / 2;
 
-    if(npos>EVENTBUFFER) npos -= 3; //discard events if buffer full!!
-    event++; //?
-  }
-  notes[npos] = EVENTS_DONE;
-  return 1;
+  return;
 }
 
+static int _ = mdaPiano::register_class(p_uri);