diff --git a/src/common.h b/src/common.h index fb0d9a6..24d1890 100644 --- a/src/common.h +++ b/src/common.h @@ -1,4 +1,6 @@ +#define MAX_DRV_PARM 10 + struct options { int start; /* start order */ int amplify; /* amplification factor */ @@ -15,6 +17,7 @@ struct options { char *drv_id; /* sound driver ID */ char *out_file; /* output file name */ char *ins_path; /* instrument path */ + char *driver_parm[MAX_DRV_PARM]; /* driver parameters */ char mute[XMP_MAX_CHANNELS]; }; diff --git a/src/main.c b/src/main.c index c28600e..fb30468 100644 --- a/src/main.c +++ b/src/main.c @@ -166,8 +166,8 @@ int main(int argc, char **argv) if (options.silent) { sound = &sound_null; } else { - sound = select_sound_driver(options.drv_id, - &options.freq, &options.format); + sound = select_sound_driver(options.drv_id, &options.freq, + &options.format, options.driver_parm); } if (sound == NULL) { diff --git a/src/options.c b/src/options.c index 98df0a4..60883fa 100644 --- a/src/options.c +++ b/src/options.c @@ -19,7 +19,6 @@ #include "list.h" extern char *optarg; -static int o, i; static char *token; #ifdef HAVE_SYS_RTPRIO_H @@ -50,21 +49,6 @@ static void usage(char *s) printf("Usage: %s [options] [modules]\n", s); -#if 0 - printf("\nRegistered module loaders:\n"); - xmp_get_fmt_info(&fmt); - list_wrap(NULL, 3, 78, 1); - - for (i = 0, f = fmt; f; i++, f = f->next) { - snprintf(buf, 80, "%s (%s)", f->id, f->tracker); - list_wrap(buf, 3, 0, 1); - } - - snprintf(buf, 80, "[%d registered loaders]", i); - list_wrap(buf, 3, 0, 0); - printf("\n"); -#endif - printf("\nAvailable drivers:\n"); list_for_each(head, &sound_driver_list) { @@ -146,8 +130,10 @@ static struct option lopt[] = { void get_options(int argc, char **argv, struct options *options) { int optidx = 0; + int dparm = 0; + int o; + #define OPTIONS "a:b:cD:d:f:hI:iLlM:mno:qRS:s:T:t:uVv" - i = 0; while ((o = getopt_long(argc, argv, OPTIONS, lopt, &optidx)) != -1) { switch (o) { case 'a': @@ -161,11 +147,9 @@ void get_options(int argc, char **argv, struct options *options) case 'c': options->out_file = "-"; break; -#if 0 case 'D': - xmp_set_driver_parameter(opt, optarg); + options->driver_parm[dparm++] = optarg; break; -#endif case 'd': options->drv_id = optarg; break; diff --git a/src/sound.c b/src/sound.c index 75c2a27..831c7ff 100644 --- a/src/sound.c +++ b/src/sound.c @@ -38,7 +38,7 @@ void init_sound_drivers() #endif } -struct sound_driver *select_sound_driver(char *pref, int *rate, int *format) +struct sound_driver *select_sound_driver(char *pref, int *rate, int *format, char **parm) { struct list_head *head; struct sound_driver *sd; @@ -47,7 +47,7 @@ struct sound_driver *select_sound_driver(char *pref, int *rate, int *format) list_for_each(head, &sound_driver_list) { sd = list_entry(head, struct sound_driver, list); if (strcmp(sd->id, pref) == 0) { - if (sd->init(rate, format) == 0) { + if (sd->init(rate, format, parm) == 0) { return sd; } } @@ -56,7 +56,7 @@ struct sound_driver *select_sound_driver(char *pref, int *rate, int *format) list_for_each(head, &sound_driver_list) { sd = list_entry(head, struct sound_driver, list); /* Probing */ - if (sd->init(rate, format) == 0) { + if (sd->init(rate, format, parm) == 0) { /* found */ return sd; } diff --git a/src/sound.h b/src/sound.h index 0f72744..4f35350 100644 --- a/src/sound.h +++ b/src/sound.h @@ -2,13 +2,14 @@ #define __SOUND_H #include +#include #include "list.h" struct sound_driver { char *id; char *description; char **help; - int (*init)(int *, int *); + int (*init)(int *, int *, char **); void (*deinit)(void); void (*play)(void *, int); void (*flush)(void); @@ -17,7 +18,23 @@ struct sound_driver { struct list_head list; }; +#define parm_init() { char *token; for (; *parm; parm++) { \ + char s[80]; strncpy(s, *parm, 80); \ + token = strtok(s, ":="); token = strtok(NULL, ""); +#define parm_end() } } +#define parm_error() do { \ + fprintf(stderr, "xmp: incorrect parameters in -D %s\n", s); \ + exit(-4); } while (0) +#define chkparm0(x,y) { \ + if (!strcmp(s, x)) { \ + if (token != NULL) parm_error(); else { y; } } } +#define chkparm1(x,y) { \ + if (!strcmp(s, x)) { \ + if (token == NULL) parm_error(); else { y; } } } +#define chkparm2(x,y,z,w) { if (!strcmp(s, x)) { \ + if (2 > sscanf(token, y, z, w)) parm_error(); } } + void init_sound_drivers(void); -struct sound_driver *select_sound_driver(char *, int *, int *); +struct sound_driver *select_sound_driver(char *, int *, int *, char **); #endif diff --git a/src/sound_alsa.c b/src/sound_alsa.c index af8b7c4..6ebc957 100644 --- a/src/sound_alsa.c +++ b/src/sound_alsa.c @@ -5,8 +5,7 @@ static snd_pcm_t *pcm_handle; - -static int init(int *rate, int *format) +static int init(int *rate, int *format, char **parm) { snd_pcm_hw_params_t *hwparams; int ret; @@ -15,6 +14,12 @@ static int init(int *rate, int *format) unsigned int ptime = 50000; /* 50ms */ char *card_name = "default"; + parm_init(); + chkparm1("buffer", btime = 1000 * strtoul(token, NULL, 0)); + chkparm1("period", btime = 1000 * strtoul(token, NULL, 0)); + chkparm1("card", card_name = token); + parm_end(); + if ((ret = snd_pcm_open(&pcm_handle, card_name, SND_PCM_STREAM_PLAYBACK, 0)) < 0) { fprintf(stderr, "Unable to initialize ALSA pcm device: %s\n", diff --git a/src/sound_bsd.c b/src/sound_bsd.c index 95781f3..e55fbb3 100644 --- a/src/sound_bsd.c +++ b/src/sound_bsd.c @@ -19,13 +19,7 @@ static int audio_fd; -static char *help[] = { - "gain=val", "Audio output gain (0 to 255)", - "buffer=val", "Audio buffer size (default is 32768)", - NULL -}; - -static int init(int *rate, int *format) +static int init(int *rate, int *format, char **parm) { audio_info_t ainfo; int gain = 128; @@ -100,6 +94,12 @@ static void onresume() { } +static char *help[] = { + "gain=val", "Audio output gain (0 to 255)", + "buffer=val", "Audio buffer size (default is 32768)", + NULL +}; + struct sound_driver sound_bsd = { "bsd", "BSD PCM audio", diff --git a/src/sound_coreaudio.c b/src/sound_coreaudio.c index 719f13b..138620c 100644 --- a/src/sound_coreaudio.c +++ b/src/sound_coreaudio.c @@ -123,14 +123,13 @@ OSStatus render_proc(void *inRefCon, */ -static int init(int *sampling_rate, int *format) +static int init(int *sampling_rate, int *format, char **parm) { struct xmp_options *o = &ctx->o; AudioStreamBasicDescription ad; Component comp; ComponentDescription cd; AURenderCallbackStruct rc; - //char *token, **parm; OSStatus err; UInt32 size, max_frames; diff --git a/src/sound_null.c b/src/sound_null.c index 402cfa3..05b1a7a 100644 --- a/src/sound_null.c +++ b/src/sound_null.c @@ -2,7 +2,7 @@ #include #include "sound.h" -static int init(int *sampling_rate, int *format) +static int init(int *sampling_rate, int *format, char **parm) { return 0; } diff --git a/src/sound_oss.c b/src/sound_oss.c index 1cf2313..553519c 100644 --- a/src/sound_oss.c +++ b/src/sound_oss.c @@ -40,14 +40,9 @@ # endif #endif -static int audio_fd; +struct sound_driver sound_oss; -static char *help[] = { - "frag=num,size", "Set the number and size of fragments", - "dev=", "Audio device to use (default /dev/dsp)", - "nosync", "Don't flush OSS buffers between modules", - NULL -}; +static int audio_fd; static int fragnum, fragsize; static int do_sync = 1; @@ -115,24 +110,21 @@ static void setaudio(int *rate, int *format) } } -static int init(int *rate, int *format) +static int init(int *rate, int *format, char **parm) { char *dev_audio[] = { "/dev/dsp", "/dev/sound/dsp" }; audio_buf_info info; - //static char buf[80]; - //char *token, **parm; + static char buf[80]; int i; fragnum = 16; /* default number of fragments */ i = 1024; /* default size of fragment */ -#if 0 parm_init(); chkparm2("frag", "%d,%d", &fragnum, &i); chkparm1("dev", dev_audio[0] = token); chkparm0("nosync", do_sync = 0); parm_end(); -#endif for (fragsize = 0; i >>= 1; fragsize++) ; if (fragsize < 4) @@ -146,15 +138,12 @@ static int init(int *rate, int *format) setaudio(rate, format); -#if 0 if (ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info) == 0) { snprintf(buf, 80, "%s [%d fragments of %d bytes]", - drv_oss.description, info.fragstotal, + sound_oss.description, info.fragstotal, info.fragsize); - drv_oss.description = buf; + sound_oss.description = buf; } -#endif - ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info); return 0; } @@ -206,6 +195,13 @@ static void onresume() #endif } +static char *help[] = { + "frag=num,size", "Set the number and size of fragments", + "dev=", "Audio device to use (default /dev/dsp)", + "nosync", "Don't flush OSS buffers between modules", + NULL +}; + struct sound_driver sound_oss = { "oss", "OSS PCM audio", diff --git a/src/sound_sndio.c b/src/sound_sndio.c index 7563390..7567f39 100644 --- a/src/sound_sndio.c +++ b/src/sound_sndio.c @@ -22,7 +22,7 @@ static struct sio_hdl *hdl; -static int init(int *rate, int *format) +static int init(int *rate, int *format, char **parm) { struct sio_par par, askpar; diff --git a/src/sound_win32.c b/src/sound_win32.c index a9a3aba..3509898 100644 --- a/src/sound_win32.c +++ b/src/sound_win32.c @@ -31,11 +31,6 @@ static WORD freebuffer; /* */ static WORD nextbuffer; /* next buffer to be mixed */ static int num_buffers; -static char *help[] = { - "buffers=val", "Number of buffers (default 10)", - NULL -}; - static void show_error(int res) { char *msg; @@ -75,18 +70,17 @@ static void CALLBACK wave_callback(HWAVEOUT hwo, UINT uMsg, DWORD dwInstance, } } -static int init(int *sampling_rate, int *format) +static int init(int *sampling_rate, int *format, char **parm) { MMRESULT res; WAVEFORMATEX wfe; int i; - //char *token, **parm; num_buffers = 10; - //parm_init(); - //chkparm1("buffers", num_buffers = strtoul(token, NULL, 0)); - //parm_end(); + parm_init(); + chkparm1("buffers", num_buffers = strtoul(token, NULL, 0)); + parm_end(); if (num_buffers > MAXBUFFERS) num_buffers = MAXBUFFERS; @@ -171,6 +165,11 @@ static void onresume() { } +static char *help[] = { + "buffers=val", "Number of buffers (default 10)", + NULL +}; + struct sound_driver sound_win32 = { "win32", "Windows WinMM",