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; }
/* ==================== 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); }