diff --git a/src/Makefile b/src/Makefile index f37e2c2..dee1608 100644 --- a/src/Makefile +++ b/src/Makefile @@ -38,8 +38,8 @@ install-docs: $(SRC_PATH)/xmp.1 @[ -d $(DESTDIR)$(MANDIR) ] || mkdir -p $(DESTDIR)$(MANDIR) @$(INSTALL) -m644 $+ $(DESTDIR)$(MANDIR) -install-conf: $(SRC_PATH)/xmp.conf - @echo Installing configuration file in $(DESTDIR)$(SYSCONFDIR) +install-conf: $(SRC_PATH)/xmp.conf $(SRC_PATH)/modules.conf + @echo Installing configuration files in $(DESTDIR)$(SYSCONFDIR) @[ -d $(DESTDIR)$(SYSCONFDIR) ] || mkdir -p $(DESTDIR)$(SYSCONFDIR) @$(INSTALL) -m644 $+ $(DESTDIR)$(SYSCONFDIR) diff --git a/src/common.h b/src/common.h index 9e0d7c8..0565058 100644 --- a/src/common.h +++ b/src/common.h @@ -15,7 +15,7 @@ struct options { int loop; /* loop module */ int random; /* play in random order */ int reverse; /* reverse stereo channels */ - int vblank; /* use vblank timing */ + int flags; /* player flags */ int verbose; /* verbosity level */ int silent; /* silent output */ int info; /* display information and exit */ @@ -43,6 +43,7 @@ int report(char *, ...); /* option */ void get_options(int, char **, struct options *); int read_config(struct options *); +void read_modconf(struct options *, unsigned char *); /* terminal */ int set_tty(void); diff --git a/src/main.c b/src/main.c index 354bf1b..4e2e463 100644 --- a/src/main.c +++ b/src/main.c @@ -147,7 +147,7 @@ int main(int argc, char **argv) xmp_context handle; struct xmp_module_info mi; struct xmp_frame_info fi; - struct options opt; + struct options opt, save_opt; struct control control; int i; int first; @@ -268,7 +268,11 @@ int main(int argc, char **argv) } lf_flag = 0; + memcpy(&save_opt, &opt, sizeof (struct options)); + for (first = optind; optind < argc; optind++) { + memcpy(&opt, &save_opt, sizeof (struct options)); + if (opt.verbose > 0) { if (lf_flag) report("\n"); @@ -310,6 +314,10 @@ int main(int argc, char **argv) } continue; } + + xmp_get_module_info(handle, &mi); + read_modconf(&opt, mi.md5); + skipprev = 0; control.time = 0.0; control.loop = opt.loop; @@ -336,18 +344,15 @@ int main(int argc, char **argv) xmp_channel_mute(handle, i, opt.mute[i]); } - /* Change timing if vblank specified */ + /* Set player flags */ - if (opt.vblank) { - xmp_set_player(handle, XMP_PLAYER_TIMING, - XMP_TIMING_VBLANK); + xmp_set_player(handle, XMP_PLAYER_FLAGS, opt.flags); + if (opt.flags & XMP_FLAGS_VBLANK) { xmp_scan_module(handle); } /* Show module data */ - xmp_get_module_info(handle, &mi); - if (opt.verbose > 0) { info_mod(&mi); } diff --git a/src/modules.conf b/src/modules.conf new file mode 100644 index 0000000..9aab033 --- /dev/null +++ b/src/modules.conf @@ -0,0 +1,33 @@ +# Configuration for specific modules +# xmp will look for this file in /etc/xmp/modules.conf and +# $HOME/.xmp/modules.conf (both files will be read). +# +# Format is: +# +# [MD5sum] +# 8bit = yes/no Convert 16 bit samples to 8 bit +# amplify = <0|1|2|3> Amplification factor (default is 1) +# filter = yes/no Enable filters (affects IT only) +# fixloop = yes/no Use sample loop start value / 2 +# fx9bug = yes/no Protracker 2.x effect 9 bug emulation +# interpolation = Software mixer interpolation +# mono = yes/no Mono output +# mix = value Stereo channel separation (0 - 100) +# reverse = yes/no Reverse L/R stereo channels +# vblank = yes/no Force vblank timing instead of CIA + +# "No Mercy" by Alf/VTL (added by Martin Willers) +[366ec0fa962aebee034aa2dbaa49aaea] +fx9bug = yes + +# mod.souvenir of china +[93f146aeb758c39d8b5fbc98bf237a43] +fixloop = yes + +# "siedler ii" (added by Daniel Ã…kerud) +[70aa034dfb2f1f73d9fdbafe131bb701] +vblank = yes + +# Klisje paa klisje (added by Kjetil Torgrim Homme) +[e998012c700eb43af0321711305829b2] +vblank = yes diff --git a/src/options.c b/src/options.c index 96528f6..7e8e484 100644 --- a/src/options.c +++ b/src/options.c @@ -266,7 +266,7 @@ void get_options(int argc, char **argv, struct options *options) options->format |= XMP_FORMAT_UNSIGNED; break; case OPT_VBLANK: - options->vblank = 1; + options->flags |= XMP_FLAGS_VBLANK; break; case 'V': puts("Extended Module Player " VERSION); diff --git a/src/read_config.c b/src/read_config.c index d8dfafe..d710542 100644 --- a/src/read_config.c +++ b/src/read_config.c @@ -94,16 +94,18 @@ int read_config(struct options *o) val = strtok(NULL, " \t\n"); -#define getval_yn(w,x,y) { \ +#define getval_yn(x,w,y) { \ if (!strcmp(var,x)) { if (get_yesno (val)) w |= (y); \ else w &= ~(y); continue; } } #define getval_no(x,y) { \ if (!strcmp(var,x)) { y = atoi (val); continue; } } - getval_yn(o->format, "8bit", XMP_FORMAT_8BIT); - getval_yn(o->format, "mono", XMP_FORMAT_MONO); - getval_yn(o->dsp, "filter", XMP_DSP_LOWPASS); + getval_yn("8bit", o->format, XMP_FORMAT_8BIT); + getval_yn("mono", o->format, XMP_FORMAT_MONO); + getval_yn("filter", o->dsp, XMP_DSP_LOWPASS); + getval_yn("loop", o->loop, 1); + getval_yn("reverse", o->reverse, 1); getval_no("amplify", o->amplify); getval_no("mix", o->mix); /*getval_no("chorus", o->chorus); @@ -131,11 +133,6 @@ int read_config(struct options *o) } } - if (!strcmp(var, "loop")) { - o->loop = get_yesno(val); - continue; - } - if (!strcmp(var, "bits")) { if (atoi(val) == 8) o->format = XMP_FORMAT_8BIT;; @@ -147,7 +144,8 @@ int read_config(struct options *o) o->ins_path = instrument_path; continue; } - /* If the line does not match any of the previous parameter, + + /* If the line doesn't match any of the previous parameters, * send it to the device driver */ if (o->dparm < MAX_DRV_PARM) { @@ -160,3 +158,112 @@ int read_config(struct options *o) return 0; } + + +static int compare_md5(unsigned char *d, char *digest) +{ + int i; + + for (i = 0; i < 16 && *digest; i++, digest += 2) { + char hex[3]; + hex[0] = digest[0]; + hex[1] = digest[1]; + hex[2] = 0; + + if (d[i] != strtoul(hex, NULL, 16)) + return -1; + } + + return 0; +} + +static void parse_modconf(struct options *o, char *confname, unsigned char *md5) +{ + FILE *rc; + char *hash, *var, *val, line[256]; + int active = 0; + + if ((rc = fopen(confname, "r")) == NULL) + return; + + while (!feof(rc)) { + memset(line, 0, 256); + fscanf(rc, "%255[^\n]", line); + fgetc(rc); + + /* Delete comments */ + if ((hash = strchr(line, '#'))) + *hash = 0; + + if (line[0] == '[') { + if (compare_md5(md5, line + 1) == 0) { + active = 1; + } + continue; + } + + if (!active) + continue; + + delete_spaces(line); + + if (!(var = strtok(line, "=\n"))) + continue; + + val = strtok(NULL, " \t\n"); + + getval_yn("8bit", o->format, XMP_FORMAT_8BIT); + getval_yn("mono", o->format, XMP_FORMAT_MONO); + getval_yn("filter", o->dsp, XMP_DSP_LOWPASS); + getval_yn("loop", o->loop, XMP_DSP_LOWPASS); + getval_yn("reverse", o->reverse, 1); + getval_no("amplify", o->amplify); + getval_no("mix", o->mix); + getval_yn("fixloop", o->flags, XMP_FLAGS_FIXLOOP); + getval_yn("fx9bug", o->flags, XMP_FLAGS_FX9BUG); + getval_yn("vblank", o->flags, XMP_FLAGS_VBLANK); + + if (!strcmp(var, "interpolation")) { + if (!strcmp(val, "nearest")) { + o->interp = XMP_INTERP_NEAREST; + } else if (!strcmp(val, "linear")) { + o->interp = XMP_INTERP_LINEAR; + } else if (!strcmp(val, "spline")) { + o->interp = XMP_INTERP_SPLINE; + } else { + fprintf(stderr, "%s: unknown interpolation " + "type \"%s\"\n", confname, val); + } + } + } + + fclose(rc); +} + + +void read_modconf(struct options *o, unsigned char *md5) +{ +#if defined __EMX__ + char myrc[PATH_MAX]; + char *home = getenv("HOME"); + + snprintf(myrc, PATH_MAX, "%s\\.xmp\\modules.conf", home); + parse_modconf(o, "xmp-modules.conf", md5); + parse_modconf(o, myrc, md5); +#elif defined __AMIGA__ + parse_modconf(o, "PROGDIR:modules.conf", md5); +#elif defined WIN32 + char myrc[PATH_MAX]; + char *home = getenv("SystemRoot"); + + snprintf(myrc, PATH_MAX, "%s/modules.conf", home); + parse_modconf(o, myrc, md5); +#else + char myrc[PATH_MAX]; + char *home = getenv("HOME"); + + snprintf(myrc, PATH_MAX, "%s/.xmp/modules.conf", home); + parse_modconf(o, SYSCONFDIR "/modules.conf", md5); + parse_modconf(o, myrc, md5); +#endif +}