/* Copyright 2003 Stefano Maini (a.k.a. Sty) This file is part of Drumpiler. Drumpiler is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Drumpiler is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Foobar; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #ifdef USESDL #include #else #include #include #include #include #include #endif #define FREQ 44100 #define SIZE 512 #define BSIZE 9 unsigned long buf[SIZE]; typedef struct { char *file; unsigned long len; unsigned long *p; long Rvol,Lvol; long Rpan,Lpan; } WAV; typedef struct { WAV *wav; int col; unsigned long pos; long Rvol,Lvol; long Rpan,Lpan; } CHAN; #define MAXCHAN 128 #define MAXWAV 128 CHAN chan[MAXCHAN]; WAV wav[MAXWAV]; #define MAXCONST 256 #define MAXFUNC 256 char * sConst[MAXCONST]; char * sFunc[MAXFUNC]; char *Const[MAXCONST]; int Func[MAXFUNC]; int nConst,nFunc; int nchan; float temperr; unsigned long tick; unsigned long streamlen; char *prg; // l'intero file di tezto char **row; // array delle righe int nrow; // numero delle righe FILE *waveout; #ifdef USESDL #define SDLBUF 200000 char *sdlbuf; int tail,head,body; void fill_audio(void *udata, Uint8 *stream, int len) { int i; if(len>body) len=body; if(!len) return; i=len-(SDLBUF-tail); if(i<0) i=0; memcpy(stream,sdlbuf+tail,len-i); memcpy(stream+len-i,sdlbuf,i); tail+=len; if(tail>=SDLBUF) tail-=SDLBUF; body-=len; } void sdlwrite(void *buf,int len) { int i; while ( len>(SDLBUF-body) ) { SDL_PauseAudio(0); SDL_Delay(40); } i=len-(SDLBUF-head); if(i<0) i=0; memcpy(sdlbuf+head,buf,len-i); memcpy(sdlbuf,buf+len-i,i); SDL_LockAudio(); head+=len; if(head>=SDLBUF) head-=SDLBUF; body+=len; SDL_UnlockAudio(); } #else int dsp; #endif void mixer(unsigned long *buf,unsigned long size) { unsigned long i,j; long r,l,rr,ll; WAV *w; CHAN *c; if(!size) return; for(i=0;iwav; if(c->poslen) { l=(long)((signed short)(w->p[c->pos]&0xFFFF)); r=(long)((signed short)(w->p[c->pos]>>16)); ll+= l * c->Lvol + r * c->Rpan; rr+= r * c->Rvol + l * c->Lpan; c->pos++; c++; j++; } else { nchan--; memcpy(c,&chan[nchan],sizeof(CHAN)); } } ll>>=9; rr>>=9; #define CLIPMIN -16384 #define CLIPMAX 16383 if(llCLIPMAX) ll=CLIPMAX; if(rrCLIPMAX) rr=CLIPMAX; buf[i]= (ll&0xFFFF) | ((rr<<16)&0xFFFF0000); } if(waveout) fwrite(buf,4,size,waveout); else { #ifdef USESDL sdlwrite(buf,size<<2); #else write(dsp,buf,size<<2); #endif } streamlen+=size<<2; } #define qputs(s) {printf("(%d) %s \r\n",i+1,s); return 0;} #define skipspace(p) {while(((*p==' ')||(*p==9))&&(*p)) p++;} #define skiparg(p) {while(((*p!=' ')&&(*p!=9))&&(*p)) p++;} int openprg(char *name) { int i,j,k,len,vol,incode,loops,coldef; char *p,*p1,*p2; FILE *f; // carico l'intero file in memoria f = fopen(name,"rb"); if(!f) return 0; fseek(f,0,SEEK_END); len=ftell(f); fseek(f,0,SEEK_SET); prg = malloc(len); fread(prg,1,len,f); fclose(f); // conto le righe, le alloco e le separo for(nrow=0,i=0;i=row[nrow])) {*p=0; p--;} // left trim while((*row[nrow]<=' ')&&(row[nrow]<=p)) {*row[nrow]=0;row[nrow]++;} p=prg+i+1; nrow++; } } incode = 0; loops = 0; coldef=0; for(i=0;i64) qputs("invalid volume value (0-64)"); vol=k; wav[j].Lvol=k; wav[j].Rvol=k; wav[j].Lpan=0; wav[j].Rpan=0; skipspace(p); if(!*p) qputs("missing wave panning"); p1=p; skiparg(p); if(!*p) qputs("missing wave filename"); *p=0; p++; k=atoi(p1); if(k<0||k>64) qputs("invalid panning value (64L-0-64R)"); if(k>0) { k=k*vol/64; switch(*(p1+(strlen(p1)-1))) { case 'R': wav[j].Lvol-=k; wav[j].Lpan+=k; break; case 'L': wav[j].Rvol-=k; wav[j].Rpan+=k; break; default: qputs("invalid panning direction (L/R)"); } } skipspace(p); if(!*p) qputs("missing wave filename"); p1=p; wav[j].file=p1; break; case '$': if(nConst==MAXCONST) qputs("too many constants defined"); if(incode) qputs("$ not allowed inside function"); skipspace(p); if(!*p) qputs("missing constant name"); p1=p; skiparg(p); if(!*p) qputs("missing constant value"); *p=0; p++; skipspace(p); if(!*p) qputs("missing constant value"); p2=p; skiparg(p); *p=0; for(j=0;j0) qputs("there are unclosed loops"); incode=1; coldef=0; skipspace(p); if(!*p) qputs("missing function name"); p1=p; skiparg(p); *p=0; for(j=0;j240) qputs("invalid tempo value (30-240)"); break; case 'd': if(!incode) qputs("s not allowed outside function"); skipspace(p); if(!*p) qputs("missing division value"); p1=p; skiparg(p); *p=0; if(*p1=='$') { *p1++; for(j=0;j64) qputs("invalid division value (1-64)"); break; case 'l': if(!incode) qputs("l not allowed outside function"); skipspace(p); if(!*p) qputs("missing looping value"); p1=p; skiparg(p); *p=0; if(*p1=='$') { *p1++; for(j=0;j1024) qputs("invalid looping value (1-1024)"); loops++; break; case 'e': if(!incode) qputs("e not allowed outside function"); if(!loops) qputs("inexistent loop"); loops--; break; case '-': if(!incode) qputs("- not allowed outside function"); skipspace(p); if(!*p) qputs("missing function name"); p1=p; skiparg(p); *p=0; for(j=0;j': if(!incode) qputs("> not allowed outside function"); coldef=1; break; case '.': if(!incode) qputs(". not allowed outside function"); if(!coldef) qputs("must define > in this function"); break; default: qputs("unrecognized command"); } } if(loops>0) qputs("there are unclosed loops"); return 1; } int sndinit() { #ifdef USESDL SDL_AudioSpec wanted; wanted.freq = FREQ; wanted.format = AUDIO_S16; wanted.channels = 2; wanted.samples = SIZE; wanted.callback = fill_audio; wanted.userdata = NULL; sdlbuf=malloc(SDLBUF); if(!sdlbuf) return 1; if ( SDL_OpenAudio(&wanted, NULL) < 0 ) return 1; #else int rate=FREQ; int stereo=1; int sample=16; unsigned int blk=0x00040000+(BSIZE+2); dsp=open("/dev/dsp",O_WRONLY,0); if (dsp==-1) {puts("dsp open error");return 1;} if(ioctl(dsp,SNDCTL_DSP_SETFRAGMENT,&blk)==-1) { puts("fragsize error"); return 1;} if(ioctl(dsp,SNDCTL_DSP_SAMPLESIZE,&sample)==-1) { puts("sample error"); return 1;} if(ioctl(dsp,SNDCTL_DSP_STEREO,&stereo)==-1) { puts("stereo error"); return 1;} if(ioctl(dsp,SNDCTL_DSP_SPEED,&rate)==-1) { puts("rate error"); return 1;} #endif return 0; } unsigned long wavehead[11]= { 0x46464952,0x0,0x45564157, 0x20746D66,0x10,0x00020001,0x0000AC44,0x0002B110,0x00100004, 0x61746164,0x0}; int wavesave(char *name) { waveout=fopen(name,"wb"); if(!waveout) return 0; fwrite(wavehead,4,11,waveout); return 1; } int waveclose(void) { int i; i=streamlen+36; fseek(waveout,4,SEEK_SET); fwrite(&i,4,1,waveout); i=streamlen; fseek(waveout,40,SEEK_SET); fwrite(&i,4,1,waveout); fclose(waveout); } char prc[1024]; int waveload(WAV *wav,char *pth) { FILE *f; unsigned int i,l; unsigned long *w=0; strcpy(prc,pth); strcat(prc,wav->file); f=fopen(prc,"rb"); if(!f) return 0; if(fread(&i,4,1,f)!=1) return 0; if(i!=0x46464952) return 0; if(fread(&i,4,1,f)!=1) return 0; if(fread(&i,4,1,f)!=1) return 0; if(i!=0x45564157) return 0; while(fread(&i,4,1,f)==1) { if(fread(&l,4,1,f)!=1) return 0; switch(i) { case 0x20746D66: if(l!=0x10) return 0; if(fread(&i,4,1,f)!=1) return 0; if(i!=0x00020001) return 0; if(fread(&i,4,1,f)!=1) return 0; if(i!=FREQ) return 0; if(fseek(f,8,SEEK_CUR)) return 0; break; case 0x61746164: w=malloc(l); if(!w) return 0; if(fread(w,1,l,f)!=l) return 0; wav->len=(l>>2); wav->p=w; fclose(f); return 1; break; default: if(fseek(f,l,SEEK_CUR)) return 0; break; } } return 0; } // tempo = 44100 * 60 / ( bpm * dvs / 4 ) // = numero di campioni per tick /* per ogni tick si incrementa la parte decimale del tempo ogni volta che supera 1 si aggiunge 1 campione al tempo */ void changetempo(int Bpm,int Div) { float t; t = FREQ * 60.0 / ( (float) Bpm * (float) Div / 4.0 ) ; tick = (unsigned long) t; temperr = t - (float) tick; } void runengine(int pc) { char nulstr[]=""; int i,j,x,brkl=0,sp=0,stack[256],loops[256],Bpm=120,Div=4,bpms[256],divs[256]; char *p,*col,*cols[256],*brk=nulstr,*brks[256]; float resto=0.0; unsigned long pos; WAV *w; pc++; changetempo(Bpm,Div); while(pc': col=row[pc]; break; case '*': brk=row[pc]; brkl=strlen(brk); break; case '.': // suona :) j=strlen(row[pc]); for(i=1;ilen; } } } if((row[pc][i]>='1')&&(row[pc][i]<='8')) { w=&wav[col[i]]; if(w->p) { if(ilen; } } } } if(nchan==MAXCHAN) {puts("channels overflow"); return;} chan[nchan].wav=w; chan[nchan].pos=0; chan[nchan].col=i; chan[nchan].Lvol=w->Lvol*(int)(row[pc][i]-'0'); chan[nchan].Rvol=w->Rvol*(int)(row[pc][i]-'0'); chan[nchan].Lpan=w->Lpan*(int)(row[pc][i]-'0'); chan[nchan].Rpan=w->Rpan*(int)(row[pc][i]-'0'); nchan++; } } } pos=tick; while(resto>=1.0) { pos++; resto-=1.0; } resto += temperr; while(pos) { if(pos>=SIZE) { mixer(buf,SIZE); pos-=SIZE; } else { mixer(buf,pos); pos=0; } } break; } pc++; } puts("end of processing"); } int main(int argc,char **argv) { char mainfun[]="main",defpath[]="./"; int i,f,pc; char *fn=0,*pth=defpath,*src=0,*fun=mainfun; char lasto=0; puts("Drumpiler BETA 0.9 by Stefano 'Sty' Maini (drumpiler@sty.cjb.net)"); if(argc==1) {puts("\tdrumpiler [-o output] [-p drmpath] [-f mainfunc] drumsource"); return 1;} for(i=1;i