Beispiel #1
0
qboolean decoder_ogg_reset( snd_stream_t *stream )
{
	snd_ogg_stream_t *ogg_stream;

	if( stream->isUrl )
		return qfalse;

	ogg_stream = (snd_ogg_stream_t *)stream->ptr;
	return qov_pcm_seek( &ogg_stream->vorbisfile, 0 ) == 0;
}
Beispiel #2
0
/*
====================
OGG_GetSamplesFloat
====================
*/
static void OGG_GetSamplesFloat (channel_t *ch, sfx_t *sfx, int firstsampleframe, int numsampleframes, float *outsamplesfloat)
{
	ogg_stream_perchannel_t *per_ch = (ogg_stream_perchannel_t *)ch->fetcher_data;
	ogg_stream_persfx_t *per_sfx = (ogg_stream_persfx_t *)sfx->fetcher_data;
	int f = sfx->format.width * sfx->format.channels; // bytes per frame in the buffer
	short *buf;
	int i, len;
	int newlength, done, ret;

	// if this channel does not yet have a channel fetcher, make one
	if (per_ch == NULL)
	{
		// allocate a struct to keep track of our file position and buffer
		per_ch = (ogg_stream_perchannel_t *)Mem_Alloc(snd_mempool, sizeof(*per_ch));
		// begin decoding the file
		per_ch->ov_decode.buffer = per_sfx->file;
		per_ch->ov_decode.ind = 0;
		per_ch->ov_decode.buffsize = per_sfx->filesize;
		if (qov_open_callbacks(&per_ch->ov_decode, &per_ch->vf, NULL, 0, callbacks) < 0)
		{
			// this never happens - this function succeeded earlier on the same data
			Mem_Free(per_ch);
			return;
		}
		per_ch->bs = 0;
		per_ch->buffer_firstframe = 0;
		per_ch->buffer_numframes = 0;
		// attach the struct to our channel
		ch->fetcher_data = (void *)per_ch;
	}

	// if the request is too large for our buffer, loop...
	while (numsampleframes * f > (int)sizeof(per_ch->buffer))
	{
		done = sizeof(per_ch->buffer) / f;
		OGG_GetSamplesFloat(ch, sfx, firstsampleframe, done, outsamplesfloat);
		firstsampleframe += done;
		numsampleframes -= done;
		outsamplesfloat += done * sfx->format.channels;
	}

	// seek if the request is before the current buffer (loop back)
	// seek if the request starts beyond the current buffer by at least one frame (channel was zero volume for a while)
	// do not seek if the request overlaps the buffer end at all (expected behavior)
	if (per_ch->buffer_firstframe > firstsampleframe || per_ch->buffer_firstframe + per_ch->buffer_numframes < firstsampleframe)
	{
		// we expect to decode forward from here so this will be our new buffer start
		per_ch->buffer_firstframe = firstsampleframe;
		per_ch->buffer_numframes = 0;
		ret = qov_pcm_seek(&per_ch->vf, (ogg_int64_t)firstsampleframe);
		if (ret != 0)
		{
			// LordHavoc: we can't Con_Printf here, not thread safe...
			//Con_Printf("OGG_FetchSound: qov_pcm_seek(..., %d) returned %d\n", firstsampleframe, ret);
			return;
		}
	}

	// decompress the file as needed
	if (firstsampleframe + numsampleframes > per_ch->buffer_firstframe + per_ch->buffer_numframes)
	{
		// first slide the buffer back, discarding any data preceding the range we care about
		int offset = firstsampleframe - per_ch->buffer_firstframe;
		int keeplength = per_ch->buffer_numframes - offset;
		if (keeplength > 0)
			memmove(per_ch->buffer, per_ch->buffer + offset * sfx->format.width * sfx->format.channels, keeplength * sfx->format.width * sfx->format.channels);
		per_ch->buffer_firstframe = firstsampleframe;
		per_ch->buffer_numframes -= offset;
		// decompress as much as we can fit in the buffer
		newlength = sizeof(per_ch->buffer) - per_ch->buffer_numframes * f;
		done = 0;
		while (newlength > done && (ret = qov_read(&per_ch->vf, (char *)per_ch->buffer + per_ch->buffer_numframes * f + done, (int)(newlength - done), mem_bigendian, 2, 1, &per_ch->bs)) > 0)
			done += ret;
		// clear the missing space if any
		if (done < newlength)
			memset(per_ch->buffer + done, 0, newlength - done);
		// we now have more data in the buffer
		per_ch->buffer_numframes += done / f;
	}

	// convert the sample format for the caller
	buf = (short *)((char *)per_ch->buffer + (firstsampleframe - per_ch->buffer_firstframe) * f);
	len = numsampleframes * sfx->format.channels;
	for (i = 0;i < len;i++)
		outsamplesfloat[i] = buf[i] * (1.0f / 32768.0f);
}