[AD] digmid.c patch

[ Thread Index | Date Index | More lists.liballeg.org/allegro-developers Archives ]


Here's a patch for digmid.c. This hopefully reduces the CPU load for
note-on events. For one, it takes advantage of the fact that drum
samples use a fixed frequency by working out the end frequency once when
the sample's loaded. Also, it won't interpolate between two notes if
there's no pitch bend. As well, I added a different version of the
inline scale64 function that uses real 64-bit math for systems that use
multithreading, instead of the heftier 32-bit only version that's been
there since the DOS-only code (which was only there due to interrupt
context restrictions on FPU math and 64-bit divides).

- Kitty Cat

--- digmid.c	2004-04-27 04:45:05.000000000 -0700
+++ digmid.c	2004-04-27 04:32:41.000000000 -0700
@@ -129,6 +129,79 @@
 
 
 
+/* scale64:
+ *  Evalulates a*b/c using 64 bit arithmetic. This is used in an interrupt
+ *  context, so we have to do it ourselves rather than relying on compiler
+ *  support or floating point (it is impossible to reliably lock the
+ *  compiler helpers that implement a 64 bit divide, and it isn't safe to
+ *  use the i386 FPU stack in an interrupt context). Multithreaded systems
+ *  are not bound by this restriction however, so we use 64 bit math there.
+ */
+#if !(defined ALLEGRO_MULTITHREADED)
+static INLINE unsigned long scale64(unsigned long a, unsigned long b, unsigned long c)
+{
+   unsigned long al = a & 0xFFFF;
+   unsigned long ah = a >> 16;
+   unsigned long bl = b & 0xFFFF;
+   unsigned long bh = b >> 16;
+   unsigned long rl, rh, r, s, t, o;
+
+   /* 64 bit multiply */
+   rl = al*bl;
+   rh = ah*bh;
+
+   t = al*bh;
+   o = rl;
+   rh += (t >> 16);
+   rl += (t << 16);
+   if (rl < o)
+      rh++;
+
+   t = ah*bl;
+   o = rl;
+   rh += (t >> 16);
+   rl += (t << 16);
+   if (rl < o)
+      rh++;
+
+   /* 64 bit divide */
+   s = 0x80000000;
+   t = rh;
+   r = 0;
+
+   while (s) {
+      o = t;
+      t -= c;
+
+      if (t > o)
+	 t = o;
+      else
+	 r |= s;
+
+      t <<= 1;
+      if (rl & s)
+	 t |= 1;
+
+      s >>= 1;
+   }
+
+   return r << 1;
+}
+#else
+static INLINE unsigned long scale64(unsigned long a, unsigned long b, unsigned long c)
+{
+   LONG_LONG ret;
+
+   ret = a;
+   ret *= b;
+   ret /= c;
+
+   return ret;
+}
+#endif
+
+
+
 /* load_patch:
  *  Reads a GUS format patch file from disk.
  */
@@ -293,6 +366,25 @@
       p->extra[i]->scale_freq = pack_igetw(f);     /* scale values */
       p->extra[i]->scale_factor = pack_igetw(f);
 
+      /* Drums use a static frequency */
+      if(drum) {
+	 unsigned long freq = scale64(ftbl[drum-1], p->sample[i]->freq, p->extra[i]->base_note);
+
+	 /* frequency scaling */
+	 if (p->extra[i]->scale_factor != 1024) {
+	    unsigned long f1 = scale64(p->sample[i]->freq, p->extra[i]->scale_freq, 60);
+	    freq -= f1;
+	    freq = scale64(freq, p->extra[i]->scale_factor, 1024);
+	    freq += f1;
+	 }
+
+	 /* lower by an octave if we are going to overflow */
+	 while (freq >= (1<<19)-1)
+	    freq /= 2;
+
+	 p->sample[i]->freq = freq;
+      }
+
       pack_fread(buf, 36, f);                      /* skip reserved */
 
       if (p->sample[i]->bits == 16) {              /* adjust 16 bit loops */
@@ -557,7 +649,7 @@
 	    if (i < 256) {
 	       /* load this patch */
 	       f = pack_fopen_chunk(f, FALSE);
-	       patch[i] = load_patch(f, (i >= 128));
+	       patch[i] = load_patch(f, ((i > 127) ? (i - 127) : 0));
 	       f = pack_fclose_chunk(f);
 
 	       for (j=i+1; j<256; j++) {
@@ -595,7 +687,7 @@
 
 	    f = pack_fopen(filename, F_READ);
 	    if (f) {
-	       patch[i] = load_patch(f, (i >= 128));
+	       patch[i] = load_patch(f, ((i > 127) ? (i - 127) : 0));
 	       pack_fclose(f);
 	    }
 
@@ -615,65 +707,6 @@
 
 
 
-/* scale64:
- *  Evalulates a*b/c using 64 bit arithmetic. This is used in an interrupt
- *  context, so we have to do it ourselves rather than relying on compiler
- *  support or floating point (it is impossible to reliably lock the
- *  compiler helpers that implement a 64 bit divide, and it isn't safe to
- *  use the i386 FPU stack in an interrupt context).
- */
-static INLINE unsigned long scale64(unsigned long a, unsigned long b, unsigned long c)
-{
-   unsigned long al = a & 0xFFFF;
-   unsigned long ah = a >> 16;
-   unsigned long bl = b & 0xFFFF;
-   unsigned long bh = b >> 16;
-   unsigned long rl, rh, r, s, t, o;
-
-   /* 64 bit multiply */
-   rl = al*bl;
-   rh = ah*bh;
-
-   t = al*bh;
-   o = rl;
-   rh += (t >> 16);
-   rl += (t << 16);
-   if (rl < o)
-      rh++;
-
-   t = ah*bl;
-   o = rl;
-   rh += (t >> 16);
-   rl += (t << 16);
-   if (rl < o)
-      rh++;
-
-   /* 64 bit divide */
-   s = 0x80000000;
-   t = rh;
-   r = 0;
-
-   while (s) {
-      o = t;
-      t -= c;
-
-      if (t > o)
-	 t = o;
-      else
-	 r |= s;
-
-      t <<= 1;
-      if (rl & s)
-	 t |= 1;
-
-      s >>= 1;
-   }
-
-   return r << 1;
-}
-
-
-
 /* digmid_freq:
  *  Helper for converting note numbers to sample frequencies.
  */ 
@@ -684,18 +717,16 @@
    sfreq = s->freq;
    base_note = e->base_note;
 
-   if (inst > 127) { 
-      /* drums use a fixed frequency */
-      freq = scale64(ftbl[inst-128], sfreq, base_note);
-   }
-   else {
-      /* calculate frequency */
+   /* calculate frequency */
+   if(bend) {
       f1 = scale64(ftbl[note], sfreq, base_note);
       f2 = scale64(ftbl[note+1], sfreq, base_note);
 
       /* quick pitch bend method - ~.035% error - acceptable? */
       freq = ((f1*(4096-bend)) + (f2*bend)) / 4096;
    }
+   else
+      freq = scale64(ftbl[note], sfreq, base_note);
 
    /* frequency scaling */
    if (e->scale_factor != 1024) {
@@ -733,10 +764,13 @@
    s = patch[inst]->sample[snum];
    e = patch[inst]->extra[snum];
 
-   freq = digmid_freq(inst, s, e, note, bend);
-
    if (inst > 127)
+   {
       pan = e->pan;
+      freq = s->freq;
+   }
+   else
+      freq = digmid_freq(inst, s, e, note, bend);
 
    /* store note information for later use */
    info = &digmid_voice[voice - midi_digmid.basevoice];



Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/