mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-01-30 04:30:43 +00:00
beginnings of flac support. compiles but untested. if this doesn't crash,
I'll be surprised :)
This commit is contained in:
parent
fa8dfd3767
commit
dff68bfed0
6 changed files with 594 additions and 6 deletions
108
acinclude.m4
108
acinclude.m4
|
@ -802,7 +802,7 @@ size_t iconv();
|
|||
|
||||
dnl From Bruno Haible.
|
||||
dnl
|
||||
AC_DEFUN([AM_LANGINFO_CODESET],
|
||||
AC_DEFUn([am_lanGINFO_CODESET],
|
||||
[
|
||||
AC_CACHE_CHECK([for nl_langinfo and CODESET], am_cv_langinfo_codeset,
|
||||
[AC_TRY_LINK([#include <langinfo.h>],
|
||||
|
@ -1106,6 +1106,112 @@ fi
|
|||
|
||||
])
|
||||
|
||||
# swiped from libFLAC :)
|
||||
# Configure paths for libFLAC
|
||||
# "Inspired" by ogg.m4
|
||||
|
||||
dnl AM_PATH_LIBFLAC([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]])
|
||||
dnl Test for libFLAC, and define LIBFLAC_CFLAGS and LIBFLAC_LIBS
|
||||
dnl
|
||||
AC_DEFUN([AM_PATH_LIBFLAC],
|
||||
[dnl
|
||||
dnl Get the cflags and libraries
|
||||
dnl
|
||||
AC_ARG_WITH(libFLAC,[ --with-libFLAC=PFX Prefix where libFLAC is installed (optional)], libFLAC_prefix="$withval", libFLAC_prefix="")
|
||||
AC_ARG_WITH(libFLAC-libraries,[ --with-libFLAC-libraries=DIR Directory where libFLAC library is installed (optional)], libFLAC_libraries="$withval", libFLAC_libraries="")
|
||||
AC_ARG_WITH(libFLAC-includes,[ --with-libFLAC-includes=DIR Directory where libFLAC header files are installed (optional)], libFLAC_includes="$withval", libFLAC_includes="")
|
||||
AC_ARG_ENABLE(libFLACtest, [ --disable-libFLACtest Do not try to compile and run a test libFLAC program],, enable_libFLACtest=yes)
|
||||
|
||||
if test "x$libFLAC_libraries" != "x" ; then
|
||||
LIBFLAC_LIBS="-L$libFLAC_libraries"
|
||||
elif test "x$libFLAC_prefix" != "x" ; then
|
||||
LIBFLAC_LIBS="-L$libFLAC_prefix/lib"
|
||||
elif test "x$prefix" != "xNONE" ; then
|
||||
LIBFLAC_LIBS="-L$libdir"
|
||||
fi
|
||||
|
||||
LIBFLAC_LIBS="$LIBFLAC_LIBS -lFLAC -lm"
|
||||
|
||||
if test "x$libFLAC_includes" != "x" ; then
|
||||
LIBFLAC_CFLAGS="-I$libFLAC_includes"
|
||||
elif test "x$libFLAC_prefix" != "x" ; then
|
||||
LIBFLAC_CFLAGS="-I$libFLAC_prefix/include"
|
||||
elif test "$prefix" != "xNONE"; then
|
||||
LIBFLAC_CFLAGS="-I$prefix/include"
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING(for libFLAC)
|
||||
no_libFLAC=""
|
||||
|
||||
|
||||
if test "x$enable_libFLACtest" = "xyes" ; then
|
||||
ac_save_CFLAGS="$CFLAGS"
|
||||
ac_save_CXXFLAGS="$CXXFLAGS"
|
||||
ac_save_LIBS="$LIBS"
|
||||
CFLAGS="$CFLAGS $LIBFLAC_CFLAGS"
|
||||
CXXFLAGS="$CXXFLAGS $LIBFLAC_CFLAGS"
|
||||
LIBS="$LIBS $LIBFLAC_LIBS"
|
||||
dnl
|
||||
dnl Now check if the installed libFLAC is sufficiently new.
|
||||
dnl
|
||||
rm -f conf.libFLACtest
|
||||
AC_TRY_RUN([
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <FLAC/format.h>
|
||||
|
||||
int main ()
|
||||
{
|
||||
system("touch conf.libFLACtest");
|
||||
return 0;
|
||||
}
|
||||
|
||||
],, no_libFLAC=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
|
||||
CFLAGS="$ac_save_CFLAGS"
|
||||
LIBS="$ac_save_LIBS"
|
||||
fi
|
||||
|
||||
if test "x$no_libFLAC" = "x" ; then
|
||||
AC_MSG_RESULT(yes)
|
||||
ifelse([$1], , :, [$1])
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
if test -f conf.libFLACtest ; then
|
||||
:
|
||||
else
|
||||
echo "*** Could not run libFLAC test program, checking why..."
|
||||
CFLAGS="$CFLAGS $LIBFLAC_CFLAGS"
|
||||
LIBS="$LIBS $LIBFLAC_LIBS"
|
||||
AC_TRY_LINK([
|
||||
#include <stdio.h>
|
||||
#include <FLAC/format.h>
|
||||
], [ return 0; ],
|
||||
[ echo "*** The test program compiled, but did not run. This usually means"
|
||||
echo "*** that the run-time linker is not finding libFLAC or finding the wrong"
|
||||
echo "*** version of libFLAC. If it is not finding libFLAC, you'll need to set your"
|
||||
echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
|
||||
echo "*** to the installed location Also, make sure you have run ldconfig if that"
|
||||
echo "*** is required on your system"
|
||||
echo "***"
|
||||
echo "*** If you have an old version installed, it is best to remove it, although"
|
||||
echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"],
|
||||
[ echo "*** The test program failed to compile or link. See the file config.log for the"
|
||||
echo "*** exact error that occured. This usually means libFLAC was incorrectly installed"
|
||||
echo "*** or that you have moved libFLAC since it was installed. In the latter case, you"
|
||||
echo "*** may want to edit the libFLAC-config script: $LIBFLAC_CONFIG" ])
|
||||
CFLAGS="$ac_save_CFLAGS"
|
||||
LIBS="$ac_save_LIBS"
|
||||
fi
|
||||
LIBFLAC_CFLAGS=""
|
||||
LIBFLAC_LIBS=""
|
||||
ifelse([$2], , :, [$2])
|
||||
fi
|
||||
AC_SUBST(LIBFLAC_CFLAGS)
|
||||
AC_SUBST(LIBFLAC_LIBS)
|
||||
rm -f conf.libFLACtest
|
||||
])
|
||||
|
||||
AC_DEFUN([QF_DEPS], [
|
||||
$1_INCS='$2'
|
||||
$1_DEPS='$3'
|
||||
|
|
14
configure.ac
14
configure.ac
|
@ -565,6 +565,18 @@ if test "x$enable_vorbis" != "xno"; then
|
|||
fi
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(flac,
|
||||
[ --disable-flac disable flac support],
|
||||
)
|
||||
|
||||
HAVE_FLAC=no
|
||||
if test "x$enable_flac" != "xno"; then
|
||||
AM_PATH_LIBFLAC(HAVE_FLAC=yes, HAVE_FLAC=no)
|
||||
if test "x$HAVE_FLAC" = xyes; then
|
||||
AC_DEFINE(HAVE_FLAC, 1, [define this if you have flac libs])
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(zlib,
|
||||
[ --disable-zlib disable zlib support],
|
||||
)
|
||||
|
@ -2324,7 +2336,7 @@ AC_MSG_RESULT([
|
|||
Sound support :${SOUND_TYPES- no} ${SND_OUTPUT_DEFAULT}
|
||||
CD Audio system :${CDTYPE- no}
|
||||
IPv6 networking : $NETTYPE_IPV6
|
||||
Compression support: gz=$HAVE_ZLIB ogg=$HAVE_VORBIS png=$HAVE_PNG
|
||||
Compression support: gz=$HAVE_ZLIB ogg=$HAVE_VORBIS flac=$HAVE_FLAC png=$HAVE_PNG
|
||||
Compiler version : $CCVER
|
||||
Compiler flags : $CFLAGS
|
||||
qfcc cpp invocation: $CPP_NAME
|
||||
|
|
|
@ -83,7 +83,7 @@ typedef struct sfxblock_s {
|
|||
cache_user_t cache;
|
||||
} sfxblock_t;
|
||||
|
||||
// !!! if this is changed, it much be changed in asm_i386.h too !!!
|
||||
// !!! if this is changed, it must be changed in asm_i386.h too !!!
|
||||
struct channel_s {
|
||||
sfx_t *sfx; // sfx number
|
||||
int leftvol; // 0-255 volume
|
||||
|
@ -113,6 +113,7 @@ void SND_InitScaletable (void);
|
|||
void SND_Load (sfx_t *sfx);
|
||||
void SND_CallbackLoad (void *object, cache_allocator_t allocator);
|
||||
void SND_LoadOgg (QFile *file, sfx_t *sfx, char *realname);
|
||||
void SND_LoadFLAC (QFile *file, sfx_t *sfx, char *realname);
|
||||
void SND_LoadWav (QFile *file, sfx_t *sfx, char *realname);
|
||||
void SND_LoadMidi (QFile *file, sfx_t *sfx, char *realname);
|
||||
|
||||
|
|
|
@ -13,11 +13,11 @@ EXTRA_LTLIBRARIES= snd_render_default.la
|
|||
noinst_LTLIBRARIES= @SND_REND_STATIC@
|
||||
|
||||
snd_render_default_la_LDFLAGS= $(plugin_ldflags)
|
||||
snd_render_default_la_SOURCES= snd_dma.c snd_mem.c snd_mix.c vorbis.c wav.c midi.c
|
||||
snd_render_default_la_SOURCES= snd_dma.c snd_mem.c snd_mix.c flac.c vorbis.c wav.c midi.c
|
||||
if ASM_ARCH
|
||||
snd_render_default_la_LIBADD= $(VORBISFILE_LIBS) $(VORBIS_LIBS) $(OGG_LIBS) $(WM_LIBS)
|
||||
snd_render_default_la_LIBADD= $(VORBISFILE_LIBS) $(VORBIS_LIBS) $(LIBFLAC_LIBS) $(OGG_LIBS) $(WM_LIBS)
|
||||
snd_render_default_la_DEPENDENCIES=
|
||||
else
|
||||
snd_render_default_la_LIBADD= $(VORBISFILE_LIBS) $(VORBIS_LIBS) $(OGG_LIBS) $(WM_LIBS)
|
||||
snd_render_default_la_LIBADD= $(VORBISFILE_LIBS) $(VORBIS_LIBS) $(LIBFLAC_LIBS) $(OGG_LIBS) $(WM_LIBS)
|
||||
snd_render_default_la_DEPENDENCIES=
|
||||
endif
|
||||
|
|
462
libs/audio/renderer/flac.c
Normal file
462
libs/audio/renderer/flac.c
Normal file
|
@ -0,0 +1,462 @@
|
|||
/*
|
||||
flac.c
|
||||
|
||||
Ogg Vorbis support
|
||||
|
||||
Copyright (C) 2001 Bill Currie <bill@taniwha.org>
|
||||
|
||||
Author: Bill Currie <bill@taniwha.org>
|
||||
Date: 2002/6/14
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
|
||||
Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA
|
||||
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
static __attribute__ ((unused)) const char rcsid[] =
|
||||
"$Id$";
|
||||
|
||||
#ifdef HAVE_FLAC
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
# include "string.h"
|
||||
#endif
|
||||
#ifdef HAVE_STRINGS_H
|
||||
# include "strings.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <FLAC/seekable_stream_decoder.h>
|
||||
|
||||
#include "QF/cvar.h"
|
||||
#include "QF/quakefs.h"
|
||||
#include "QF/sound.h"
|
||||
#include "QF/sys.h"
|
||||
|
||||
#include "snd_render.h"
|
||||
|
||||
typedef struct {
|
||||
FLAC__SeekableStreamDecoder *decoder;
|
||||
QFile *file;
|
||||
FLAC__StreamMetadata_StreamInfo info;
|
||||
FLAC__StreamMetadata *vorbis_info;
|
||||
byte *buffer;
|
||||
int size;
|
||||
int pos;
|
||||
} flacfile_t;
|
||||
|
||||
static FLAC__SeekableStreamDecoderReadStatus
|
||||
read_func (const FLAC__SeekableStreamDecoder *decoder, FLAC__byte buffer[],
|
||||
unsigned *bytes, void *client_data)
|
||||
{
|
||||
flacfile_t *ff = (flacfile_t *) client_data;
|
||||
*bytes = Qread (ff->file, buffer, *bytes);
|
||||
return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK;
|
||||
}
|
||||
|
||||
static FLAC__SeekableStreamDecoderSeekStatus
|
||||
seek_func (const FLAC__SeekableStreamDecoder *decoder,
|
||||
FLAC__uint64 absolute_byte_offset, void *client_data)
|
||||
{
|
||||
flacfile_t *ff = (flacfile_t *) client_data;
|
||||
Qseek (ff->file, absolute_byte_offset, SEEK_SET);
|
||||
return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK;
|
||||
}
|
||||
|
||||
static FLAC__SeekableStreamDecoderTellStatus
|
||||
tell_func (const FLAC__SeekableStreamDecoder *decoder,
|
||||
FLAC__uint64 *absolute_byte_offset, void *client_data)
|
||||
{
|
||||
flacfile_t *ff = (flacfile_t *) client_data;
|
||||
*absolute_byte_offset = Qtell (ff->file);
|
||||
return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK;
|
||||
}
|
||||
|
||||
static FLAC__SeekableStreamDecoderLengthStatus
|
||||
length_func (const FLAC__SeekableStreamDecoder *decoder,
|
||||
FLAC__uint64 *stream_length, void *client_data)
|
||||
{
|
||||
flacfile_t *ff = (flacfile_t *) client_data;
|
||||
*stream_length = Qfilesize (ff->file);
|
||||
return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK;
|
||||
}
|
||||
|
||||
static FLAC__bool
|
||||
eof_func (const FLAC__SeekableStreamDecoder *decoder, void *client_data)
|
||||
{
|
||||
flacfile_t *ff = (flacfile_t *) client_data;
|
||||
return Qeof (ff->file);
|
||||
}
|
||||
|
||||
static FLAC__StreamDecoderWriteStatus
|
||||
write_func (const FLAC__SeekableStreamDecoder *decoder,
|
||||
const FLAC__Frame *frame, const FLAC__int32 * const buffer[],
|
||||
void *client_data)
|
||||
{
|
||||
flacfile_t *ff = (flacfile_t *) client_data;
|
||||
int bps = ff->info.bits_per_sample / 8;
|
||||
if (ff->info.channels == 1) {
|
||||
memcpy (ff->buffer, buffer[0], bps * frame->header.blocksize);
|
||||
} else {
|
||||
unsigned i;
|
||||
const FLAC__int32 *li = buffer[0];
|
||||
const FLAC__int32 *ri = buffer[1];
|
||||
|
||||
if (ff->info.bits_per_sample == 8) {
|
||||
char *lo = (char *) ff->buffer + 0;
|
||||
char *ro = (char *) ff->buffer + 1;
|
||||
|
||||
for (i = 0; i < frame->header.blocksize; i++, lo++, ro++) {
|
||||
*lo++ = *li++;
|
||||
*ro++ = *ri++;
|
||||
}
|
||||
} else {
|
||||
short *lo = (short *) ff->buffer + 0;
|
||||
short *ro = (short *) ff->buffer + 1;
|
||||
|
||||
for (i = 0; i < frame->header.blocksize; i++, lo++, ro++) {
|
||||
*lo++ = *li++;
|
||||
*ro++ = *ri++;
|
||||
}
|
||||
}
|
||||
}
|
||||
ff->size = frame->header.blocksize;
|
||||
ff->pos = 0;
|
||||
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_func (const FLAC__SeekableStreamDecoder *decoder,
|
||||
const FLAC__StreamMetadata *metadata, void *client_data)
|
||||
{
|
||||
flacfile_t *ff = (flacfile_t *) client_data;
|
||||
if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO)
|
||||
ff->info = metadata->data.stream_info;
|
||||
}
|
||||
|
||||
static flacfile_t *
|
||||
open_flac (QFile *file)
|
||||
{
|
||||
flacfile_t *ff = calloc (1, sizeof (flacfile_t));
|
||||
ff->decoder = FLAC__seekable_stream_decoder_new ();
|
||||
ff->file = file;
|
||||
|
||||
FLAC__seekable_stream_decoder_set_read_callback (ff->decoder, read_func);
|
||||
FLAC__seekable_stream_decoder_set_seek_callback (ff->decoder, seek_func);
|
||||
FLAC__seekable_stream_decoder_set_tell_callback (ff->decoder, tell_func);
|
||||
FLAC__seekable_stream_decoder_set_length_callback (ff->decoder,
|
||||
length_func);
|
||||
FLAC__seekable_stream_decoder_set_eof_callback (ff->decoder, eof_func);
|
||||
FLAC__seekable_stream_decoder_set_write_callback (ff->decoder, write_func);
|
||||
FLAC__seekable_stream_decoder_set_metadata_callback (ff->decoder,
|
||||
meta_func);
|
||||
FLAC__seekable_stream_decoder_set_client_data (ff->decoder, ff);
|
||||
|
||||
FLAC__seekable_stream_decoder_init (ff->decoder);
|
||||
FLAC__seekable_stream_decoder_process_until_end_of_metadata (ff->decoder);
|
||||
return ff;
|
||||
}
|
||||
|
||||
static void
|
||||
close_flac (flacfile_t *ff)
|
||||
{
|
||||
FLAC__seekable_stream_decoder_finish (ff->decoder);
|
||||
FLAC__seekable_stream_decoder_delete (ff->decoder);
|
||||
|
||||
Qclose (ff->file);
|
||||
|
||||
free (ff);
|
||||
}
|
||||
|
||||
static int
|
||||
flac_read (flacfile_t *ff, byte *buf, int len)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
while (len) {
|
||||
int res = 0;
|
||||
if (ff->size == ff->pos)
|
||||
FLAC__seekable_stream_decoder_process_single (ff->decoder);
|
||||
res = ff->size - ff->pos;
|
||||
if (res > len)
|
||||
res = len;
|
||||
if (res > 0) {
|
||||
count += res;
|
||||
len -= res;
|
||||
buf += res;
|
||||
} else if (res < 0) {
|
||||
Sys_Printf ("flac error %d\n", res);
|
||||
return -1;
|
||||
} else {
|
||||
Sys_Printf ("unexpected eof\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static sfxbuffer_t *
|
||||
flac_load (flacfile_t *ff, sfxblock_t *block, cache_allocator_t allocator)
|
||||
{
|
||||
byte *data;
|
||||
sfxbuffer_t *sc = 0;
|
||||
sfx_t *sfx = block->sfx;
|
||||
void (*resample)(sfxbuffer_t *, byte *, int, void *);
|
||||
wavinfo_t *info = &block->wavinfo;
|
||||
|
||||
switch (ff->info.channels) {
|
||||
case 1:
|
||||
resample = SND_ResampleMono;
|
||||
break;
|
||||
case 2:
|
||||
resample = SND_ResampleStereo;
|
||||
break;
|
||||
default:
|
||||
Sys_Printf ("%s: unsupported channel count: %d\n",
|
||||
sfx->name, info->channels);
|
||||
return 0;
|
||||
}
|
||||
|
||||
data = malloc (info->datalen);
|
||||
if (!data)
|
||||
goto bail;
|
||||
sc = SND_GetCache (info->samples, info->rate, info->width, info->channels,
|
||||
block, allocator);
|
||||
if (!sc)
|
||||
goto bail;
|
||||
sc->sfx = sfx;
|
||||
if (flac_read (ff, data, info->datalen) < 0)
|
||||
goto bail;
|
||||
resample (sc, data, info->samples, 0);
|
||||
sc->head = sc->length;
|
||||
bail:
|
||||
if (data)
|
||||
free (data);
|
||||
close_flac (ff);
|
||||
return sc;
|
||||
}
|
||||
|
||||
static void
|
||||
flac_callback_load (void *object, cache_allocator_t allocator)
|
||||
{
|
||||
QFile *file;
|
||||
flacfile_t *ff;
|
||||
|
||||
sfxblock_t *block = (sfxblock_t *) object;
|
||||
|
||||
QFS_FOpenFile (block->file, &file);
|
||||
if (!file)
|
||||
return; //FIXME Sys_Error?
|
||||
|
||||
if (!(ff = open_flac (file))) {
|
||||
Sys_Printf ("Input does not appear to be an Ogg bitstream.\n");
|
||||
Qclose (file);
|
||||
return; //FIXME Sys_Error?
|
||||
}
|
||||
flac_load (ff, block, allocator);
|
||||
}
|
||||
|
||||
static void
|
||||
flac_cache (sfx_t *sfx, char *realname, flacfile_t *ff, wavinfo_t info)
|
||||
{
|
||||
sfxblock_t *block = calloc (1, sizeof (sfxblock_t));
|
||||
sfx->data = block;
|
||||
sfx->wavinfo = SND_CacheWavinfo;
|
||||
sfx->touch = SND_CacheTouch;
|
||||
sfx->retain = SND_CacheRetain;
|
||||
sfx->release = SND_CacheRelease;
|
||||
|
||||
block->sfx = sfx;
|
||||
block->file = ff;
|
||||
block->wavinfo = info;
|
||||
|
||||
Cache_Add (&block->cache, block, flac_callback_load);
|
||||
}
|
||||
|
||||
static int
|
||||
flac_stream_read (void *file, byte *buf, int count, wavinfo_t *info)
|
||||
{
|
||||
return flac_read (file, buf, count);
|
||||
}
|
||||
|
||||
static int
|
||||
flac_stream_seek (void *file, int pos, wavinfo_t *info)
|
||||
{
|
||||
return FLAC__seekable_stream_decoder_seek_absolute (file, pos);
|
||||
}
|
||||
|
||||
static void
|
||||
flac_stream_close (sfx_t *sfx)
|
||||
{
|
||||
sfxstream_t *stream = (sfxstream_t *)sfx->data;
|
||||
|
||||
close_flac (stream->file);
|
||||
free (stream);
|
||||
free (sfx);
|
||||
}
|
||||
|
||||
static sfx_t *
|
||||
flac_stream_open (sfx_t *_sfx)
|
||||
{
|
||||
sfx_t *sfx;
|
||||
sfxstream_t *stream = (sfxstream_t *) _sfx->data;
|
||||
wavinfo_t *info = &stream->wavinfo;
|
||||
int samples;
|
||||
int size;
|
||||
QFile *file;
|
||||
|
||||
QFS_FOpenFile (stream->file, &file);
|
||||
if (!file)
|
||||
return 0;
|
||||
|
||||
sfx = calloc (1, sizeof (sfx_t));
|
||||
samples = shm->speed * 0.3;
|
||||
size = samples = (samples + 255) & ~255;
|
||||
if (!snd_loadas8bit->int_val)
|
||||
size *= 2;
|
||||
if (info->channels == 2)
|
||||
size *= 2;
|
||||
stream = calloc (1, sizeof (sfxstream_t) + size);
|
||||
memcpy (stream->buffer.data + size, "\xde\xad\xbe\xef", 4);
|
||||
|
||||
sfx->name = _sfx->name;
|
||||
sfx->data = stream;
|
||||
sfx->wavinfo = SND_CacheWavinfo;
|
||||
sfx->touch = sfx->retain = SND_StreamRetain;
|
||||
sfx->release = SND_StreamRelease;
|
||||
sfx->close = flac_stream_close;
|
||||
|
||||
stream->sfx = sfx;
|
||||
stream->file = open_flac (file);
|
||||
if (!stream->file) {
|
||||
Sys_Printf ("Input does not appear to be a flac bitstream.\n");
|
||||
Qclose (file);
|
||||
free (stream);
|
||||
free (sfx);
|
||||
return 0;
|
||||
}
|
||||
stream->resample = info->channels == 2 ? SND_ResampleStereo
|
||||
: SND_ResampleMono;
|
||||
stream->read = flac_stream_read;
|
||||
stream->seek = flac_stream_seek;
|
||||
stream->wavinfo = *info;
|
||||
|
||||
stream->buffer.length = samples;
|
||||
stream->buffer.advance = SND_StreamAdvance;
|
||||
stream->buffer.setpos = SND_StreamSetPos;
|
||||
stream->buffer.sfx = sfx;
|
||||
|
||||
stream->resample (&stream->buffer, 0, 0, 0); // get sfx setup properly
|
||||
stream->seek (stream->file, 0, &stream->wavinfo);
|
||||
|
||||
stream->buffer.advance (&stream->buffer, 0);
|
||||
|
||||
return sfx;
|
||||
}
|
||||
|
||||
static void
|
||||
flac_stream (sfx_t *sfx, char *realname, flacfile_t *ff, wavinfo_t info)
|
||||
{
|
||||
sfxstream_t *stream = calloc (1, sizeof (sfxstream_t));
|
||||
|
||||
sfx->open = flac_stream_open;
|
||||
sfx->wavinfo = SND_CacheWavinfo;
|
||||
sfx->touch = sfx->retain = SND_StreamRetain;
|
||||
sfx->release = SND_StreamRelease;
|
||||
sfx->data = stream;
|
||||
|
||||
stream->file = ff;
|
||||
stream->wavinfo = info;
|
||||
}
|
||||
|
||||
static wavinfo_t
|
||||
get_info (flacfile_t *ff)
|
||||
{
|
||||
int sample_start = -1, sample_count = 0;
|
||||
int samples;
|
||||
wavinfo_t info;
|
||||
FLAC__StreamMetadata_VorbisComment *vc;
|
||||
FLAC__StreamMetadata_VorbisComment_Entry *ve;
|
||||
FLAC__uint32 i;
|
||||
|
||||
samples = ff->info.total_samples;
|
||||
vc = &ff->vorbis_info->data.vorbis_comment;
|
||||
|
||||
for (i = 0, ve = vc->comments;
|
||||
i < ff->vorbis_info->data.vorbis_comment.num_comments; ve++) {
|
||||
Sys_DPrintf ("%.*s\n", ve->length, ve->entry);
|
||||
if (strncmp ("CUEPOINT=", ve->entry, 9) == 0) {
|
||||
char *str = alloca (ve->length + 1);
|
||||
strncpy (str, ve->entry, ve->length);
|
||||
str[ve->length] = 0;
|
||||
sscanf (str + 9, "%d %d", &sample_start, &sample_count);
|
||||
}
|
||||
}
|
||||
|
||||
if (sample_start != -1)
|
||||
samples = sample_start + sample_count;
|
||||
|
||||
info.rate = ff->info.sample_rate;
|
||||
info.width = ff->info.bits_per_sample / 8;
|
||||
info.channels = ff->info.channels;
|
||||
info.loopstart = sample_start;
|
||||
info.samples = samples;
|
||||
info.dataofs = 0;
|
||||
info.datalen = samples * 2;
|
||||
|
||||
if (developer->int_val) {
|
||||
Sys_Printf ("\nBitstream is %d channel, %dHz\n",
|
||||
info.channels, info.rate);
|
||||
Sys_Printf ("\nDecoded length: %d samples (%d bytes)\n",
|
||||
info.samples, info.samples * info.channels * 2);
|
||||
Sys_Printf ("Encoded by: %.*s\n\n",
|
||||
vc->vendor_string.length, vc->vendor_string.entry);
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
void
|
||||
SND_LoadFLAC (QFile *file, sfx_t *sfx, char *realname)
|
||||
{
|
||||
flacfile_t *ff;
|
||||
wavinfo_t info;
|
||||
|
||||
if (!(ff = open_flac (file))) {
|
||||
Sys_Printf ("Input does not appear to be an Ogg bitstream.\n");
|
||||
Qclose (file);
|
||||
return;
|
||||
}
|
||||
info = get_info (ff);
|
||||
if (info.channels < 1 || info.channels > 2) {
|
||||
Sys_Printf ("unsupported number of channels");
|
||||
return;
|
||||
}
|
||||
if (info.samples / info.rate < 3) {
|
||||
Sys_DPrintf ("cache %s\n", realname);
|
||||
flac_cache (sfx, realname, ff, info);
|
||||
} else {
|
||||
Sys_DPrintf ("stream %s\n", realname);
|
||||
flac_stream (sfx, realname, ff, info);
|
||||
}
|
||||
}
|
||||
|
||||
#endif//HAVE_FLAC
|
|
@ -322,6 +322,13 @@ SND_Load (sfx_t *sfx)
|
|||
return;
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_VORBIS
|
||||
if (strnequal ("fLaC", buf, 4)) {
|
||||
Sys_DPrintf ("SND_Load: flac file\n");
|
||||
SND_LoadFLAC (file, sfx, realname);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_WILDMIDI
|
||||
if (strnequal ("MThd", buf, 4)) {
|
||||
Sys_DPrintf ("SND_Load: midi file\n");
|
||||
|
|
Loading…
Reference in a new issue