Mercurial > hg > forks > pwpunix
view pwpzax/zaxplay.c @ 80:d2121ed6e67e
Cosmetics.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Tue, 14 Aug 2012 06:17:39 +0300 |
parents | 561fa061caf6 |
children |
line wrap: on
line source
/* * PWP music player. Uses libSDL for audio output. * * compile: gcc -O3 -o zaxplay zaxplay.c `sdl-config --libs --cflags` * * run: zaxplay <tunenum> * */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <SDL.h> #include <math.h> 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" static const pwpmusic *tunes[] = { &Final_Isi, &Future_Moottori, &Go_Mazzembly, &Ikuisuus }; static const int ntunes = sizeof(tunes) / sizeof(tunes[0]); const pwpmusic *tune; struct { 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) 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; 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; } } 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--){ *d++=64+((ph>>8)&0x80); ph+=freq; } } #define ch pwpgb.ch void 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++; } void gb_genwave(char*d,int l) { int remain=0; l<<=8; while(l) { int min=ch[0].wvleft,w,sum; w=ch[1].wvleft;if(w<min)min=w; w=ch[2].wvleft;if(w<min)min=w; sum=ch[0].wvphase+ch[1].wvphase+ch[2].wvphase+128; if(sum<0)sum=0;else if(sum>255)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].wvlgt1; ch[i].wvlgt1=ch[i].wvlgt; ch[i].wvlgt=ch[i].wvleft; ch[i].wvphase=0-ch[i].wvphase; } } } } } struct { int ord,patt,row; int tick,tempo; int frag, curr, freq; } player; void player_set_tempo(int tempo) { player.tempo = tempo; player.frag = (player.freq * tempo) / 73; } void player_newnote() { int c=0; for(;c<tune->numchans;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]; } } } 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; } else { gb_genwave((char *)buf, player.curr); buf += player.curr; len -= player.curr; player.curr = player.frag; player_newnote(); } } } static void sdlaudio_close(void) { fprintf(stderr, "* Closing audio.\n"); SDL_CloseAudio(); SDL_Quit(); } int main(int argc, char *argv[]) { 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 <tunenum 0..%d>\n", argv[0], ntunes - 1); return 0; } 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_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; } 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; } } sdlaudio_close(); return 0; }