mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-02-16 10:52:32 +01:00
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:
parent
7099c3df40
commit
de2e30bea3
@ -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)
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
22
src/coding/ogg_vorbis_decoder.c
Normal file
22
src/coding/ogg_vorbis_decoder.c
Normal 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
|
@ -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
|
||||
|
@ -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
167
src/meta/ogg_vorbis_file.c
Normal 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
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user