shithub: choc

Download patch

ref: bb403e304ada52eee1921f577ba99dfb444d4e39
parent: 8c7e10c96855a31fe94a77c23e6977aea0b4b279
author: Jonathan Dowland <jon+github@alcopop.org>
date: Fri Jun 26 03:56:53 EDT 2015

Implement approximation of Doom's pitching

Calculate a destination sound buffer size by working out the ratio
of pitch:NORM_PITCH, inverting and applying that to the source buf
size. This approximates Doom/DMX based on measurements.

Really simple algorithm that maps dest-cell to source-cell by the
ratio of offset from the start of each chunk, with no interpolation.
I've got better results with interpolation but that needs a low-pass
filter applied afterwards and I haven't finished that part yet.

--- a/src/i_sdlsound.c
+++ b/src/i_sdlsound.c
@@ -291,6 +291,49 @@
     return NULL;
 }
 
+// Allocate a new sound chunk and pitch-shift an existing sound up-or-down
+// into it.
+
+static allocated_sound_t * PitchShift(allocated_sound_t *insnd, int pitch)
+{
+    allocated_sound_t * outsnd;
+    Sint16 *inp, *outp;
+    Sint16 *srcbuf, *dstbuf;
+    Uint32 srclen, dstlen;
+
+    srcbuf = (Sint16 *)insnd->chunk.abuf;
+    srclen = insnd->chunk.alen;
+
+    // determine ratio pitch:NORM_PITCH and apply to srclen, then invert.
+    // This is an approximation of vanilla behaviour based on measurements
+    dstlen = (int)((1 + (1 - (float)pitch / NORM_PITCH)) * srclen);
+
+    // ensure that the new buffer is an even length
+    if( (dstlen % 2) == 0)
+    {
+        dstlen++;
+    }
+
+    outsnd = AllocateSound(insnd->sfxinfo, dstlen);
+
+    if(!outsnd)
+    {
+        return NULL;
+    }
+
+    outsnd->pitch = pitch;
+    dstbuf = (Sint16 *)outsnd->chunk.abuf;
+
+    // loop over output buffer. find corresponding input cell, copy over
+    for(outp = dstbuf; outp < dstbuf + dstlen/2; ++outp)
+    {
+        inp = srcbuf + (int)((float)(outp - dstbuf) / dstlen * srclen);
+        *outp = *inp;
+    }
+
+    return outsnd;
+}
+
 // When a sound stops, check if it is still playing.  If it is not,
 // we can mark the sound data as CACHE to be freed back for other
 // means.
@@ -895,7 +938,32 @@
         return -1;
     }
 
-    snd = GetAllocatedSoundBySfxInfoAndPitch(sfxinfo, NORM_PITCH);
+    snd = GetAllocatedSoundBySfxInfoAndPitch(sfxinfo, pitch);
+
+    if(snd == NULL)
+    {
+        allocated_sound_t *newsnd;
+        // fetch the base sound effect, un-pitch-shifted
+        snd = GetAllocatedSoundBySfxInfoAndPitch(sfxinfo, NORM_PITCH);
+
+        if(!snd)
+        {
+            return -1;
+        }
+
+        newsnd = PitchShift(snd, pitch);
+
+        if(newsnd)
+        {
+            LockAllocatedSound(newsnd);
+            UnlockAllocatedSound(snd);
+            snd = newsnd;
+        }
+    }
+    else
+    {
+        LockAllocatedSound(snd);
+    }
 
     // play sound