/* * Example Interface for libmodplug without using XMMS ** commandline interface to modplugxmms library gurkan@linuks.mine.nu www.linuks.mine.nu Copyright (C) 2003 Gürkan Sengün TODO unlock /dev/dsp when in 'p'ause mode and have a look at SNDCTL_DSP_GETxPTR more functions sig handling 12:23 < tp76> tarzeau: yes. I prefer `T *foo = malloc (N * sizeof *foo);'. use stat() to get filesize run indent -kr 14:08 < tarzeau> so the player isn't stuck when anotehr thing is using /dev/dsp 14:08 < tarzeau> if that works a msg is displayed 14:08 < tarzeau> later the song is tried to be opened 14:08 < tarzeau> then the soundcard settings are set 14:09 < tarzeau> the the module is load using libmodplug 14:09 < tarzeau> module settings being set 14:09 < tarzeau> keyboard handling set 14:09 < tarzeau> the status string set up 14:09 < tarzeau> time stuff and the main loop 14:09 < warp> ok. 14:09 < tarzeau> where keyboard input is handled 14:09 < tarzeau> that's more or less it 14:10 < warp> see, you've just described all the functions you could make. 14:10 < warp> so, start that for loop with a init_sound_device () or something. 14:10 < warp> etc... make functions for all the things you just described. 14:10 < tarzeau> heh good idea, i'll copy paste this irc talk and do that for the next version like 0.9 with the sighandler for people trying to ctrl-c or ctlr-z maybe add support for write a .wav file for later play or .ogg and maybe add support for gzip -d some.mod.gz | modplugplay add support to allow modplugplay *.IT *.it *.s3m *.xm (n)ext (N)ot next and -r for random order (make a random played/unplayed (bit)list) show file size argument processing if it's not a file, we check if it's an option if not we ignore it action keys -> like key (put in list/directory) -> dislike key (remove) -> show info || [] >> << >| () TODO or maybe just a $HOME/.modplugplay or /etc/modplugplay command line option handling -l --loop -m --mono -s --stereo (default) -4 --44100 (default) -2 --22050 -1 --11025 -8 --8bit (default is 16bit) -h --help -q --quiet -v --version (head -c1080 module |strings) -i --info don't play, only show module info (songname,length,size,type) */ #include /* printf */ #include /* strcpy */ #include /* srand/rand */ #include #include /* core */ #include /* control device */ #include #ifdef __NetBSD__ #include #else #include #endif #include /* gettimeofday */ #include #include /* poll for keyboard input */ #include /* needed to get terminal size */ #define VERSION "1.0" #define BUF_SIZE 4096 #define DEVICE_NAME "/dev/dsp" static struct termios stored_settings; int audio_fd, mixer_fd; unsigned char audio_buffer[BUF_SIZE]; char order[3]; typedef struct { int x, y; } term_size; /* inquire actual terminal size */ static int get_term_size(int fd, term_size *t) { #ifdef TIOCGSIZE struct ttysize win; #elif defined(TIOCGWINSZ) struct winsize win; #endif #ifdef TIOCGSIZE if (ioctl(fd,TIOCGSIZE,&win)) return 0; if (t) { t->y=win.ts_lines; t->x=win.ts_cols; } #elif defined TIOCGWINSZ if (ioctl(fd,TIOCGWINSZ,&win)) return 0; if (t) { t->y=win.ws_row; t->x=win.ws_col; } #else { const char *s; s=getenv("LINES"); if (s) t->y=strtol(s,NULL,10); else t->y=25; s=getenv("COLUMNS"); if (s) t->x=strtol(s,NULL,10); else t->x=80; } #endif return 1; } void set_keypress(void) { struct termios new_settings; tcgetattr(0,&stored_settings); new_settings=stored_settings; new_settings.c_lflag &= (~ICANON); new_settings.c_lflag &= (~ECHO); new_settings.c_cc[VTIME] = 0; new_settings.c_cc[VMIN] = 1; tcsetattr(0,TCSANOW,&new_settings); return; } void reset_keypress(void) { tcsetattr(0,TCSANOW,&stored_settings); return; } void ansi_cursor(int visible) { if (visible) { printf("\033[?25h"); } else { printf("\033[?25l"); } } void help(char *s) { printf("Copyright (C) 2003 Gürkan Sengün\n"); printf("Version %s compiled on %s at %s.\n",VERSION,__DATE__,__TIME__); printf("\n"); printf("%s: too few arguments\n",s); printf("Usage: modplugplay" /*[OPTIONS]*/" [FILES]\n"); printf("\n"); /* printf(" -v print version info\n"); printf(" -h print help\n"); printf(" -l start in looping mode\n"); */ /* printf(" -r randomize play sequence\n"); printf(" -c write to console instead of %s\n",DEVICE_NAME); printf(" -i use stdin for file input\n"); printf(" -q be quiet\n"); */ exit(1); } int get_byteorder() { #define sz sizeof(int) int ival; int format; char s[sz]; char t[sz]; int i, lit, big; for (i=0; i>= 8; if (s[i] == c) lit++; if (s[sz-i-1] == c) big++; t[i] = c; } if (lit == sz && big == 0) { /*printf("little endian\n");*/ format = AFMT_S16_LE; strcpy(order, "LE"); } else if (big == sz && lit == 0) { /*printf("big endian\n");*/ format = AFMT_S16_BE; strcpy(order, "BE"); } else { strcpy(order, "??"); format = -1; } return(format); } char *getFileData(char *filename, long *size) { FILE *f; char *data; f = fopen(filename, "rb"); if (f == NULL) { return NULL; } fseek(f, 0L, SEEK_END); (*size) = ftell(f); rewind(f); data = (char*)malloc(*size); fread(data, *size, sizeof(char), f); fclose(f); return(data); } int getpcmvol() /* get absolute pcm volume, 0 - 100 (for left+right) */ { int vol; if ((mixer_fd=open("/dev/mixer", O_RDONLY | O_NONBLOCK, 0)) == -1) { printf("can't open mixer\n"); exit(1); } ioctl(mixer_fd,MIXER_READ(SOUND_MIXER_PCM),&vol); close(mixer_fd); vol=vol & 255; if (vol==100) vol=99; return(vol); } int setrelpcmvol(int newvol) /* set relative pcm volume, -100 .. 100 */ { int currentvol=getpcmvol(); currentvol+=newvol; if (currentvol>100) currentvol=100; if (currentvol<0) currentvol=0; newvol=currentvol+(currentvol*256); if ((mixer_fd=open("/dev/mixer", O_RDONLY | O_NONBLOCK, 0)) == -1) { printf("can't open mixer\n"); exit(1); } ioctl(mixer_fd,MIXER_WRITE(SOUND_MIXER_PCM),&newvol); close(mixer_fd); } int main(int argc, char* argv[]) { long size; char *d; term_size terminal; ModPlugFile *f2; int mlen, len; struct timeval tvstart; struct timeval tv; struct timeval tvpause; struct timeval tvunpause; struct timeval tvptotal; char status[161]; char songname[41]; char notpaus[4]; int vol=getpcmvol(); int songsplayed = 0; ModPlug_Settings settings; ModPlug_GetSettings(&settings); int format; int channels = 2; int speed = 44100; int c; // kontest char buffer[128]; int result, nread; struct pollfd pollfds; int timeout = 1; /* Timeout in msec. */ int loop=0; // kontest int pause=0; int mono=0; int bits=0; int song; int millisecond; char *randplayed; /* randomly played songs songs that are n/N'd are done or not? */ /* what about N if the previous song is not playable? */ /* maybe mark it played in randplayed */ // [rev--dly--] [sur--dly--] [bas--rng--] int rev=0; // a int revdly=0; // s int sur=0; // d int surdly=0; // y int bas=0; // x int basrng=0; // c if ((format = get_byteorder()) == -1) { return 1; } /* Initialize pollfds; we're looking at input, stdin */ pollfds.fd = 0; /* stdin */ pollfds.events = POLLIN; /* Wait for input */ if (argc==1) { help(argv[0]); } if (!get_term_size(STDIN_FILENO,&terminal)) { fprintf(stderr,"warning: failed to get terminal size\n"); } srand(time(NULL)); for (song=1; song 0) { ioctl(audio_fd,SNDCTL_DSP_RESET,0); ModPlug_Seek(f2,(tv.tv_sec-tvstart.tv_sec-tvptotal.tv_sec)*1000-10000); tvstart.tv_sec+=10; } } /* backward 10" */ /* if (buffer[0]=='i') { printf("\n"); } */ /* if (buffer[0]=='a') { rev++; settings.mReverbDepth=rev; ModPlug_SetSettings(&settings); } if (buffer[0]=='A') { rev--; settings.mReverbDepth=rev; ModPlug_SetSettings(&settings); } if (buffer[0]=='s') { revdly++; settings.mReverbDelay=revdly; ModPlug_SetSettings(&settings); } if (buffer[0]=='S') { revdly--; settings.mReverbDelay=revdly; ModPlug_SetSettings(&settings); } if (buffer[0]=='d') { sur++; settings.mSurroundDepth=sur; ModPlug_SetSettings(&settings); } if (buffer[0]=='D') { sur--; settings.mSurroundDepth=sur; ModPlug_SetSettings(&settings); } if (buffer[0]=='y') { surdly++; settings.mSurroundDelay=surdly; ModPlug_SetSettings(&settings); } if (buffer[0]=='Y') { surdly--; settings.mSurroundDelay=surdly; ModPlug_SetSettings(&settings); } if (buffer[0]=='x') { bas++; settings.mBassAmount=bas; ModPlug_SetSettings(&settings); } if (buffer[0]=='X') { bas--; settings.mBassAmount=bas; ModPlug_SetSettings(&settings); } if (buffer[0]=='c') { basrng++; settings.mBassRange=basrng; ModPlug_SetSettings(&settings); } if (buffer[0]=='C') { basrng--; settings.mBassRange=basrng; ModPlug_SetSettings(&settings); } */ if (buffer[0]=='n') { if (song1) { song-=2; mlen=0; pause=0; ioctl(audio_fd,SNDCTL_DSP_RESET,0); } } if (buffer[0]=='r') { song=(int) ((float)(argc-1)*rand()/(RAND_MAX+1.0)); mlen=0; pause=0; ioctl(audio_fd,SNDCTL_DSP_RESET,0); /* printf("\n[%d?]\n",song+1); */ } /*if (buffer[0]=='R') { song=(int) ((float)(argc-1)*rand()/(RAND_MAX+1.0)); mlen=0; pause=0; }*/ if (buffer[0]=='1') { /* 11025 hertz */ speed=11025; ioctl(audio_fd,SNDCTL_DSP_RESET,0); if (ioctl(audio_fd,SNDCTL_DSP_SPEED,&speed) == -1) { perror("SNDCTL_DSP_SPEED"); exit(1); } settings.mFrequency = 11025; ModPlug_SetSettings(&settings); f2=ModPlug_Load(d,size); ModPlug_Seek(f2,(tv.tv_sec-tvstart.tv_sec-tvptotal.tv_sec)*1000+10000); } if (buffer[0]=='2') { /* 22050 hertz */ speed=22050; ioctl(audio_fd,SNDCTL_DSP_RESET,0); if (ioctl(audio_fd,SNDCTL_DSP_SPEED,&speed) == -1) { perror("SNDCTL_DSP_SPEED"); exit(1); } settings.mFrequency = 22050; ModPlug_SetSettings(&settings); f2=ModPlug_Load(d,size); ModPlug_Seek(f2,(tv.tv_sec-tvstart.tv_sec-tvptotal.tv_sec)*1000+10000); } if (buffer[0]=='4') { /* 44100 hertz */ speed=44100; ioctl(audio_fd,SNDCTL_DSP_RESET,0); if (ioctl(audio_fd,SNDCTL_DSP_SPEED,&speed) == -1) { perror("SNDCTL_DSP_SPEED"); exit(1); } settings.mFrequency = 44100; ModPlug_SetSettings(&settings); f2=ModPlug_Load(d,size); ModPlug_Seek(f2,(tv.tv_sec-tvstart.tv_sec-tvptotal.tv_sec)*1000+10000); } if (buffer[0]=='8') { /* 8/16 bit */ /*format=;*/ bits^=1; if (bits) { format=AFMT_U8; strcpy(order,""); } else { if (get_byteorder()==0) { format=AFMT_S16_LE; strcpy(order,"LE"); } else if (get_byteorder()==1) { format=AFMT_S16_BE; strcpy(order,"BE"); } else { printf("could not determine byte order.\n"); strcpy(order,"??"); return 1; } } ioctl(audio_fd,SNDCTL_DSP_RESET,0); if (ioctl(audio_fd,SNDCTL_DSP_SETFMT, &format) == -1) { perror("SND_CTL_DSP_SETFMT"); exit(1); } if (bits) settings.mBits=8; else settings.mBits=16; ModPlug_SetSettings(&settings); f2=ModPlug_Load(d,size); ModPlug_Seek(f2,(tv.tv_sec-tvstart.tv_sec-tvptotal.tv_sec)*1000+10000); } if (buffer[0]=='m') { /* mono/stereo */ mono^=1; if (mono) channels=1; else channels=2; ioctl(audio_fd,SNDCTL_DSP_RESET,0); if (ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &channels) == -1) { perror("SNDCTL_DSP_CHANNELS"); exit(1); } if (mono) settings.mChannels=1; else settings.mChannels=2; ModPlug_SetSettings(&settings); f2=ModPlug_Load(d,size); ModPlug_Seek(f2,(tv.tv_sec-tvstart.tv_sec-tvptotal.tv_sec)*1000+10000); } if (buffer[0]=='l') { loop^=1; if (loop) { memcpy(status+4,"loop",4); } else { memcpy(status+4,"play",4); } } /* loop */ if (buffer[0]=='+') { setrelpcmvol(4); } if (buffer[0]=='-') { setrelpcmvol(-4); } if (buffer[0]=='p') { pause^=1; ioctl(audio_fd,SNDCTL_DSP_RESET,0); if (pause) { gettimeofday(&tvpause,NULL); memcpy(notpaus,status+4,4); memcpy(status+4,"paus",4); } else { gettimeofday(&tvunpause,NULL); memcpy(status+4,notpaus,4); tvptotal.tv_sec+=tvunpause.tv_sec-tvpause.tv_sec; tvptotal.tv_usec+=tvunpause.tv_usec-tvpause.tv_usec; /* printf(status,tv.tv_sec-tvstart.tv_sec,tv.tv_usec/100000); */ } } /* pause */ } } } } printf("\n"); reset_keypress(); ModPlug_Unload(f2); close(audio_fd); free(d); } /* valid module */ } /* for */ return 0; }