first commit of ogg vorbis support (via libvorbisfile)

git-svn-id: https://vgmstream.svn.sourceforge.net/svnroot/vgmstream@227 51a99a44-fe44-0410-b1ba-c3e57ba2b86b
This commit is contained in:
halleyscometsw 2008-06-15 04:01:03 +00:00
parent 7099c3df40
commit de2e30bea3
11 changed files with 293 additions and 8 deletions

View File

@ -19,6 +19,10 @@ PKG_CHECK_MODULES(AUDACIOUS, [audacious >= 1.4.0],,
[AC_MSG_ERROR([Cannot find Audacious, have you installed audacious yet?])]
)
PKG_CHECK_MODULES(VORBISFILE, [vorbisfile],,
[AC_MSG_ERROR([Cannot find libvorbisfile])]
)
dnl Check for GTK/GLib/GThread/Pango
PKG_CHECK_MODULES(GTK, [glib-2.0 >= 2.6.0 gtk+-2.0 >= 2.6.0 gthread-2.0 pango],
@ -26,7 +30,7 @@ PKG_CHECK_MODULES(GTK, [glib-2.0 >= 2.6.0 gtk+-2.0 >= 2.6.0 gthread-2.0 pango],
)
CFLAGS="$CFLAGS $AUDACIOUS_CFLAGS"
LIBS="$LIBS $AUDACIOUS_LIBS $GTK_LIBS"
LIBS="$LIBS $AUDACIOUS_LIBS $GTK_LIBS $VORBISFILE_LIBS"
plugindir=`pkg-config audacious --variable=plugin_dir`
AC_SUBST(plugindir)

View File

@ -7,7 +7,8 @@ CODING_OBJS=coding/adx_decoder.o \
coding/pcm_decoder.o \
coding/psx_decoder.o \
coding/xa_decoder.o \
coding/eaxa_decoder.o
coding/eaxa_decoder.o \
coding/ogg_vorbis_decoder.o
LAYOUT_OBJS=layout/ast_blocked.o \
layout/blocked.o \
@ -52,7 +53,8 @@ META_OBJS=meta/adx_header.o \
meta/ea_header.o \
meta/ngc_caf.o \
meta/ps2_vpk.o \
meta/genh.o
meta/genh.o \
meta/ogg_vorbis_file.o
OBJECTS=vgmstream.o streamfile.o util.o $(CODING_OBJS) $(LAYOUT_OBJS) $(META_OBJS)

View File

@ -4,6 +4,6 @@ AM_CFLAGS = -Wall @CFLAGS@ -I$(top_builddir) -I$(top_srcdir)
AM_MAKEFLAGS=-f Makefile.unix
libcoding_la_LDFLAGS =
libcoding_la_SOURCES = adx_decoder.c eaxa_decoder.c g721_decoder.c ima_decoder.c ngc_afc_decoder.c ngc_dsp_decoder.c ngc_dtk_decoder.c pcm_decoder.c psx_decoder.c xa_decoder.c
libcoding_la_SOURCES = adx_decoder.c eaxa_decoder.c g721_decoder.c ima_decoder.c ngc_afc_decoder.c ngc_dsp_decoder.c ngc_dtk_decoder.c pcm_decoder.c psx_decoder.c xa_decoder.c ogg_vorbis_decoder.c
EXTRA_DIST = coding.h g72x_state.h

View File

@ -29,4 +29,8 @@ void decode_xa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, i
void decode_eaxa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel);
#ifdef VGM_USE_VORBIS
void decode_ogg_vorbis(ogg_vorbis_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels);
#endif
#endif

View File

@ -0,0 +1,22 @@
#include "../vgmstream.h"
#ifdef VGM_USE_VORBIS
#include <vorbis/vorbisfile.h>
#include "coding.h"
#include "../util.h"
void decode_ogg_vorbis(ogg_vorbis_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels) {
int samples_done = 0;
OggVorbis_File *ogg_vorbis_file = &data->ogg_vorbis_file;
do {
long rc = ov_read(ogg_vorbis_file, (char *)(outbuf + samples_done*channels),
(samples_to_do - samples_done)*sizeof(sample)*channels, 0,
sizeof(sample), 1, &data->bitstream);
if (rc > 0) samples_done += rc/sizeof(sample)/channels;
else return;
} while (samples_done < samples_to_do);
}
#endif

View File

