diff --git a/engine/client/snd_ov.c b/engine/client/snd_ov.c
index e10686b1b..3c71c8ee3 100644
--- a/engine/client/snd_ov.c
+++ b/engine/client/snd_ov.c
@@ -86,11 +86,10 @@ static float QDECL OV_Query(struct sfx_s *sfx, struct sfxcache_s *buf, char *nam
 	if (!dec)
 		return -1;
 
-	if (dec->timetotal < 0)
-	{
-		dec->pcmtotal = p_ov_pcm_total(&dec->vf, -1);
-		dec->timetotal = p_ov_time_total(&dec->vf, -1);
-	}
+//	if (dec->pcmtotal == 0)
+//		dec->pcmtotal = p_ov_pcm_total(&dec->vf, -1);
+//	if (dec->timetotal < 0)
+//		dec->timetotal = p_ov_time_total(&dec->vf, -1);
 
 	if (buf)
 	{
@@ -199,9 +198,9 @@ static sfxcache_t *QDECL OV_DecodeSome(struct sfx_s *sfx, struct sfxcache_s *buf
 			if (dec->failed || start+length <= dec->decodedbytestart + dec->decodedbytecount)
 				break;
 
-			if (dec->decodedbufferbytes < start+length - dec->decodedbytestart + 4096)	//expand if needed. 4096 seems to be the recommended size.
+			if (dec->decodedbufferbytes < start+length - dec->decodedbytestart + 4096 && !dec->nopurge)	//expand if needed. 4096 seems to be the recommended size.
 			{
-		//		Con_Printf("Expand buffer\n");
+//				Con_Printf("Expand buffer for %s\n", sfx->name);
 				dec->decodedbufferbytes = (start+length - dec->decodedbytestart) + max(outspeed, 4096); //over allocate, because we can.
 				dec->decodedbuffer = BZ_Realloc(dec->decodedbuffer, dec->decodedbufferbytes);
 			}
@@ -489,8 +488,21 @@ static qboolean OV_StartDecode(unsigned char *start, unsigned long length, ovdec
 	buffer->start = BZ_Malloc(length);
 	memcpy(buffer->start, start, length);
 
-	buffer->timetotal = -1;
+	buffer->pcmtotal = p_ov_pcm_total(&buffer->vf, -1);
+	buffer->timetotal = buffer->pcmtotal / (float)buffer->srcspeed;
 
+	if (buffer->timetotal < 5)	//short sounds might as well remain cached.
+		buffer->nopurge = true;
+
+	if (buffer->nopurge)
+	{	//waste more memory upfront to avoid reallocs later.
+		buffer->decodedbufferbytes = buffer->pcmtotal;
+		buffer->decodedbufferbytes += 4096;	 //ogg vorbis apparently lies/fails sometimes.
+		buffer->decodedbufferbytes *= (double)snd_speed / buffer->srcspeed;	//from src rate to dst rate
+		buffer->decodedbufferbytes *= 2*buffer->srcchannels; //convert from frames to bytes.
+		buffer->decodedbufferbytes += 4096;	 //just general paranoia.
+		buffer->decodedbuffer = BZ_Realloc(buffer->decodedbuffer, buffer->decodedbufferbytes);
+	}
 	return true;
 }
 
@@ -533,9 +545,6 @@ qboolean QDECL S_LoadOVSound (sfx_t *s, qbyte *data, size_t datalen, int sndspee
 
 	s->decoder.decodedata(s, NULL, 0, 100);
 
-	if (p_ov_time_total(&buffer->vf, -1) < 5)	//short sounds might as well remain cached.
-		buffer->nopurge = true;
-
 	return true;
 }