]> git.draconx.ca Git - upkg.git/blobdiff - src/engine/music-modplug.c
Implement support for libmodplug in Engine.Music.
[upkg.git] / src / engine / music-modplug.c
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";
+}