@ -4,6 +4,6 @@ AM_CFLAGS = -Wall @CFLAGS@ -I$(top_builddir) -I$(top_srcdir)
AM_MAKEFLAGS=-f Makefile.unix
libmeta_la_LDFLAGS =
libmeta_la_SOURCES = Cstr.c adx_header.c afc_header.c agsc.c ast.c brstm.c ea_header.c gcsw.c halpst.c nds_strm.c ngc_adpdtk.c ngc_caf.c ngc_dsp_std.c ps2_ads.c ps2_exst.c ps2_ild.c ps2_int.c ps2_mib.c ps2_mic.c ps2_npsf.c ps2_pnb.c ps2_rxw.c ps2_str.c ps2_svag.c ps2_vag.c ps2_vpk.c psx_cdxa.c raw.c rs03.c rsf.c rwsd.c psx_gms.c xbox_xwav.c xbox_wavm.c genh.c
libmeta_la_SOURCES = Cstr.c adx_header.c afc_header.c agsc.c ast.c brstm.c ea_header.c gcsw.c halpst.c nds_strm.c ngc_adpdtk.c ngc_caf.c ngc_dsp_std.c ps2_ads.c ps2_exst.c ps2_ild.c ps2_int.c ps2_mib.c ps2_mic.c ps2_npsf.c ps2_pnb.c ps2_rxw.c ps2_str.c ps2_svag.c ps2_vag.c ps2_vpk.c psx_cdxa.c raw.c rs03.c rsf.c rwsd.c psx_gms.c xbox_xwav.c xbox_wavm.c genh.c ogg_vorbis_file.c
EXTRA_DIST = meta.h

View File

@ -81,4 +81,6 @@ VGMSTREAM * init_vgmstream_ps2_vpk(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile);
#endif

167
src/meta/ogg_vorbis_file.c Normal file
View File

@ -0,0 +1,167 @@
#include "../vgmstream.h"
#ifdef VGM_USE_VORBIS
#include "meta.h"
#include "../util.h"
#include <vorbis/vorbisfile.h>
#define DEFAULT_BITSTREAM 0
static size_t read_func(void *ptr, size_t size, size_t nmemb, void * datasource)
{
ogg_vorbis_streamfile * const ov_streamfile = datasource;
size_t items_read;
size_t bytes_read;
bytes_read = read_streamfile(ptr, ov_streamfile->offset, size * nmemb,
ov_streamfile->streamfile);
items_read = bytes_read / size;
ov_streamfile->offset += items_read * size;
return items_read;
}
static int seek_func(void *datasource, ogg_int64_t offset, int whence) {
ogg_vorbis_streamfile * const ov_streamfile = datasource;
ogg_int64_t base_offset;
ogg_int64_t new_offset;
switch (whence) {
case SEEK_SET:
base_offset = 0;
break;
case SEEK_CUR:
base_offset = ov_streamfile->offset;
break;
case SEEK_END:
base_offset = ov_streamfile->size;
break;
default:
return -1;
break;
}
new_offset = base_offset + offset;
if (new_offset < 0 || new_offset > ov_streamfile->size) {
return -1;
} else {
ov_streamfile->offset = new_offset;
return 0;
}
}
static long tell_func(void * datasource) {
ogg_vorbis_streamfile * const ov_streamfile = datasource;
return ov_streamfile->offset;
}
/* setting close_func in ov_callbacks to NULL doesn't seem to work */
int close_func(void * datasource) {
return 0;
}
/* Ogg Vorbis, by way of libvorbisfile */
VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[260];
ov_callbacks callbacks;
OggVorbis_File temp_ovf;
ogg_vorbis_streamfile temp_streamfile;
ogg_vorbis_codec_data * data = NULL;
OggVorbis_File *ovf;
int inited_ovf = 0;
vorbis_info *info;
int loop_flag = 0;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
/* It is only interesting to use oggs with vgmstream if they are looped.
To prevent such files from being played by other plugins and such they
may be renamed to .logg. This meta reader should still support .ogg,
though. */
if (strcasecmp("logg",filename_extension(filename)) &&
strcasecmp("ogg",filename_extension(filename))
) goto fail;
callbacks.read_func = read_func;
callbacks.seek_func = seek_func;
callbacks.close_func = close_func;
callbacks.tell_func = tell_func;
temp_streamfile.streamfile = streamFile;
temp_streamfile.offset = 0;
temp_streamfile.size = get_streamfile_size(temp_streamfile.streamfile);
/* can we open this as a proper ogg vorbis file? */
memset(&temp_ovf, 0, sizeof(temp_ovf));
if (ov_test_callbacks(&temp_streamfile, &temp_ovf, NULL,
0, callbacks)) goto fail;
/* we have to close this as it has the init_vgmstream meta-reading
STREAMFILE */
ov_clear(&temp_ovf);
/* proceed to open a STREAMFILE just for this stream */
data = calloc(1,sizeof(ogg_vorbis_codec_data));
if (!data) goto fail;
data->ov_streamfile.streamfile = streamFile->open(streamFile,filename,
STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!data->ov_streamfile.streamfile) goto fail;
data->ov_streamfile.offset = 0;
data->ov_streamfile.size = get_streamfile_size(data->ov_streamfile.streamfile);
/* open the ogg vorbis file for real */
if (ov_open_callbacks(&data->ov_streamfile, &data->ogg_vorbis_file, NULL,
0, callbacks)) goto fail;
ovf = &data->ogg_vorbis_file;
inited_ovf = 1;
/* don't know how to deal with multiple logical streams yet */
if (ov_streams(ovf) != 1) goto fail;
data->bitstream = DEFAULT_BITSTREAM;
info = ov_info(ovf,DEFAULT_BITSTREAM);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(info->channels,loop_flag);
if (!vgmstream) goto fail;
vgmstream->codec_data = data;
/* fill in the vital statistics */
vgmstream->channels = info->channels;
vgmstream->sample_rate = info->rate;
vgmstream->num_samples = ov_pcm_total(ovf,DEFAULT_BITSTREAM);
vgmstream->coding_type = coding_ogg_vorbis;
vgmstream->layout_type = layout_ogg_vorbis;
vgmstream->meta_type = meta_ogg_vorbis;
return vgmstream;
/* clean up anything we may have opened */
fail:
if (data) {
if (inited_ovf)
ov_clear(&data->ogg_vorbis_file);
if (data->ov_streamfile.streamfile)
close_streamfile(data->ov_streamfile.streamfile);
free(data);
}
if (vgmstream) {
vgmstream->codec_data = NULL;
close_vgmstream(vgmstream);
}
return NULL;
}
#endif

