fix typo
[software/lv2-mdametapiano.git] / src / mdaPiano.cpp
index 1a8f160..7341ee9 100644 (file)
 
 #include "mdaPianoCommon.h"
 #include "mdaPiano.h"
-
-#include <stdio.h>
-#include <math.h>
+#include <cstdlib> //for exit
 
 #define STRING_BUF 2048
-static const char* sample_file = "samples.raw";
-
 
 mdaPiano::mdaPiano(double rate)
   : LV2::Synth<mdaPianoVoice, mdaPiano>(p_n_ports, p_midi) {
 
-  cmax = 0x7F;  //just in case...
-
-  load_samples(&waves);
-  load_kgrp(kgrp);
-
-  notes[0] = EVENTS_DONE;
-  cpos = sustain = activevoices = 0;
-  comb = new float[256];
-
-  update();
-  suspend();
-}
-
-
-void mdaPiano::update()  //parameter change
-{
-  float * param = programs[curProgram].param;
-  size = (uint32_t)(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];
+  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"
+    };
 
-  fine = param[9] - 0.5f;
-  random = 0.077f * param[10] * param[10];
-  stretch = 0.000434f * (param[11] - 0.5f);
-
-  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 + (uint32_t)(24.9f * param[8]);
-}
+  for (unsigned char i=0; i<15; ++i) {
+    load_sample(&samples[i], sample_names[i]);
+  }
 
+  load_kgrp(kgrp);
 
-void mdaPiano::resume()
-{
-  Fs = getSampleRate();
-  iFs = 1.0f / Fs;
-  if(Fs > 64000.0f) cmax = 0xFF; else cmax = 0x7F;
-  memset(comb, 0, sizeof(float) * 256);
-}
+  for(uint32_t i=0; i<NVOICES; ++i) {
+    voices[i] = new mdaPianoVoice(rate, samples, kgrp);
+    add_voices(voices[i]);
+  }
 
+  sustain = 0;
 
-mdaPiano::~mdaPiano ()  //destroy any buffers...
-{
-  if(programs) delete [] programs;
-  if(comb) delete[] comb;
+  add_audio_outputs(p_left, p_right);
 }
 
-
-void mdaPiano::setParameter(uint32_t index, float value)
-{
-  programs[curProgram].param[index] = value;
-  update();
+//parameter change
+void mdaPiano::update() {
+  for (uint32_t v=0; v<NVOICES; ++v) {
+    voices[v]->update(Current);
+  }
 }
 
 
-void mdaPiano::process(float **inputs, float **outputs, uint32_t sampleFrames)
-{
-  float* out0 = outputs[0];
-  float* out1 = outputs[1];
-  uint32_t event=0, frame=0, frames, v;
-  float x, l, r;
-  uint32_t i;
-
-  while(frame<sampleFrames)
-  {
-    frames = notes[event++];
-    if(frames>sampleFrames) frames = sampleFrames;
-    frames -= frame;
-    frame += frames;
-
-    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 = 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 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;
       }
-      comb[cpos] = l + r;
-      ++cpos &= cmax;
-      x = cdep * comb[cpos];  //stereo simulator
-
-      *out0++ += l + x;
-      *out1++ += r - x;
     }
+  }
 
-    if(frame<sampleFrames)
+  //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)
     {
-      uint32_t note = notes[event++];
-      uint32_t vel  = notes[event++];
-      noteOn(note, vel);
+      return i;
     }
   }
-  for(v=0; v<activevoices; v++) if(voice[v].env < SILENCE) voice[v] = voice[--activevoices];
-  notes[0] = EVENTS_DONE;  //mark events buffer as done
+
+  //TODO: steal quietest note if all voices are used up
+  return 0;
 }
 
 
-void mdaPiano::processReplacing(float **inputs, float **outputs, uint32_t sampleFrames)
+void mdaPiano::setVolume(float value)
 {
-  float* out0 = outputs[0];
-  float* out1 = outputs[1];
-  uint32_t event=0, frame=0, frames, v;
-  float x, l, r;
-  uint32_t i;
-
-  while(frame<sampleFrames)
-  {
-    frames = notes[event++];
-    if(frames>sampleFrames) frames = sampleFrames;
-    frames -= frame;
-    frame += frames;
-
-    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++;
-      }
-      comb[cpos] = l + r;
-      ++cpos &= cmax;
-      x = cdep * comb[cpos];  //stereo simulator
-
-      *out0++ = l + x;
-      *out1++ = r - x;
-    }
-
-    if(frame<sampleFrames)
-    {
-      uint32_t note = notes[event++];
-      uint32_t 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
+  for (uint32_t v=0; v<NVOICES; ++v)
+    voices[v]->set_volume(value);
 }
 
 
