--- /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";
+}