View File

@ -55,6 +55,7 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = {
init_vgmstream_caf,
init_vgmstream_ps2_vpk,
init_vgmstream_genh,
init_vgmstream_ogg_vorbis,
};
#define INIT_VGMSTREAM_FCNS (sizeof(init_vgmstream_fcns)/sizeof(init_vgmstream_fcns[0]))
@ -125,6 +126,16 @@ void reset_vgmstream(VGMSTREAM * vgmstream) {
* init_vgmstream_* function doing something tricky and precomputing it.
* Otherwise hit_loop will be 0 and it will be copied over anyway when we
* really hit the loop start. */
#ifdef VGM_USE_VORBIS
if (vgmstream->meta_type==meta_ogg_vorbis) {
ogg_vorbis_codec_data *data =
(ogg_vorbis_codec_data *)(vgmstream->codec_data);
OggVorbis_File *ogg_vorbis_file = &(data->ogg_vorbis_file);
ov_pcm_seek(ogg_vorbis_file, 0);
}
#endif
}
/* simply allocate memory for the VGMSTREAM and its channels */
@ -209,6 +220,23 @@ void close_vgmstream(VGMSTREAM * vgmstream) {
/* the start_vgmstream is considered just data */
if (vgmstream->start_vgmstream) free(vgmstream->start_vgmstream);
#ifdef VGM_USE_VORBIS
if (vgmstream->meta_type==meta_ogg_vorbis) {
ogg_vorbis_codec_data *data =
(ogg_vorbis_codec_data *)(vgmstream->codec_data);
if (vgmstream->codec_data) {
OggVorbis_File *ogg_vorbis_file = &(data->ogg_vorbis_file);
ov_clear(ogg_vorbis_file);
close_streamfile(data->ov_streamfile.streamfile);
free(vgmstream->codec_data);
vgmstream->codec_data = NULL;
}
}
#endif
free(vgmstream);
}
@ -224,6 +252,7 @@ void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstre
case layout_interleave_shortblock:
render_vgmstream_interleave(buffer,sample_count,vgmstream);
break;
case layout_ogg_vorbis:
case layout_dtk_interleave:
case layout_none:
render_vgmstream_nolayout(buffer,sample_count,vgmstream);
@ -247,6 +276,7 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
case coding_PCM16LE:
case coding_PCM16BE:
case coding_PCM8:
case coding_ogg_vorbis:
return 1;
case coding_NDS_IMA:
return (vgmstream->interleave_block_size-4)*2;
@ -414,6 +444,13 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
samples_to_do,chan);
}
break;
#ifdef VGM_USE_VORBIS
case coding_ogg_vorbis:
decode_ogg_vorbis(vgmstream->codec_data,
buffer+samples_written*vgmstream->channels,samples_to_do,
vgmstream->channels);
break;
#endif
}
}
@ -479,6 +516,16 @@ int vgmstream_do_loop(VGMSTREAM * vgmstream) {
}
}
#endif
#ifdef VGM_USE_VORBIS
if (vgmstream->meta_type==meta_ogg_vorbis) {
ogg_vorbis_codec_data *data =
(ogg_vorbis_codec_data *)(vgmstream->codec_data);
OggVorbis_File *ogg_vorbis_file = &(data->ogg_vorbis_file);
ov_pcm_seek_lap(ogg_vorbis_file, vgmstream->loop_sample);
}
#endif
/* restore! */
memcpy(vgmstream->ch,vgmstream->loop_ch,sizeof(VGMSTREAMCHANNEL)*vgmstream->channels);
vgmstream->current_sample=vgmstream->loop_sample;

