[ 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];