engine: soundlib: implemented Ogg Vorbis sounds streaming
This commit is contained in:
parent
86154f81aa
commit
99acd64203
4 changed files with 157 additions and 1 deletions
|
@ -479,6 +479,7 @@ typedef enum
|
|||
WF_UNKNOWN = 0,
|
||||
WF_PCMDATA,
|
||||
WF_MPGDATA,
|
||||
WF_VORBISDATA,
|
||||
WF_TOTALCOUNT, // must be last
|
||||
} sndformat_t;
|
||||
|
||||
|
|
|
@ -31,6 +31,12 @@ typedef struct ogg_filestream_s
|
|||
size_t position;
|
||||
} ogg_filestream_t;
|
||||
|
||||
typedef struct vorbis_streaming_ctx_s
|
||||
{
|
||||
file_t *file;
|
||||
OggVorbis_File vf;
|
||||
} vorbis_streaming_ctx_t;
|
||||
|
||||
static void OggFilestream_Init( ogg_filestream_t *filestream, const char *name, const byte *buffer, size_t filesize )
|
||||
{
|
||||
filestream->name = name;
|
||||
|
@ -91,6 +97,24 @@ static opus_int64 OpusCallback_Tell( void *datasource )
|
|||
return OggFilestream_Tell( datasource );
|
||||
}
|
||||
|
||||
static size_t FS_ReadOggVorbis( void *ptr, size_t blockSize, size_t nmemb, void *datasource )
|
||||
{
|
||||
vorbis_streaming_ctx_t *ctx = (vorbis_streaming_ctx_t*)datasource;
|
||||
return g_fsapi.Read( ctx->file, ptr, blockSize * nmemb );
|
||||
}
|
||||
|
||||
static int FS_SeekOggVorbis( void *datasource, int64_t offset, int whence )
|
||||
{
|
||||
vorbis_streaming_ctx_t *ctx = (vorbis_streaming_ctx_t*)datasource;
|
||||
return g_fsapi.Seek( ctx->file, offset, whence );
|
||||
}
|
||||
|
||||
static long FS_TellOggVorbis( void *datasource )
|
||||
{
|
||||
vorbis_streaming_ctx_t *ctx = (vorbis_streaming_ctx_t*)datasource;
|
||||
return g_fsapi.Tell( ctx->file );
|
||||
}
|
||||
|
||||
static const ov_callbacks ov_callbacks_membuf = {
|
||||
OggFilestream_Read,
|
||||
OggFilestream_Seek,
|
||||
|
@ -98,6 +122,13 @@ static const ov_callbacks ov_callbacks_membuf = {
|
|||
OggFilestream_Tell
|
||||
};
|
||||
|
||||
static const ov_callbacks ov_callbacks_fs = {
|
||||
FS_ReadOggVorbis,
|
||||
FS_SeekOggVorbis,
|
||||
NULL,
|
||||
FS_TellOggVorbis
|
||||
};
|
||||
|
||||
static const OpusFileCallbacks op_callbacks_membuf = {
|
||||
OpusCallback_Read,
|
||||
OggFilestream_Seek,
|
||||
|
@ -108,7 +139,7 @@ static const OpusFileCallbacks op_callbacks_membuf = {
|
|||
/*
|
||||
=================================================================
|
||||
|
||||
Ogg Vorbis decompression
|
||||
Ogg Vorbis decompression & streaming
|
||||
|
||||
=================================================================
|
||||
*/
|
||||
|
@ -156,6 +187,124 @@ qboolean Sound_LoadOggVorbis( const char *name, const byte *buffer, fs_offset_t
|
|||
return true;
|
||||
}
|
||||
|
||||
stream_t *Stream_OpenOggVorbis( const char *filename )
|
||||
{
|
||||
stream_t *stream;
|
||||
vorbis_streaming_ctx_t *ctx;
|
||||
|
||||
ctx = (vorbis_streaming_ctx_t*)Mem_Calloc( host.soundpool, sizeof( vorbis_streaming_ctx_t ));
|
||||
ctx->file = FS_Open( filename, "rb", false );
|
||||
if (!ctx->file) {
|
||||
Mem_Free( ctx );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
stream = (stream_t*)Mem_Calloc( host.soundpool, sizeof( stream_t ));
|
||||
stream->file = ctx->file;
|
||||
stream->pos = 0;
|
||||
|
||||
if( ov_open_callbacks( ctx, &ctx->vf, NULL, 0, ov_callbacks_fs ) < 0 )
|
||||
{
|
||||
Con_DPrintf( S_ERROR "%s: failed to load (%s): file openning error\n", __func__, filename );
|
||||
FS_Close( ctx->file );
|
||||
Mem_Free( stream );
|
||||
Mem_Free( ctx );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vorbis_info *info = ov_info( &ctx->vf, -1 );
|
||||
if( info->channels < 1 || info->channels > 2 ) {
|
||||
Con_DPrintf( S_ERROR "%s: failed to load (%s): unsuppored channels count\n", __func__, filename );
|
||||
FS_Close( ctx->file );
|
||||
Mem_Free( stream );
|
||||
Mem_Free( ctx );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
stream->buffsize = 0; // how many samples left from previous frame
|
||||
stream->channels = info->channels;
|
||||
stream->rate = info->rate;
|
||||
stream->width = 2; // always 16 bit
|
||||
stream->ptr = ctx;
|
||||
stream->type = WF_VORBISDATA;
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
int Stream_ReadOggVorbis( stream_t *stream, int needBytes, void *buffer )
|
||||
{
|
||||
int section;
|
||||
int bytesWritten = 0;
|
||||
vorbis_streaming_ctx_t *ctx = (vorbis_streaming_ctx_t*)stream->ptr;
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
byte *data;
|
||||
int outsize;
|
||||
|
||||
if( !stream->buffsize )
|
||||
{
|
||||
if(( stream->pos = ov_read( &ctx->vf, (char*)stream->temp, OUTBUF_SIZE, 0, stream->width, 1, §ion )) <= 0 )
|
||||
break; // there was EoF or error
|
||||
}
|
||||
|
||||
// check remaining size
|
||||
if( bytesWritten + stream->pos > needBytes )
|
||||
outsize = ( needBytes - bytesWritten );
|
||||
else outsize = stream->pos;
|
||||
|
||||
// copy raw sample to output buffer
|
||||
data = (byte *)buffer + bytesWritten;
|
||||
memcpy( data, &stream->temp[stream->buffsize], outsize );
|
||||
bytesWritten += outsize;
|
||||
stream->pos -= outsize;
|
||||
stream->buffsize += outsize;
|
||||
|
||||
// continue from this sample on a next call
|
||||
if( bytesWritten >= needBytes )
|
||||
return bytesWritten;
|
||||
|
||||
stream->buffsize = 0; // no bytes remaining
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Stream_SetPosOggVorbis( stream_t *stream, int newpos )
|
||||
{
|
||||
vorbis_streaming_ctx_t *ctx = (vorbis_streaming_ctx_t*)stream->ptr;
|
||||
if( ov_raw_seek_lap( &ctx->vf, newpos ) == 0 ) {
|
||||
stream->buffsize = 0; // flush any previous data
|
||||
return true;
|
||||
}
|
||||
return false; // failed to seek
|
||||
}
|
||||
|
||||
int Stream_GetPosOggVorbis( stream_t *stream )
|
||||
{
|
||||
vorbis_streaming_ctx_t *ctx = (vorbis_streaming_ctx_t*)stream->ptr;
|
||||
return ov_raw_tell( &ctx->vf );
|
||||
}
|
||||
|
||||
void Stream_FreeOggVorbis( stream_t *stream )
|
||||
{
|
||||
if( stream->ptr )
|
||||
{
|
||||
vorbis_streaming_ctx_t *ctx = (vorbis_streaming_ctx_t*)stream->ptr;
|
||||
ov_clear( &ctx->vf );
|
||||
Mem_Free( stream->ptr );
|
||||
stream->ptr = NULL;
|
||||
}
|
||||
|
||||
if( stream->file )
|
||||
{
|
||||
FS_Close( stream->file );
|
||||
stream->file = NULL;
|
||||
}
|
||||
|
||||
Mem_Free( stream );
|
||||
}
|
||||
|
||||
/*
|
||||
=================================================================
|
||||
|
||||
|
|
|
@ -61,6 +61,7 @@ static const streamfmt_t stream_game[] =
|
|||
{
|
||||
{ "%s%s.%s", "mp3", Stream_OpenMPG, Stream_ReadMPG, Stream_SetPosMPG, Stream_GetPosMPG, Stream_FreeMPG },
|
||||
{ "%s%s.%s", "wav", Stream_OpenWAV, Stream_ReadWAV, Stream_SetPosWAV, Stream_GetPosWAV, Stream_FreeWAV },
|
||||
{ "%s%s.%s", "ogg", Stream_OpenOggVorbis, Stream_ReadOggVorbis, Stream_SetPosOggVorbis, Stream_GetPosOggVorbis, Stream_FreeOggVorbis },
|
||||
{ NULL, NULL, NULL, NULL, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
|
|
|
@ -135,5 +135,10 @@ int Stream_ReadMPG( stream_t *stream, int bytes, void *buffer );
|
|||
int Stream_SetPosMPG( stream_t *stream, int newpos );
|
||||
int Stream_GetPosMPG( stream_t *stream );
|
||||
void Stream_FreeMPG( stream_t *stream );
|
||||
stream_t *Stream_OpenOggVorbis( const char *filename );
|
||||
int Stream_ReadOggVorbis( stream_t *stream, int bytes, void *buffer );
|
||||
int Stream_SetPosOggVorbis( stream_t *stream, int newpos );
|
||||
int Stream_GetPosOggVorbis( stream_t *stream );
|
||||
void Stream_FreeOggVorbis( stream_t *stream );
|
||||
|
||||
#endif//SOUNDLIB_H
|
||||
|
|
Loading…
Add table
Reference in a new issue