commit bb403e304ada52eee1921f577ba99dfb444d4e39
Author: Jonathan Dowland <jon+github@alcopop.org>
AuthorDate: Fri Jun 26 07:56:53 2015 +0100
Commit: Jonathan Dowland <jon+github@alcopop.org>
CommitDate: Wed Jul 8 21:01:55 2015 +0100
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.
---
src/i_sdlsound.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 69 insertions(+), 1 deletion(-)
diff --git a/src/i_sdlsound.c b/src/i_sdlsound.c
index 00fde696..a1d4b87a 100644
--- a/src/i_sdlsound.c
+++ b/src/i_sdlsound.c
@@ -291,6 +291,49 @@ static allocated_sound_t * GetAllocatedSoundBySfxInfoAndPitch(sfxinfo_t *sfxinfo
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 @@ static int I_SDL_StartSound(sfxinfo_t *sfxinfo, int channel, int vol, int sep, i
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