diff --git a/configure.ac b/configure.ac index ecc1482b2..8c8c5f412 100644 --- a/configure.ac +++ b/configure.ac @@ -507,6 +507,24 @@ case "$target_os" in ;; esac +AC_ARG_ENABLE(wildmidi, +[ --disable-wildmidi disable libWildMidi support], +) +HAVE_WILDMIDI=no +WM_LIBS= +if test "x$enable_wildmidi" != "xno"; then + AC_CHECK_LIB(WildMidi, WildMidi_GetString, HAVE_WILDMIDI=yes, HAVE_WILDMIDI=no) + if test "x$HAVE_WILDMIDI" = "xyes"; then + AC_CHECK_HEADER(wildmidi_lib.h, HAVE_WILDMIDI=yes, HAVE_WILDMIDI=no) + if test "x$HAVE_WILDMIDI" = "xyes"; then + WM_LIBS="-lWildMidi" + AC_DEFINE(HAVE_WILDMIDI, 1, [Define if you have WildMidi]) + fi + fi +fi + +AC_SUBST(WM_LIBS) + AC_ARG_ENABLE(vorbis, [ --disable-vorbis disable ogg vorbis support], ) @@ -2196,6 +2214,7 @@ AC_MSG_RESULT([ Global configuration file : $globalconf User configuration file : $userconf OpenGL dynamic lib : $gl_driver + libWildMidi Support : $HAVE_WILDMIDI ]) if test -d $srcdir/CVS; then diff --git a/include/snd_render.h b/include/snd_render.h index 4198043cf..d8dd237d4 100644 --- a/include/snd_render.h +++ b/include/snd_render.h @@ -126,6 +126,7 @@ void SND_UnblockSound (void); void SND_ResampleMono (sfxbuffer_t *sc, byte *data, int length, void *prev); void SND_ResampleStereo (sfxbuffer_t *sc, byte *data, int length, void *prev); +void SND_NoResampleStereo (sfxbuffer_t *sc, byte *data, int length, void *prev); sfxbuffer_t *SND_GetCache (long samples, int rate, int inwidth, int channels, sfxblock_t *block, cache_allocator_t allocator); @@ -139,6 +140,7 @@ 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_LoadWav (QFile *file, sfx_t *sfx, char *realname); +void SND_LoadMidi (QFile *file, sfx_t *sfx, char *realname); wavinfo_t *SND_CacheWavinfo (sfx_t *sfx); wavinfo_t *SND_StreamWavinfo (sfx_t *sfx); diff --git a/libs/audio/renderer/Makefile.am b/libs/audio/renderer/Makefile.am index ea3ac5a1e..c33c0ac19 100644 --- a/libs/audio/renderer/Makefile.am +++ b/libs/audio/renderer/Makefile.am @@ -13,11 +13,11 @@ EXTRA_PROGRAMS= snd_render_default.la noinst_PROGRAMS= @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 +snd_render_default_la_SOURCES= snd_dma.c snd_mem.c snd_mix.c vorbis.c wav.c midi.c if ASM_ARCH -snd_render_default_la_LDADD= $(VORBISFILE_LIBS) $(VORBIS_LIBS) $(OGG_LIBS) +snd_render_default_la_LDADD= $(VORBISFILE_LIBS) $(VORBIS_LIBS) $(OGG_LIBS) $(WM_LIBS) snd_render_default_la_DEPENDENCIES= else -snd_render_default_la_LDADD= $(VORBISFILE_LIBS) $(VORBIS_LIBS) $(OGG_LIBS) +snd_render_default_la_LDADD= $(VORBISFILE_LIBS) $(VORBIS_LIBS) $(OGG_LIBS) $(WM_LIBS) snd_render_default_la_DEPENDENCIES= endif diff --git a/libs/audio/renderer/midi.c b/libs/audio/renderer/midi.c new file mode 100644 index 000000000..a4120162b --- /dev/null +++ b/libs/audio/renderer/midi.c @@ -0,0 +1,212 @@ +/* + midi.c + + midi file loading for use with libWildMidi + + Copyright (C) 2003 Chris Ison + + 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_WILDMIDI + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#include +#include + +#include "QF/cvar.h" +#include "QF/sound.h" +#include "QF/sys.h" +#include "QF/quakefs.h" + +#include "snd_render.h" + +static int midi_intiialized = 0; + +cvar_t * wildmidi_volume; +cvar_t * wildmidi_config; + +static int +midi_init ( void ) { + wildmidi_volume = Cvar_Get ("wildmidi_volume", "100", CVAR_ARCHIVE, NULL, "Set the Master Volume"); + wildmidi_config = Cvar_Get ("wildmidi_config", "/etc/timidity.cfg", CVAR_ROM, NULL, "path/filename of timidity.cfg"); + + if (WildMidi_Init(wildmidi_config->string, shm->speed, 0) == -1) + return 1; + midi_intiialized = 1; + return 0; +} + +static wavinfo_t +get_info (void * handle) { + wavinfo_t info; + struct _WM_Info *wm_info; + + if ((wm_info = WildMidi_GetInfo(handle)) == NULL) { + Sys_Printf ("Could not obtain midi information\n"); + return info; + } + + info.rate = shm->speed; + info.width = 2; + info.channels = 2; + info.loopstart = -1; + info.samples = wm_info->approx_total_samples; + info.dataofs = 0; + info.datalen = info.samples * 4; + return info; +} + +static int +midi_stream_read (void *file, byte *buf, int count, wavinfo_t *info) +{ + // FIXME: need to check what the return of this function /should/ be + return WildMidi_GetOutput (file, (char *)buf, (unsigned long int)count); +} + +static int +midi_stream_seek (void *file, int pos, wavinfo_t *info) +{ + unsigned long int new_pos; + pos *= info->width * info->channels; + pos += info->dataofs; + new_pos = pos; + + // FIXME: need to check what the return of this function /should/ be + return WildMidi_SampledSeek(file, &new_pos); +} + +static void +midi_stream_close (sfx_t *sfx) +{ + sfxstream_t *stream = (sfxstream_t *)sfx->data; + + WildMidi_Close (stream->file); + free (stream); + free (sfx); +} + +/* + * Note: we only set the QF stream up here. + * The WildMidi stream was setup when SND_OpenMidi was called + * so stream->file contains the WildMidi handle for the midi + */ + +static sfx_t * +midi_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 = stream->file; + + sfx = calloc (1, sizeof (sfx_t)); + samples = shm->speed * 0.3; + size = samples = (samples + 255) & ~255; + + // WildMidi audio data is 16bit stereo + size *= 4; + + 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 = midi_stream_close; + + stream->sfx = sfx; + stream->file = file; + stream->resample = SND_NoResampleStereo; + + stream->read = midi_stream_read; + stream->seek = midi_stream_seek; + stream->wavinfo = *info; + + stream->buffer.length = samples; + stream->buffer.advance = SND_StreamAdvance; + stream->buffer.setpos = SND_StreamSetPos; + stream->buffer.sfx = sfx; + + stream->seek (stream->file, 0, &stream->wavinfo); + stream->buffer.advance (&stream->buffer, 0); + + stream->resample (&stream->buffer, 0, 0, 0); + + return sfx; +} + +void +SND_LoadMidi (QFile *file, sfx_t *sfx, char *realname) +{ + + wavinfo_t info; + sfxstream_t *stream = calloc (1, sizeof (sfxstream_t)); + midi * handle; + unsigned char *local_buffer; + unsigned long int local_buffer_size = Qfilesize(file); + + if (!midi_intiialized) { + if (midi_init()) { + return; + } + } + + + local_buffer = malloc(local_buffer_size); + Qread(file, local_buffer, local_buffer_size); + + // WildMidi takes ownership, so be damned if you touch it + handle = WildMidi_OpenBuffer(local_buffer, local_buffer_size); + + if (handle == NULL) + return; + + info = get_info (handle); + + Sys_DPrintf ("stream %s\n", realname); + + // we init stream here cause we will only ever stream + + sfx->open = midi_stream_open; + sfx->wavinfo = SND_CacheWavinfo; + sfx->touch = sfx->retain = SND_StreamRetain; + sfx->release = SND_StreamRelease; + sfx->data = stream; + + stream->file = handle; + stream->wavinfo = info; +} +#endif // HAVE_WILDMIDI diff --git a/libs/audio/renderer/snd_mem.c b/libs/audio/renderer/snd_mem.c index 7792796bf..6e6605ddd 100644 --- a/libs/audio/renderer/snd_mem.c +++ b/libs/audio/renderer/snd_mem.c @@ -327,6 +327,13 @@ SND_Load (sfx_t *sfx) SND_LoadOgg (file, sfx, realname); return; } +#endif +#ifdef HAVE_WILDMIDI + if (strnequal ("MThd", buf, 4)) { + Sys_DPrintf ("SND_Load: midi file\n"); + SND_LoadMidi (file, sfx, realname); + return; + } #endif if (strnequal ("RIFF", buf, 4)) { Sys_DPrintf ("SND_Load: wav file\n"); @@ -655,3 +662,71 @@ SND_ResampleStereo (sfxbuffer_t *sc, byte *data, int length, void *prev) x[0], x[1], x[2], x[3]); } } + +void +SND_NoResampleStereo (sfxbuffer_t *sc, byte *data, int length, void *prev) +{ + int outcount, i; + stereo8_t *ib, *ob; + stereo16_t *is, *os; + wavinfo_t *info = sc->sfx->wavinfo (sc->sfx); + int inwidth = info->width; + int outwidth; + + is = (stereo16_t *) data; + os = (stereo16_t *) sc->data; + ib = (stereo8_t *) data; + ob = (stereo8_t *) sc->data; + + os += sc->head; + ob += sc->head; + + outcount = length; + + sc->sfx->length = info->samples; + if (info->loopstart != (unsigned int)-1) + sc->sfx->loopstart = info->loopstart; + else + sc->sfx->loopstart = (unsigned int)-1; + + if (snd_loadas8bit->int_val) { + outwidth = 1; + sc->paint = SND_PaintChannelStereo8; + sc->bps = 2; + } else { + outwidth = 2; + sc->paint = SND_PaintChannelStereo16; + sc->bps = 4; + } + + if (!length) + return; + + if (inwidth == 1 && outwidth == 1) { + for (i = 0; i < outcount; i++, ob++, ib++) { + ob->left = ib->left - 128; + ob->right = ib->right - 128; + } + } else if (inwidth == 1 && outwidth == 2) { + for (i = 0; i < outcount; i++, os++, ib++) { + os->left = (ib->left - 128) << 8; + os->right = (ib->right - 128) << 8; + } + } else if (inwidth == 2 && outwidth == 1) { + for (i = 0; i < outcount; i++, ob++, ib++) { + ob->left = LittleShort (is->left) >> 8; + ob->right = LittleShort (is->right) >> 8; + } + } else if (inwidth == 2 && outwidth == 2) { + for (i = 0; i < outcount; i++, os++, is++) { + os->left = LittleShort (is->left); + os->right = LittleShort (is->right); + } + } + { + byte *x = sc->data + sc->length * outwidth * 2; + if (memcmp (x, "\xde\xad\xbe\xef", 4)) + Sys_Error ("SND_ResampleStereo screwed the pooch %02x%02x%02x%02x", + x[0], x[1], x[2], x[3]); + } +}