]> git.draconx.ca Git - upkg.git/commitdiff
Implement support for libmodplug in Engine.Music.
authorNick Bowler <nbowler@draconx.ca>
Tue, 14 Jul 2009 23:41:52 +0000 (19:41 -0400)
committerNick Bowler <nbowler@draconx.ca>
Tue, 14 Jul 2009 23:41:52 +0000 (19:41 -0400)
configure.ac
m4/libmodplug.m4 [new file with mode: 0644]
src/engine/Makefile.inc
src/engine/modplug-types.h [new file with mode: 0644]
src/engine/music-dummymod.c [new file with mode: 0644]
src/engine/music-modplug.c [new file with mode: 0644]
src/engine/music-module.h [new file with mode: 0644]
src/engine/music.c

index 468147bb73354dadcebf99d49e45ba5ea7bba2c9..808965be4ff0ede5c49a3f9a83165e2ec8064c7b 100644 (file)
@@ -29,8 +29,46 @@ if test x$with_gobject = xyes; then
 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
diff --git a/m4/libmodplug.m4 b/m4/libmodplug.m4
new file mode 100644 (file)
index 0000000..cd16e8a
--- /dev/null
@@ -0,0 +1,75 @@
+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
+])
index 897ba2b4b297529e769f3731771d880a15c35453..774f7082da5da62f2c2cacb5f22a798e7c41970b 100644 (file)
@@ -1,7 +1,17 @@
-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
diff --git a/src/engine/modplug-types.h b/src/engine/modplug-types.h
new file mode 100644 (file)
index 0000000..e75156d
--- /dev/null
@@ -0,0 +1,34 @@
+#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
diff --git a/src/engine/music-dummymod.c b/src/engine/music-dummymod.c
new file mode 100644 (file)
index 0000000..c2e61b7
--- /dev/null
@@ -0,0 +1,73 @@
+#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";
+}
diff --git a/src/engine/music-modplug.c b/src/engine/music-modplug.c
new file mode 100644 (file)
index 0000000..e0a0695
--- /dev/null
@@ -0,0 +1,108 @@
+#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";
+}
diff --git a/src/engine/music-module.h b/src/engine/music-module.h
new file mode 100644 (file)
index 0000000..d425b9e
--- /dev/null
@@ -0,0 +1,19 @@
+#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
index f770662995e8f63e2ea359117b005850783b7fc6..c562911af25aee00772452674e2565b403e58024 100644 (file)
@@ -5,6 +5,7 @@
 #include "exportable.h"
 #include "loadable.h"
 #include "uobject.h"
+#include "music-module.h"
 #include "music.h"
 #include "upkg.h"
 
@@ -13,6 +14,7 @@
 
 struct music_priv {
        struct upkg_file *f;
+       struct music_mod *mod;
        unsigned loaded;
 };
 
@@ -34,6 +36,11 @@ static int load(GObject *o)
                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++;
@@ -45,35 +52,43 @@ static void unload(GObject *o)
        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)
@@ -91,7 +106,6 @@ static void loadable_init(UObjectLoadable *l)
 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;
@@ -120,7 +134,6 @@ static int deserialize(UObject *o, struct upkg_file *f)
        f->base += pos;
        f->len   = size;
        upkg_export_seek(f, 0, SEEK_SET);
-
        priv->f = f;
 
        return 0;
@@ -155,8 +168,11 @@ static void engine_music_class_init(EngineMusicClass *class)
 
        uo->deserialize = deserialize;
        go->finalize    = engine_music_finalize;
+
+       music_mod_init();
 }
 
 static void engine_music_class_finalize(EngineMusicClass *class)
 {
+       music_mod_exit();
 }