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)); } }