-void mdaPiano::noteOn(uint32_t note, uint32_t velocity)
-{
-  float * param = programs[curProgram].param;
-  float l=99.0f;
-  uint32_t  v, vl=0, k, s;
+void mdaPiano::handle_midi(uint32_t size, unsigned char* data) {
+#ifdef DEBUG
+  printf("%d\n", data[1]);
+#endif
 
-  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; }
-      }
-    }
+  //discard invalid midi messages
+  if (size != 3)
+    return;
 
-    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 += (uint32_t)(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 = (uint32_t)(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
+  //receive on all channels
+  switch(data[0] & 0xf0)
   {
-    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]));
+    case 0x80: //note off
+      for (unsigned i = 0; i < NVOICES; ++i) {
+        if (voices[i]->get_key() == data[1]) {
+          voices[i]->release(data[2]);
+          break;
+        }
       }
-      else voice[v].note = SUSTAIN;
-    }
-  }
-}
-
+      break;
 
-uint32_t mdaPiano::processEvents(VstEvents* ev)
-{
-  uint32_t npos=0;
-
-  for (uint32_t 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
+    case 0x90: //note on
+      {
+        unsigned int v = find_free_voice(data[1], data[2]);
+        if (v < NVOICES) {
+          voices[v]->on(data[1], data[2]);
+        }
         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]));
+    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;
+          }
 
-          case 0x07:  //volume
-            volume = 0.00002f * (float)(midiData[2] * midiData[2]);
-            break;
+        case 0x07:  //volume
+          setVolume(0.00002f * (float)(data[2] * data[2]));
+          break;
 
-          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;
+        case 0x40:  //sustain pedal
+        case 0x42:  //sostenuto pedal
+          sustain = data[2] & 0x40;
 
-          default:  //all notes off
-            if(midiData[1]>0x7A)
-            {
-              for(uint32_t v=0; v<NVOICES; v++) voice[v].dec=0.99f;
-              sustain = 0;
-              muff = 160.0f;
+          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;
-        }
-        break;
-
-      default: break;
-    }
+          }
+          break;
+
+        //all sound off
+        case 0x78:
+        //all notes off
+        case 0x7b:
+        default:
+          for(short v=0; v<NVOICES; v++) {
+            voices[v]->reset();
+          }
+          break;
+      }
+      break;
 
-    if(npos>EVENTBUFFER) npos -= 3; //discard events if buffer full!!
-    event++; //?
+    default: break;
   }
-  notes[npos] = EVENTS_DONE;
-  return 1;
 }
 
 
-// TODO: load this from a file
+// TODO: load keymapping from a file
 void mdaPiano::load_kgrp(KGRP *kgrp)
 {
-  //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;
+  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;
 }
 
 
-void mdaPiano::load_samples(short **buffer)
+void mdaPiano::load_sample(Sample *s, const char* name)
 {
   FILE *f;
   long num, size;
@@ -387,7 +192,7 @@ void mdaPiano::load_samples(short **buffer)
 
   strncpy(filepath, bundle_path(), STRING_BUF);
   strncat(filepath,
-          sample_file,
+          name,
           STRING_BUF - strlen(filepath));
   f = fopen(filepath, "rb");
   if (f == NULL) {
@@ -401,18 +206,24 @@ void mdaPiano::load_samples(short **buffer)
   rewind(f);
 
   // allocate memory to contain the whole file
-  *buffer = (short*) malloc (sizeof(short)*size);
-  if (*buffer == NULL) {
+  s->buffer = (short*) malloc (sizeof(short)*size);
+  if (s->buffer == NULL) {
     fputs("Memory error", stderr);
     exit(2);
   }
 
   // copy the file into the buffer
-  num = fread(*buffer, 1, size, f);
+  num = fread(s->buffer, 1, size, f);
   if (num != size) {
     fputs ("Reading error", stderr);
     exit (3);
   }
   fclose (f);
+
+  // 16 bit
+  s->size = size / 2;
+
   return;
 }
+
+static int _ = mdaPiano::register_class(p_uri);