View File

@ -5,8 +5,13 @@
#ifndef _VGMSTREAM_H
#define _VGMSTREAM_H
#define VGM_USE_VORBIS
#include "streamfile.h"
#include "coding/g72x_state.h"
#ifdef VGM_USE_VORBIS
#include <vorbis/vorbisfile.h>
#endif
/* The encoding type specifies the format the sound data itself takes */
typedef enum {
@ -26,6 +31,9 @@ typedef enum {
coding_XA, /* PSX CD-XA */
coding_XBOX, /* XBOX IMA */
coding_EAXA, /* EA/XA ADPCM */
#ifdef VGM_USE_VORBIS
coding_ogg_vorbis, /* vorbis */
#endif
} coding_t;
/* The layout type specifies how the sound data is laid out in the file */
@ -49,6 +57,9 @@ typedef enum {
#endif
/* otherwise odd */
layout_dtk_interleave, /* dtk interleaves channels by nibble */
#ifdef VGM_USE_VORBIS
layout_ogg_vorbis, /* ogg vorbis file */
#endif
} layout_t;
/* The meta type specifies how we know what we know about the file. We may know because of a header we read, some of it may have been guessed from filenames, etc. */
@ -117,6 +128,10 @@ typedef enum {
meta_RAW, /* RAW PCM file */
meta_GENH, /* generic header */
#ifdef VGM_USE_VORBIS
meta_ogg_vorbis, /* ogg vorbis */
#endif
} meta_t;
typedef struct {
@ -198,8 +213,31 @@ typedef struct {
uint8_t ea_platform;
void * start_vgmstream; /* a copy of the VGMSTREAM as it was at the beginning of the stream */
/* Data the codec needs for the whole stream. This is for codecs too
* different from vgmstream's structure to be reasonably shoehorned into
* using the ch structures.
* Note also that support must be added for resetting, looping and
* closing for every codec that uses this, as it will not be handled. */
void * codec_data;
} VGMSTREAM;
#ifdef VGM_USE_VORBIS
typedef struct {
STREAMFILE *streamfile;
ogg_int64_t offset;
ogg_int64_t size;
} ogg_vorbis_streamfile;
typedef struct {
OggVorbis_File ogg_vorbis_file;
int bitstream;
ogg_vorbis_streamfile ov_streamfile;
} ogg_vorbis_codec_data;
#endif
/* do format detection, return pointer to a usable VGMSTREAM, or NULL on failure */
VGMSTREAM * init_vgmstream(const char * const filename);

View File

@ -1,13 +1,12 @@
export SHELL = /bin/sh
export CFLAGS=-Wall -O3
export LDFLAGS=-lm -L../src -lvgmstream
export CFLAGS=-Wall -ggdb
export LDFLAGS=-lm -L../src -lvgmstream -lvorbisfile
export STRIP=strip
.PHONY: libvgmstream.a
test: libvgmstream.a test.o
$(CC) test.o $(LDFLAGS) $(CFLAGS) -o test
$(STRIP) test
test.o: test.c
$(CC) $(CFLAGS) -c "-DVERSION=\"`../version.sh`\"" test.c -o test.o