AM_PATH_GLIB_2_0(, [have_gobject=yes], [have_gobject=no], [gobject])
fi
-AM_CONDITIONAL([BUILD_UPKG], [test x$have_gobject = xyes])
+AC_ARG_WITH([modlib],
+ [AS_HELP_STRING([--with-modlib],
+ [specify which module decoding library to use - one of modplug, none or auto. [default=auto]]
+ )],
+ [with_modlib=$withval],
+ [with_modlib=auto])
+
+CHECK_LIBMODPLUG([have_libmodplug=yes], [have_libmodplug=no])
+AC_MSG_CHECKING([which module library to use])
+case $with_modlib in
+none)
+ use_modlib=none
+;;
+no)
+ use_modlib=none
+;;
+modplug)
+ if test x$have_libmodplug = xyes; then
+ use_modlib=modplug
+ else
+ use_modlib=none
+ fi
+;;
+auto)
+ if test x$have_libmodplug = xyes; then
+ use_modlib=modplug
+ else
+ use_modlib=none
+ fi
+;;
+*)
+ AC_MSG_ERROR([Invalid argument to --with-modlib: $with_modlib])
+;;
+esac
+AC_MSG_RESULT([$use_modlib])
+AM_CONDITIONAL([USE_LIBMODPLUG], [test x$use_modlib = xmodplug])
+AM_CONDITIONAL([USE_DUMMYMOD], [test x$use_modlib = xnone])
+
+AM_CONDITIONAL([BUILD_UPKG], [test x$have_gobject = xyes])
AC_CONFIG_FILES([
Makefile
--- /dev/null
+AC_DEFUN([_LIBMODPLUG_TEST], [dnl
+AC_CACHE_CHECK([whether libmodplug works],
+ [libmodplug_cv_works],
+ [AC_LINK_IFELSE([AC_LANG_PROGRAM([dnl
+#include <modplug.h>
+], [dnl
+unsigned char buf@<:@128@:>@ = {0};
+ModPlugFile *f = ModPlug_Load(buf, sizeof buf);
+ModPlug_Unload(f);
+])], [libmodplug_cv_works=yes], [libmodplug_cv_works=no])])
+])
+
+dnl CHECK_LIBMODPLUG([action-if-ok], [action-if-fail])
+AC_DEFUN([CHECK_LIBMODPLUG],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+AC_ARG_VAR([LIBMODPLUG_CFLAGS], [C compiler flags for libmodplug])dnl
+AC_ARG_VAR([LIBMODPLUG_LIBS], [linker flags for libmodplug])dnl
+
+if test x"$PKG_CONFIG" != x; then
+ AC_MSG_CHECKING([pkg-config database for libmodplug])
+ _PKG_CONFIG([libmodplug_cflags], [cflags], [libmodplug])
+ _PKG_CONFIG([libmodplug_libs], [libs], [libmodplug])
+ if test x$pkg_failed = xyes; then
+ errors=`$PKG_CONFIG --errors-to-stdout --print-errors libmodplug`
+ echo "$errors" >&AS_MESSAGE_LOG_FD
+ AC_MSG_RESULT([no])
+ else
+ if test x"$LIBMODPLUG_CFLAGS" = x; then
+ LIBMODPLUG_CFLAGS=$pkg_cv_libmodplug_cflags
+ fi
+ if test x"$LIBMODPLUG_LIBS" = x; then
+ LIBMODPLUG_LIBS=$pkg_cv_libmodplug_libs
+ fi
+
+ AC_MSG_RESULT([yes])
+ fi
+fi
+
+if test x"$LIBMODPLUG_CFLAGS" = x; then
+ LIBMODPLUG_CFLAGS="-I$includedir/libmodplug"
+fi
+
+if test x"$LIBMODPLUG_LIBS" = x; then
+ LIBMODPLUG_LIBS=-lmodplug
+fi
+
+AC_LANG_PUSH([C])
+old_cflags=$CFLAGS
+old_libs=$LIBS
+CFLAGS="$LIBMODPLUG_CFLAGS $CFLAGS"
+LIBS="$LIBMODPLUG_LIBS $LIBS"
+
+_LIBMODPLUG_TEST
+
+CFLAGS=$old_cflags
+LIBS=$old_libs
+AC_LANG_POP([C])
+
+if test x"$libmodplug_cv_works" = x"yes"; then
+ AC_SUBST([LIBMODPLUG_CFLAGS])
+ AC_SUBST([LIBMODPLUG_LIBS])
+ ifelse([$1], [], [true], [$1])
+else
+ ifelse([$2], [], [AC_MSG_FAILURE([dnl
+libmodplug is required. The latest version can be
+obtained from http://modplug-xmms.sourceforge.net/.
+
+If libmodplug is installed but was not found by this configure script,
+consider adjusting LIBMODPLUG_CFLAGS and/or LIBMODPLUG_LIBS as necessary.
+
+If pkg-config is installed, it may help to adjust PKG_CONFIG_PATH
+if libmodplug is installed in a non-standard prefix.
+])], [$2])
+fi
+])
-noinst_HEADERS += engine/music.h engine/texture.h
+noinst_HEADERS += engine/music.h engine/texture.h engine/music-module.h
lib_LTLIBRARIES += engine.la
engine_la_SOURCES = engine/music.c engine/texture.c engine/engine.c
engine_la_CFLAGS = $(GLIB_CFLAGS)
-engine_la_LDFLAGS = $(GLIB_LIBS)
-engine_la_LDFLAGS += -module -avoid-version -export-symbols-regex _LTX_
+engine_la_LIBADD = $(GLIB_LIBS)
+engine_la_LDFLAGS = -module -avoid-version -export-symbols-regex _LTX_
+
+if USE_DUMMYMOD
+engine_la_SOURCES += engine/music-dummymod.c
+endif
+
+if USE_LIBMODPLUG
+engine_la_SOURCES += engine/music-modplug.c engine/modplug-types.h
+engine_la_CFLAGS += $(LIBMODPLUG_CFLAGS)
+engine_la_LIBADD += $(LIBMODPLUG_LIBS)
+endif
--- /dev/null
+#ifndef MODPLUG_TYPES_H_
+#define MODPLUG_TYPES_H_
+
+#define MOD_TYPE_NONE 0x00
+#define MOD_TYPE_MOD 0x01
+#define MOD_TYPE_S3M 0x02
+#define MOD_TYPE_XM 0x04
+#define MOD_TYPE_MED 0x08
+#define MOD_TYPE_MTM 0x10
+#define MOD_TYPE_IT 0x20
+#define MOD_TYPE_669 0x40
+#define MOD_TYPE_ULT 0x80
+#define MOD_TYPE_STM 0x100
+#define MOD_TYPE_FAR 0x200
+#define MOD_TYPE_WAV 0x400
+#define MOD_TYPE_AMF 0x800
+#define MOD_TYPE_AMS 0x1000
+#define MOD_TYPE_DSM 0x2000
+#define MOD_TYPE_MDL 0x4000
+#define MOD_TYPE_OKT 0x8000
+#define MOD_TYPE_MID 0x10000
+#define MOD_TYPE_DMF 0x20000
+#define MOD_TYPE_PTM 0x40000
+#define MOD_TYPE_DBM 0x80000
+#define MOD_TYPE_MT2 0x100000
+#define MOD_TYPE_AMF0 0x200000
+#define MOD_TYPE_PSM 0x400000
+#define MOD_TYPE_J2B 0x800000
+#define MOD_TYPE_ABC 0x1000000
+#define MOD_TYPE_PAT 0x2000000
+#define MOD_TYPE_UMX 0x80000000 // Fake type
+#define MAX_MODTYPE 24
+
+#endif
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "music-module.h"
+#include "upkg.h"
+
+struct music_mod {
+ struct upkg_file *f;
+};
+
+int music_mod_init(void)
+{
+ return 0;
+}
+
+void music_mod_exit(void)
+{
+}
+
+struct music_mod *music_mod_open(struct upkg_file *f)
+{
+ struct music_mod *m = malloc(sizeof *m);
+
+ if (m) {
+ m->f = f;
+ }
+
+ return m;
+}
+
+void music_mod_close(struct music_mod *m)
+{
+ free(m);
+}
+
+int music_mod_dump(struct music_mod *m, FILE *of)
+{
+ unsigned char buf[1024];
+ size_t rc;
+
+ if (upkg_export_seek(m->f, 0, SEEK_SET) != 0) {
+ return -1;
+ }
+
+ while (1) {
+ rc = upkg_export_read(m->f, buf, sizeof buf);
+ if (rc == 0) {
+ if (!m->f->eof)
+ return -1;
+ return 0;
+ }
+
+ if (fwrite(buf, rc, 1, of) != 1) {
+ if (feof(of)) {
+ fprintf(stderr, "unexpected end-of-file.\n");
+ } else {
+ perror("fwrite");
+ }
+ return -1;
+ }
+
+ if (rc < sizeof buf) {
+ if (!m->f->eof)
+ return -1;
+ return 0;
+ }
+ }
+}
+
+const char *music_mod_type(struct music_mod *mod)
+{
+ return "unknown";
+}
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <modplug.h>
+#include "modplug-types.h"
+
+#include "music-module.h"
+#include "upkg.h"
+
+struct music_mod {
+ ModPlugFile *f;
+ size_t len, alloc;
+ unsigned char buf[];
+};
+
+#define BUF_INIT_SIZE 65536
+
+int music_mod_init(void)
+{
+ ModPlug_Settings settings = {
+ .mFlags = MODPLUG_ENABLE_OVERSAMPLING,
+ .mChannels = 2,
+ .mFrequency = 44100,
+ .mResamplingMode = MODPLUG_RESAMPLE_SPLINE,
+ .mLoopCount = -1,
+ };
+
+ ModPlug_SetSettings(&settings);
+ return 0;
+}
+
+void music_mod_exit(void)
+{
+}
+
+static struct music_mod *readfile(struct upkg_file *f)
+{
+ struct music_mod *m = malloc(sizeof *m + BUF_INIT_SIZE);
+ if (!m) return NULL;
+ *m = (struct music_mod) {
+ .alloc = BUF_INIT_SIZE
+ };
+
+ while (1) {
+ struct music_mod *tmp;
+ size_t sz = m->alloc - m->len;
+
+ m->len += upkg_export_read(f, m->buf + m->len, sz);
+ if (m->alloc != m->len) {
+ if (f->eof) {
+ tmp = realloc(m, sizeof *m + m->len);
+ return tmp ? tmp : m;
+ }
+
+ break;
+ }
+
+ tmp = realloc(m, sizeof *m + 2*m->alloc);
+ if (!tmp)
+ break;
+ m = tmp;
+ m->alloc *= 2;
+ }
+
+ free(m);
+ return NULL;
+}
+
+struct music_mod *music_mod_open(struct upkg_file *f)
+{
+ struct music_mod *m = readfile(f);
+ if (!m) return NULL;
+
+ m->f = ModPlug_Load(m->buf, m->len);
+ if (!m->f) {
+ free(m);
+ return NULL;
+ }
+
+ return m;
+}
+
+int music_mod_dump(struct music_mod *m, FILE *of)
+{
+ if (fwrite(m->buf, m->len, 1, of) != 1)
+ return -1;
+ return 0;
+}
+
+void music_mod_close(struct music_mod *m)
+{
+ ModPlug_Unload(m->f);
+ free(m);
+}
+
+const char *music_mod_type(struct music_mod *m)
+{
+ int type = ModPlug_GetModuleType(m->f);
+
+ if (type & MOD_TYPE_MOD)
+ return "mod";
+ if (type & MOD_TYPE_S3M)
+ return "s3m";
+ if (type & MOD_TYPE_XM)
+ return "xm";
+ if (type & MOD_TYPE_IT)
+ return "it";
+ return "unknown";
+}
--- /dev/null
+#ifndef MUSIC_MODULE_H_
+#define MUSIC_MODULE_H_
+
+#include "upkg.h"
+
+struct music_mod;
+
+/* Initialize the module decoding system. */
+int music_mod_init(void);
+/* Shutdown the module decoding system. */
+void music_mod_exit(void);
+
+struct music_mod *music_mod_open(struct upkg_file *f);
+void music_mod_close(struct music_mod *mod);
+int music_mod_dump(struct music_mod *mod, FILE *of);
+
+const char *music_mod_type(struct music_mod *mod);
+
+#endif
#include "exportable.h"
#include "loadable.h"
#include "uobject.h"
+#include "music-module.h"
#include "music.h"
#include "upkg.h"
struct music_priv {
struct upkg_file *f;
+ struct music_mod *mod;
unsigned loaded;
};
if (upkg_export_seek(priv->f, 0, SEEK_SET) != 0) {
return -1;
}
+
+ priv->mod = music_mod_open(priv->f);
+ if (!priv->mod) {
+ return -1;
+ }
}
priv->loaded++;
struct music_priv *priv = MUSIC_GET_PRIV(o);
g_return_if_fail(priv->loaded > 0);
- --priv->loaded;
+ if (--priv->loaded == 0) {
+ music_mod_close(priv->mod);
+ }
}
static int export(GObject *o, FILE *f)
{
struct music_priv *priv = MUSIC_GET_PRIV(o);
- unsigned char buf[1024];
+ int rc;
- if (!priv->f || upkg_export_seek(priv->f, 0, SEEK_SET) != 0)
+ if (load(o) != 0)
return -1;
- while (!priv->f->eof) {
- size_t rc = upkg_export_read(priv->f, buf, sizeof buf);
- if (rc == 0) {
- if (priv->f->eof) break;
- return -1;
- }
+ rc = music_mod_dump(priv->mod, f);
- if (fwrite(buf, 1, rc, f) != rc)
- return -1;
- }
+ unload(o);
- return 0;
+ return rc;
}
static int export_name(GObject *o, char *buf, size_t n)
{
struct music_priv *priv = MUSIC_GET_PRIV(o);
- return snprintf(buf, n, "%s", priv->f ? priv->f->name : "");
+ const char *type;
+ int rc;
+
+ if (load(o) != 0) {
+ if (n > 0) *buf = 0;
+ return 0;
+ }
+
+ type = music_mod_type(priv->mod);
+ rc = snprintf(buf, n, "%s.%s", priv->f->name, type);
+
+ unload(o);
+
+ return rc;
}
static void exportable_init(UObjectExportable *e)
static int deserialize(UObject *o, struct upkg_file *f)
{
struct music_priv *priv = MUSIC_GET_PRIV(o);
- EngineMusic *m = ENGINE_MUSIC(o);
size_t rc, pos = 0, buflen;
unsigned char buf[32];
long size;
f->base += pos;
f->len = size;
upkg_export_seek(f, 0, SEEK_SET);
-
priv->f = f;
return 0;
uo->deserialize = deserialize;
go->finalize = engine_music_finalize;
+
+ music_mod_init();
}
static void engine_music_class_finalize(EngineMusicClass *class)
{
+ music_mod_exit();
}