# HG changeset patch # User Matti Hamalainen # Date 1274365056 -10800 # Node ID cf56b64a3c1159a4abcb86948fb9af635b067d6d # Parent e5049100f6ac92e1ec3d6667faaf5c1b319d31c3 Prototyping of a improved zaxplay with SDL audio output. Does not work as intended yet. diff -r e5049100f6ac -r cf56b64a3c11 pwpzax/orig.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pwpzax/orig.c Thu May 20 17:17:36 2010 +0300 @@ -0,0 +1,313 @@ +/* + * PWP music player. Uses /dev/dsp (8-bit unsigned raw) + * + * compile: gcc zaxplay.c -o zaxplay -lm + * + * run: zaxplay + * + */ + +#include +#include + +#include +/* #include */ + +#include +#include +#include + +typedef struct +{ + char*title; + int numchans; + int tempo; + + unsigned char*patord; + unsigned char*tracks; +}pwpmusic; + +#include "Final_Isi.h" +#include "Future_Moottori.h" +#include "Go_Mazzembly.h" +#include "Ikuisuus.h" + +struct { + int wvlgt; + int wvleft; + int wvphase; +} +gb_ch[3]; +#define ch gb_ch + +int fd; +int freq=8000; + +pwpmusic*tune; +pwpmusic*tunes[]={&Final_Isi,&Future_Moottori,&Go_Mazzembly,&Ikuisuus}; +#define NUMTUNES 4 + +gb_gen1chan(char*d,int l,int freq) +{ + int ph=128*256; + while(l--){ + *d++=64+((ph>>8)&0x80); + ph+=freq; + } +} + +gb_beepemu(char*d,int l) +{ + static int pf=0; + int + fq0=ch[0].wvlgt, + fq1=ch[1].wvlgt, + fq2=ch[2].wvlgt,fq; + if(ch[0].wvphase==0)fq0=32768; + if(ch[1].wvphase==0)fq1=32768; + if(ch[2].wvphase==0)fq2=32768; + + if(fq0>fq1){int tmp=fq0;fq0=fq1;fq1=tmp;} + if(fq0>fq2){int tmp=fq0;fq0=fq2;fq2=tmp;} + if(fq1>fq2){int tmp=fq1;fq1=fq2;fq2=tmp;} + + if(pf&1){ + if(pf&2)fq=fq1;else fq=fq2; + if(!fq)fq=fq0; + }else{ + fq=fq0; + if(fq==32768){fq=fq1; + if(fq==32768)fq=fq2;} + } + if(fq==32768)memset(d,128,l);else + { + fq=(65536*256)/fq; + gb_gen1chan(d,l,fq); + } + pf++; +} + +gb_genwave(char*d,int l) /* tee oBtiMoITU versio joskus */ +{ + int remain=0; + + l<<=8; + while(l){ + int min=ch[0].wvleft,w,sum; + w=ch[1].wvleft;if(w255)sum=255; + + if(min>l)min=l; l-=min; + memset(d,sum,(min+remain)>>8); + d+=((min+remain)>>8); + remain=(min+remain)&255; + + {int i=0; + for(;i<3;i++){ + w=ch[i].wvleft-=min; + if(!w){ + ch[i].wvleft=ch[i].wvlgt; /* add pulseratio */ + ch[i].wvphase=0-ch[i].wvphase; + } + }} + } +} + +/* my_memset, ... */ + +/* +gb_genwave_opt(char*buf,int endptr) +{ + #define SETTILL(a) \ + {int bord=w##a,rs;if(bord>endptr)goto last;\ + rs=sum;if(rs&~0xff){if(rs<0)rs=0;else rs=255;}\ + memset(buf+(ptr>>8),rs,2+((bord-ptr)>>8));ptr=bord;\ + ch[a].wvphase=0-ch[a].wvphase;\ + sum+=(ch[a].wvphase)<<1;\ + w##a=ptr+ch[a].wvlgt;} + #define HANDLE(s0,s1,s2) \ + {SETTILL(s0); \ + if(w##s0<=w##s1)goto w##s0##w##s1##w##s2;else \ + if(w##s0<=w##s2)goto w##s1##w##s0##w##s2;else \ + goto w##s1##w##s2##w##s0;} + + int ptr=0,sum=ch[0].wvphase+ + ch[1].wvphase+ + ch[2].wvphase; + + int w0=ch[0].wvleft, + w1=ch[1].wvleft, + w2=ch[2].wvleft; + + endptr<<=8; + + w1w2w0:HANDLE(1,2,0); + w2w1w0:HANDLE(2,1,0); + w0w2w1:HANDLE(0,2,1); + w2w0w1:HANDLE(2,0,1); + w0w1w2:HANDLE(0,1,2); + w1w0w2:HANDLE(1,0,2); + + last: + {int rs=sum; + if(rs&~0xff){if(rs<0)rs=0;else rs=255;} + memset(buf+(ptr>>8),rs,(endptr-ptr)>>8);} + + ch[0].wvleft=w0-endptr; + ch[1].wvleft=w1-endptr; + ch[2].wvleft=w2-endptr; + + #undef SETTILL +} +*/ + +gb_genwave_opt(char*buf,int endptr) +{ + int ptr=0,sum=ch[0].wvphase+ + ch[1].wvphase+ + ch[2].wvphase; + + #define w0 ch[0].wvleft + #define w1 ch[1].wvleft + #define w2 ch[2].wvleft + +/* volatile int w0=ch[0].wvleft, + w1=ch[1].wvleft, + w2=ch[2].wvleft;*/ + + endptr<<=8; + + #define SETTILL(a) \ + {int bord=w##a,rs;if(bord>endptr)goto last;\ + rs=sum;if(rs&~0xff){if(rs<0)rs=0;else rs=255;}\ + memset(buf+(ptr>>8),rs,2+((bord-(ptr&~0xff))>>8));ptr=bord;\ + ch[a].wvphase=0-ch[a].wvphase;\ + sum+=(ch[a].wvphase)<<1;\ + w##a=ptr+ch[a].wvlgt;} + + if(w0<=w1){ + if(w1<=w2)goto w0w1w2;else + if(w2<=w0)goto w2w0w1;else + goto w0w2w1; + }else{ + if(w0<=w2)goto w1w0w2;else + if(w2<=w1)goto w2w1w0; //.. else w1w2w0 (next) + } + + w1w2w0: + SETTILL(1); + if(w1<=w2)goto w1w2w0;else + if(w1<=w0)goto w2w1w0;else //.. if(w1>w0)goto w2w0w1; + goto w2w0w1; + w2w1w0: + SETTILL(2); + if(w2<=w1)goto w2w1w0;else + if(w2<=w0)goto w1w2w0;else + goto w1w0w2; + + w0w2w1: + SETTILL(0); + if(w0<=w2)goto w0w2w1;else + if(w0<=w1)goto w2w0w1;else //.. if(w0>w1)goto w2w1w0; + goto w2w1w0; + w2w0w1: + SETTILL(2); + if(w2<=w0)goto w2w0w1;else + if(w2<=w1)goto w0w2w1;else + goto w0w1w2; //.. not reqd + + w0w1w2: + SETTILL(0); + if(w0<=w1)goto w0w1w2;else + if(w0<=w2)goto w1w0w2;else //.. if(w0>w2)goto w1w2w0; + goto w1w2w0; + + w1w0w2: + SETTILL(1); + if(w1<=w0)goto w1w0w2;else + if(w1<=w2)goto w0w1w2;else + goto w0w2w1; + + last: + {int rs=sum; + if(rs&~0xff){if(rs<0)rs=0;else rs=255;} + memset(buf+(ptr>>8),rs,2+((endptr-ptr)>>8));} + + ch[0].wvleft=w0-endptr; + ch[1].wvleft=w1-endptr; + ch[2].wvleft=w2-endptr; + + #undef SETTILL +} +#define VOLUME 32 + +playnote(char*buf) /* ==> playtick */ +{ + static int ord=0,row=0; + int chan=0,pat=tune->patord[ord]; + + for(;channumchans;chan++){ + unsigned char b=tune->tracks[(pat*tune->numchans+chan)*64+row]; + + if(b==254)gb_ch[chan].wvphase=0;else + if(b!=255){ + b=(b>>4)*12+(b&15); + gb_ch[chan].wvlgt= + ((double)(400.0*256)/pow(1.059465,b)); + + if(gb_ch[chan].wvlgt<512) + gb_ch[chan].wvlgt=512; + + gb_ch[chan].wvleft=gb_ch[chan].wvlgt/(chan+2); + gb_ch[chan].wvphase=VOLUME; + } + } + + gb_genwave(buf,tune->tempo*freq/73); + write(fd,buf,tune->tempo*freq/73); + +/* {int j=4;for(;j;j--){ + gb_beepemu(buf,tune->tempo*freq/(73*4)); + write(fd,buf,tune->tempo*freq/(73*4));}}*/ + + row++;if(row==64){ + row=0;pat=tune->patord[++ord]; + if(pat==255)ord=0; + } +} + +playzax() +{ + int i=0; + char*buf=malloc(tune->tempo*freq/73); + fd=open("/dev/dsp",O_WRONLY); + + for(;i<3;i++){ + gb_ch[i].wvlgt=gb_ch[i].wvleft=32000;gb_ch[i].wvphase=0;} + + for(;;){ + playnote(buf); + } +} + +int main(int argc,char**argv) +{ + if(argc!=2) + { + fprintf(stderr,"usage: %s \n", + argv[0],NUMTUNES-1); + return 0; + } + + {int i=argv[1][0]-'0'; + if(i<0 || i>=NUMTUNES)i=rand()%NUMTUNES; + tune=tunes[i]; + } + + playzax(); + return 0; +} diff -r e5049100f6ac -r cf56b64a3c11 pwpzax/zaxplay.c --- a/pwpzax/zaxplay.c Tue May 18 20:47:07 2010 +0300 +++ b/pwpzax/zaxplay.c Thu May 20 17:17:36 2010 +0300 @@ -1,20 +1,16 @@ /* - * PWP music player. Uses /dev/dsp (8-bit unsigned raw) + * PWP music player. Uses libSDL for audio output. * - * compile: gcc zaxplay.c -o zaxplay -lm + * compile: gcc -O3 -o zaxplay zaxplay.c `sdl-config --libs --cflags` * - * run: zaxplay + * run: zaxplay * */ #include #include - #include -/* #include */ - -#include -#include +#include #include typedef struct @@ -25,29 +21,64 @@ unsigned char*patord; unsigned char*tracks; -}pwpmusic; +} pwpmusic; #include "Final_Isi.h" #include "Future_Moottori.h" #include "Go_Mazzembly.h" #include "Ikuisuus.h" +static const pwpmusic *tunes[] = { + &Final_Isi, &Future_Moottori, &Go_Mazzembly, &Ikuisuus +}; +static const int ntunes = sizeof(tunes) / sizeof(tunes[0]); +pwpmusic *tune; + + struct { - int wvlgt; - int wvleft; - int wvphase; -} -gb_ch[3]; -#define ch gb_ch + struct { + int wvlgt; + int wvleft; + int wvphase; + int wvlgt1; + }ch[3]; + int freq; +} pwpgb; + +#define pwplib_volume 64 +#define pwplib_sound_off(c) gb_sound(c,0,0,0) +#define pwplib_sound_n(c,n) p gb_sound(c,n,128,128) +#define pwplib_sound_nv(c,n,v) gb_sound(c,n,v,128) +#define pwplib_sound_nvr(c,n,v,r) gb_sound(c,n,v,r) -int fd; -int freq=8000; +void gb_sound(int chan,int freq,int volume,int ratio) +{ + if(volume&&freq){ + int wvlgt= + ((double)(pwpgb.freq*12)/pow(1.059465,freq/256.0)); + + if(ratio<1)ratio=1;else if(ratio>255)ratio=255; + + pwpgb.ch[chan].wvlgt=(wvlgt*ratio)>>7; + pwpgb.ch[chan].wvlgt1=2*pwpgb.ch[chan].wvlgt-wvlgt; -pwpmusic*tune; -pwpmusic*tunes[]={&Final_Isi,&Future_Moottori,&Go_Mazzembly,&Ikuisuus}; -#define NUMTUNES 4 + pwpgb.ch[chan].wvleft=pwpgb.ch[chan].wvlgt/(chan+2); + pwpgb.ch[chan].wvphase=volume; + }else{ + pwpgb.ch[chan].wvphase=0; + pwpgb.ch[chan].wvleft=pwpgb.ch[chan].wvlgt=32123; + } +} -gb_gen1chan(char*d,int l,int freq) +void gb_init(int freq) +{ + int i; + pwpgb.freq = freq; + for(i=0;i<3;i++) + gb_sound(i,0,0,0); +} + +void gb_gen1chan(char*d,int l,int freq) { int ph=128*256; while(l--){ @@ -56,7 +87,9 @@ } } -gb_beepemu(char*d,int l) +#define ch pwpgb.ch + +void gb_beepemu(char*d,int l) { static int pf=0; int @@ -87,17 +120,17 @@ pf++; } -gb_genwave(char*d,int l) /* tee oBtiMoITU versio joskus */ +void gb_genwave(char*d,int l) { int remain=0; l<<=8; - while(l){ + while(l) + { int min=ch[0].wvleft,w,sum; w=ch[1].wvleft;if(w255)sum=255; @@ -109,205 +142,169 @@ {int i=0; for(;i<3;i++){ w=ch[i].wvleft-=min; - if(!w){ - ch[i].wvleft=ch[i].wvlgt; /* add pulseratio */ + if(!w) + { + ch[i].wvleft=ch[i].wvlgt1; + ch[i].wvlgt1=ch[i].wvlgt; + ch[i].wvlgt=ch[i].wvleft; ch[i].wvphase=0-ch[i].wvphase; } - }} + } + } } } -/* my_memset, ... */ - -/* -gb_genwave_opt(char*buf,int endptr) -{ - #define SETTILL(a) \ - {int bord=w##a,rs;if(bord>endptr)goto last;\ - rs=sum;if(rs&~0xff){if(rs<0)rs=0;else rs=255;}\ - memset(buf+(ptr>>8),rs,2+((bord-ptr)>>8));ptr=bord;\ - ch[a].wvphase=0-ch[a].wvphase;\ - sum+=(ch[a].wvphase)<<1;\ - w##a=ptr+ch[a].wvlgt;} - #define HANDLE(s0,s1,s2) \ - {SETTILL(s0); \ - if(w##s0<=w##s1)goto w##s0##w##s1##w##s2;else \ - if(w##s0<=w##s2)goto w##s1##w##s0##w##s2;else \ - goto w##s1##w##s2##w##s0;} - - int ptr=0,sum=ch[0].wvphase+ - ch[1].wvphase+ - ch[2].wvphase; - - int w0=ch[0].wvleft, - w1=ch[1].wvleft, - w2=ch[2].wvleft; - - endptr<<=8; - - w1w2w0:HANDLE(1,2,0); - w2w1w0:HANDLE(2,1,0); - w0w2w1:HANDLE(0,2,1); - w2w0w1:HANDLE(2,0,1); - w0w1w2:HANDLE(0,1,2); - w1w0w2:HANDLE(1,0,2); - - last: - {int rs=sum; - if(rs&~0xff){if(rs<0)rs=0;else rs=255;} - memset(buf+(ptr>>8),rs,(endptr-ptr)>>8);} - - ch[0].wvleft=w0-endptr; - ch[1].wvleft=w1-endptr; - ch[2].wvleft=w2-endptr; - - #undef SETTILL -} -*/ - -gb_genwave_opt(char*buf,int endptr) -{ - int ptr=0,sum=ch[0].wvphase+ - ch[1].wvphase+ - ch[2].wvphase; - - #define w0 ch[0].wvleft - #define w1 ch[1].wvleft - #define w2 ch[2].wvleft - -/* volatile int w0=ch[0].wvleft, - w1=ch[1].wvleft, - w2=ch[2].wvleft;*/ - - endptr<<=8; - - #define SETTILL(a) \ - {int bord=w##a,rs;if(bord>endptr)goto last;\ - rs=sum;if(rs&~0xff){if(rs<0)rs=0;else rs=255;}\ - memset(buf+(ptr>>8),rs,2+((bord-(ptr&~0xff))>>8));ptr=bord;\ - ch[a].wvphase=0-ch[a].wvphase;\ - sum+=(ch[a].wvphase)<<1;\ - w##a=ptr+ch[a].wvlgt;} - - if(w0<=w1){ - if(w1<=w2)goto w0w1w2;else - if(w2<=w0)goto w2w0w1;else - goto w0w2w1; - }else{ - if(w0<=w2)goto w1w0w2;else - if(w2<=w1)goto w2w1w0; //.. else w1w2w0 (next) - } - w1w2w0: - SETTILL(1); - if(w1<=w2)goto w1w2w0;else - if(w1<=w0)goto w2w1w0;else //.. if(w1>w0)goto w2w0w1; - goto w2w0w1; - w2w1w0: - SETTILL(2); - if(w2<=w1)goto w2w1w0;else - if(w2<=w0)goto w1w2w0;else - goto w1w0w2; - - w0w2w1: - SETTILL(0); - if(w0<=w2)goto w0w2w1;else - if(w0<=w1)goto w2w0w1;else //.. if(w0>w1)goto w2w1w0; - goto w2w1w0; - w2w0w1: - SETTILL(2); - if(w2<=w0)goto w2w0w1;else - if(w2<=w1)goto w0w2w1;else - goto w0w1w2; //.. not reqd - - w0w1w2: - SETTILL(0); - if(w0<=w1)goto w0w1w2;else - if(w0<=w2)goto w1w0w2;else //.. if(w0>w2)goto w1w2w0; - goto w1w2w0; - - w1w0w2: - SETTILL(1); - if(w1<=w0)goto w1w0w2;else - if(w1<=w2)goto w0w1w2;else - goto w0w2w1; - - last: - {int rs=sum; - if(rs&~0xff){if(rs<0)rs=0;else rs=255;} - memset(buf+(ptr>>8),rs,2+((endptr-ptr)>>8));} +struct { + int ord,patt,row; + int tick,tempo; + int frag, curr, freq; +} player; - ch[0].wvleft=w0-endptr; - ch[1].wvleft=w1-endptr; - ch[2].wvleft=w2-endptr; - #undef SETTILL -} -#define VOLUME 32 - -playnote(char*buf) /* ==> playtick */ +void player_set_tempo(int tempo) { - static int ord=0,row=0; - int chan=0,pat=tune->patord[ord]; - - for(;channumchans;chan++){ - unsigned char b=tune->tracks[(pat*tune->numchans+chan)*64+row]; - - if(b==254)gb_ch[chan].wvphase=0;else - if(b!=255){ - b=(b>>4)*12+(b&15); - gb_ch[chan].wvlgt= - ((double)(400.0*256)/pow(1.059465,b)); - - if(gb_ch[chan].wvlgt<512) - gb_ch[chan].wvlgt=512; - - gb_ch[chan].wvleft=gb_ch[chan].wvlgt/(chan+2); - gb_ch[chan].wvphase=VOLUME; - } - } - - gb_genwave(buf,tune->tempo*freq/73); - write(fd,buf,tune->tempo*freq/73); - -/* {int j=4;for(;j;j--){ - gb_beepemu(buf,tune->tempo*freq/(73*4)); - write(fd,buf,tune->tempo*freq/(73*4));}}*/ - - row++;if(row==64){ - row=0;pat=tune->patord[++ord]; - if(pat==255)ord=0; - } + player.tempo = tempo; + player.frag = (player.freq * tempo) / 73; } -playzax() +void player_newnote() { - int i=0; - char*buf=malloc(tune->tempo*freq/73); - fd=open("/dev/dsp",O_WRONLY); + int c=0; + + for(;cnumchans;c++) + { + int note=tune->tracks[(player.patt * tune->numchans + c) * 64 + player.row]; + if(note==254) + pwplib_sound_nv(c,0,0); + else + if(note!=255) + pwplib_sound_nv(c,(note-5)<<8,pwplib_volume); + } + player.row++; + if(player.row==64) + { + player.row=0; + player.ord++; + player.patt=tune->patord[player.ord]; + + if(player.patt>128) + { + if(player.patt==255)player.ord=0;else + { + if(player.patt==254)player.tempo=4; + player.ord++; + } + player.patt=tune->patord[player.ord]; + } + } +} - for(;i<3;i++){ - gb_ch[i].wvlgt=gb_ch[i].wvleft=32000;gb_ch[i].wvphase=0;} +void player_tick(void) +{ + if (player.tick == 0) + player_newnote(); + + player.tick++; + if (player.tick >= player.tempo) + player.tick=0; +} - for(;;){ - playnote(buf); - } +void player_render_cb(void *udata, Uint8 * buf, int len) +{ + (void) udata; + while (len > 0) { + if (player.curr > len) { + player.curr -= len; + gb_genwave((char *)buf, len); + len = 0; + player_tick(); + } else { + gb_genwave((char *)buf, player.curr); + buf += player.curr; + len -= player.curr; + player.curr = player.frag; + player_tick(); + } + } +} + +static void sdlaudio_close(void) +{ + fprintf(stderr, "* Closing audio.\n"); + SDL_CloseAudio(); + SDL_Quit(); } int main(int argc,char**argv) { - if(argc!=2) + SDL_Event event; + SDL_AudioSpec fmt; + int i; + + /* Settings */ + fmt.freq = 44100; + fmt.format = AUDIO_U8; + fmt.channels = 1; + fmt.samples = 2048; + fmt.callback = player_render_cb; + + if (argc != 2) { fprintf(stderr,"usage: %s \n", - argv[0],NUMTUNES-1); + argv[0], ntunes - 1); return 0; } - {int i=argv[1][0]-'0'; - if(i<0 || i>=NUMTUNES)i=rand()%NUMTUNES; - tune=tunes[i]; + i = atoi(argv[1]); + if (i < 0 || i >= ntunes) i = rand() % ntunes; + tune = tunes[i]; + + fprintf(stderr, + "Tune #%d: '%s'\n" + "Tempo: %d\n" + "Channels: %d\n", + i, tune->title, tune->tempo, tune->numchans); + + if (SDL_Init(SDL_INIT_EVENTTHREAD | SDL_INIT_AUDIO) != 0) + { + fprintf(stderr, "* SDL could not be initialized.\n"); + return 1; + } + + fprintf(stderr, "* SDL audio request %d, %d, %d -> %d\n", + fmt.freq, fmt.format, fmt.channels, fmt.samples); + + if (SDL_OpenAudio(&fmt, NULL) < 0) + { + fprintf(stderr, "* SDL: Could not get desired audio format.\n"); + return 1; } - playzax(); + fprintf(stderr, "* SDL audio initialized %d, %d, %d -> %d\n", + fmt.freq, fmt.format, fmt.channels, fmt.samples); + + atexit(sdlaudio_close); + + gb_init(fmt.freq); + player.freq = fmt.freq; + player.row = player.ord = 0; + player.patt = tune->patord[0]; + player.tick = 0; + player_set_tempo(tune->tempo); + player.curr = player.frag; + + SDL_PauseAudio(0); + + + while (SDL_WaitEvent(&event) >= 0) { + switch (event.type) { + case SDL_QUIT: + fprintf(stderr, "* Quitting\n"); + exit(0); + break; + } + } + return 0; }