login

<     >

2021-01-19 01:07:16 (UTC-03:00)

Marcel Rodrigues <marcelgmr@gmail.com>

use S7.8 semitones for pitch wheel

diff --git a/qms.c b/qms.c
index 8d6fb77..9c103ff 100644
--- a/qms.c
+++ b/qms.c
@@ -11,7 +11,7 @@ typedef struct VoiceState {
     unsigned int phase_step;  /* fixed point with NEXP.16 precision */
     int velocity;    /* 0x00-0x7F */
     int pitch;       /* 0x00-0x7F */
-    int wheel;       /* (-0x2000)-(+0x1FFF)  default (zero) means center */
+    int wheel;       /* S7.8    default (zero) means center */
     /* int note_age; */
 } VoiceState;
 
@@ -88,13 +88,25 @@ static unsigned int
 midipitch2step(int m, int w)
 {
     unsigned int o, n; /* m = o * 12 + n */
+    int neg_wheel;
     uint32_t nwc;
     uint32_t c = 0x0EC98200; /* ln(2^(1/12)) in U0.32 */
+    neg_wheel = w & 0x8000;
+    if (neg_wheel) {
+        w = 0x10000 - w;
+        m -= w >> 8;
+    } else {
+        m += w >> 8;
+    }
+    w &= 0xFF;
     for (n = m+3, o = 0; n >= 12; n -= 12, o++) ;
     /* the following takes advantage of assumed constants:
      *   R = 44100 = 440 * 2205 / 22
      *   N = 2048 = 2^11 */
-    nwc = ((n<<8)+((w>>4)-0x200))*(c>>8);
+    if (neg_wheel)
+        nwc = ((n<<8)-w)*(c>>8);
+    else
+        nwc = ((n<<8)+w)*(c>>8);
     return ((fxp_expm1(nwc)>>5) * 22 / (2205<<6) + (22<<21) / 2205) << o;
 }
 
@@ -107,17 +119,17 @@ qms_setvelocity(int track, int voice, int velocity)
 void
 qms_setnote(int track, int voice, int midipitch)
 {
-    int midiwheel = voices[track][voice].wheel + 0x2000;
-    voices[track][voice].phase_step = midipitch2step(midipitch, midiwheel);
+    int wheel = voices[track][voice].wheel;
+    voices[track][voice].phase_step = midipitch2step(midipitch, wheel);
     voices[track][voice].pitch = midipitch;
 }
 
 void
-qms_setwheel(int track, int voice, int midiwheel)
+qms_setwheel(int track, int voice, int wheel)
 {
     int midipitch = voices[track][voice].pitch;
-    voices[track][voice].phase_step = midipitch2step(midipitch, midiwheel);
-    voices[track][voice].wheel = midiwheel - 0x2000;
+    voices[track][voice].phase_step = midipitch2step(midipitch, wheel);
+    voices[track][voice].wheel = wheel;
 }
 
 void

diff --git a/qms.h b/qms.h
index 940e5b7..5d7b20e 100644
--- a/qms.h
+++ b/qms.h
@@ -35,7 +35,7 @@ void qms_setvol(int track, int midivol);
 void qms_setpan(int track, int midipan);
 void qms_setvelocity(int track, int voice, int velocity);
 void qms_setnote(int track, int voice, int midipitch);
-void qms_setwheel(int track, int voice, int midiwheel);
+void qms_setwheel(int track, int voice, int wheel);
 void qms_advance(unsigned int nsamples);
 void qms_runevents(Event *evs, unsigned int nevs);
 void qms_putsample(int16_t left, int16_t right);

diff --git a/smf.c b/smf.c
index 955c00e..5fc4e48 100644
--- a/smf.c
+++ b/smf.c
@@ -91,6 +91,7 @@ qms_smf2evs(const char *fname, Event *evs, int maxnevs, int *pnevs)
     uint8_t byte, status, chan, arg, vel;
     uint16_t param, wheel;
     uint8_t semirange, centrange;
+    int negative_wheel;
     int smf_track;
     int ntcs, nevs;
     ntcs = nevs = 0;
@@ -175,7 +176,7 @@ qms_smf2evs(const char *fname, Event *evs, int maxnevs, int *pnevs)
                         break;
                     case 0x26:  /* data entry LSB */
                         if (param == 0x0000)    /* pitch bend range */
-                            centrange = read_u8(fd);
+                            centrange = read_u8(fd); /* ignored for now */
                         else (void) read_u8(fd);
                         break;
                     case 0x64:  /* RPN LSB */
@@ -192,8 +193,17 @@ qms_smf2evs(const char *fname, Event *evs, int maxnevs, int *pnevs)
                     add_ev(qms_ev_pac(chan, arg % NPACS));
                     break;
                 case 0xE:   /* pitch wheel change */
+                    /* TODO: dont' ignore centrange */
+                    /* range is {semirange} semitones + {centrange} cents */
                     wheel = arg | (read_u8(fd) << 7);
-                    wheel = ((((int16_t) wheel >> 1) - 0x1000) * semirange) + 0x2000;
+                    negative_wheel = wheel < 0x2000;
+                    if (negative_wheel)
+                        wheel = 0x2000 - wheel;
+                    else
+                        wheel = wheel - 0x2000;
+                    wheel = (wheel >> 5) * semirange;
+                    if (negative_wheel)
+                        wheel = ~wheel + 1;
                     add_ev(qms_ev_wheel(chan, 0, wheel));
                 }
             }