/* GAI Visual Audio version 0.3 - Visualize the music played by XMMS Copyright (C) March 2003 Jonas Aaberg This program 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. This program 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 this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Some parts are taken from XMMS 1.2.7 by Peter Alm and some part are from the XMMS plugin finespectrum 1.0.1alpha by Vágvölgyi Attila The line algorithm is take from timecop's wmfishmon. Depends on GAI - get it and other applets at http://gai.sf.net v0.3 - Fixed bug in Blur scope. - Added two channels on the blurscope. - Fixed about box bug. - Logo shown when no xmms is running. v0.2 - Now draws flower and spec based upon both channels. The flower has better colours. Dual channels possible in spectrum mode. Invert spectrum colours. */ #include #include #include #include #include #include #include #include #include #include "xmmsctrl.h" #define DEF_WIDTH 56 #define DEF_HEIGHT 56 static int width, height; static short *buffer; static unsigned char *pic; static unsigned char *pal = NULL, *pal2 = NULL; static short *bar = NULL; static double scale, my_x0, my_y0, step, colour_step; static GdkPixbuf *va_pic; /* Settings */ static int type_blur, type_spec, type_flower; static int freq_blur; static int mixed, mixed_blur; static int invert_left, invert_right; static int upside_down_left, upside_down_right; static unsigned char blur_red, blur_green, blur_blue, blur_alpha; static unsigned char blur_red2, blur_green2, blur_blue2, blur_alpha2; static unsigned char top_red, top_green, top_blue, top_alpha; static unsigned char bottom_red, bottom_green, bottom_blue, bottom_alpha; static unsigned char flower_inner_red, flower_inner_green, flower_inner_blue, flower_inner_alpha; static unsigned char flower_outer_red, flower_outer_green, flower_outer_blue, flower_outer_alpha; /*----------------------------------------------------------------------------*/ /* Preference window */ static GaiRadioButton type_1 = {"Blur scope",&type_blur, &type_blur,1}; static GaiRadioButton type_2 = {"Spectrum",&type_spec, &type_spec,1}; static GaiRadioButton type_3 = {"Flower spectrum",&type_flower, &type_flower,1}; static GaiBox type_box[] = {{GAI_RADIOBUTTON, &type_1}, {GAI_RADIOBUTTON, &type_2}, {GAI_RADIOBUTTON, &type_3}, {GAI_END, NULL}}; static GaiColourSelector scope_colour = {"Left(First) channel colour: ", &blur_red,&blur_green,&blur_blue,&blur_alpha,1}; static GaiColourSelector scope_colour2 = {"Right channel colour: ", &blur_red2,&blur_green2,&blur_blue2,&blur_alpha2,6}; static GaiCheckButton mixed_button2 = {"Mix left and right channel to one" ,&mixed_blur, &mixed_blur}; static GaiBox scope_box[] = {{GAI_COLOURSELECTOR, &scope_colour}, {GAI_COLOURSELECTOR, &scope_colour2}, {GAI_CHECKBUTTON, &mixed_button2}, {GAI_END, NULL}}; static GaiColourSelector top_colour = {"Top colour: ", &top_red,&top_green,&top_blue,&top_alpha,2}; static GaiColourSelector bottom_colour = {"Bottom colour: ", &bottom_red,&bottom_green,&bottom_blue,&bottom_alpha,3}; static GaiCheckButton blur_buttom = {"Blured",&freq_blur, &freq_blur}; static GaiCheckButton mixed_button = {"Mix left and right channel to one" ,&mixed, &mixed}; static GaiCheckButton invert_left_button = {"Invert left channel", &invert_left, &invert_left}; static GaiCheckButton invert_right_button = {"Invert right channel", &invert_right, &invert_right}; static GaiCheckButton upside_down_right_button = {"Draw right channel upside down", &upside_down_right, &upside_down_right}; static GaiCheckButton upside_down_left_button = {"Draw left channel upside down", &upside_down_left, &upside_down_left}; static GaiBox spec_spec_box[] = {{GAI_CHECKBUTTON, &blur_buttom}, {GAI_CHECKBUTTON, &mixed_button}, {GAI_CHECKBUTTON, &invert_left_button}, {GAI_CHECKBUTTON, &invert_right_button}, {GAI_CHECKBUTTON, &upside_down_left_button}, {GAI_CHECKBUTTON, &upside_down_right_button}, {GAI_COLOURSELECTOR, &top_colour}, {GAI_COLOURSELECTOR, &bottom_colour}, {GAI_END, NULL}}; static GaiColourSelector flower_inner_colour = {"Inner colour: ", &flower_inner_red, &flower_inner_green, &flower_inner_blue, &flower_inner_alpha,4}; static GaiColourSelector flower_outer_colour = {"Outer colour: ", &flower_outer_red, &flower_outer_green, &flower_outer_blue, &flower_outer_alpha,5}; static GaiBox flower_box[] = {{GAI_COLOURSELECTOR, &flower_inner_colour}, {GAI_COLOURSELECTOR, &flower_outer_colour}, {GAI_END, NULL}}; static GaiFrame spec_type_frame = {"Type", NULL, (void *)&type_box, NULL}; static GaiFrame spec_scope_frame = {"Blur scope", NULL, (void *)&scope_box, NULL}; static GaiFrame spec_spec_frame = {"Spectrum", NULL, (void *)&spec_spec_box, NULL}; static GaiFrame spec_flower_frame = {"Flower spectrum", NULL, (void *)&flower_box, NULL}; static GaiBox spec_box[] = {{GAI_FRAME, &spec_type_frame}, {GAI_FRAME, &spec_scope_frame}, {GAI_FRAME, &spec_spec_frame}, {GAI_FRAME, &spec_flower_frame}, {GAI_END, NULL}}; static GaiNoteBook spec_pref[] = {{" ", (void *)&spec_box}, {NULL, NULL}}; static char *about_text = "Name: " APPLET_NAME "\n" "Version: " APPLET_VERSION "\n" "License: GNU GPL\n" "Author: Jonas Aaberg \n" "Some parts are taken from XMMS 1.2.7\nby Peter Alm \n" "and some part are from the\nXMMS plugin finespectrum 1.0.1alpha by\n" "Vagvoelgyi Attila \n" "Summary: GAI Visual Audio\n" "%description Displays the spectrum or scope of any sound played by XMMS.\n" "Remember to enable the plugin in XMMS!\n"; static void gen_pal(unsigned char *loc_pal, int r1, int g1, int b1, int r2, int g2, int b2) { int i; float r_step, g_step, b_step; float r_curr, g_curr, b_curr; r_step = ((float)r2-(float)r1)/255.0; g_step = ((float)g2-(float)g1)/255.0; b_step = ((float)b2-(float)b1)/255.0; r_curr=(float)r1; g_curr=(float)g1; b_curr=(float)b1; loc_pal[256*0]=0; loc_pal[256*1]=0; loc_pal[256*2]=0; for(i=1;i<256;i++){ loc_pal[0*256+i]=(unsigned char)r_curr; loc_pal[1*256+i]=(unsigned char)g_curr; loc_pal[2*256+i]=(unsigned char)b_curr; r_curr+=r_step; g_curr+=g_step; b_curr+=b_step; } } static void draw_pixel(unsigned char *buff, unsigned char *loc_pal, int x, int y, unsigned char c) { // if(x==0 && y==0) return; if(y>=0 && y=0 && x> 2; if(sum > 2) sum -= 2; *(iptr++) = sum; } } static void draw_vert_line(unsigned char *buffer, unsigned char *loc_pal, int x, int y1, int y2) { int y; if(y1 < y2){ for(y = y1; y <= y2; y++) draw_pixel(buffer,loc_pal,x,y,0xFF); } else if(y2 < y1){ for(y = y2; y <= y1; y++) draw_pixel(buffer,loc_pal,x,y,0xFF); } else draw_pixel(buffer,loc_pal,x,y1,0xFF); } /* This line algorithm comes from wmfishmon by Timecop */ static void draw_line(int x1, int y1, int x2, int y2, float angle) { int dx,dy; int error, sign, tmp; float ipix; int line_step=1; int c_step=0; unsigned char c=255; dx = abs(x1 - x2); dy = abs(y1 - y2); if((angle-M_PI) < M_PI/2 && (angle-M_PI) > 0){ c_step = -256/(width/2); c=255; } if((angle-M_PI) <= M_PI/2 && (angle-M_PI) > 0){ c_step = -256/(width/2); c=255; } if((angle-M_PI) > M_PI/2 && (angle-M_PI) < 3*M_PI/4){ c_step = -256/(width/2); c=255; } if((angle-M_PI) >=3*M_PI/4 && (angle-M_PI) < 3*M_PI/2){ c_step = 256/(width/2); c=255 - c_step*(sqrt(dx*dx+dy*dy))- 2*c_step; } if((angle-M_PI) >=3*M_PI/2 && (angle-M_PI) < 2*M_PI){ c_step = -256/(width/2); c=255; } if (dx >= dy) { if (x1 > x2) { tmp = x1; x1 = x2; x2 = tmp; tmp = y1; y1 = y2; y2 = tmp; } error = dx / 2; if (y2 > y1){ sign = line_step; } else { sign = -line_step; } draw_pixel(pic,pal,x1, y1, c); c+=c_step; if(c>250) c=250; while (x1 < x2) { if ((error -= dy) < 0) { y1 += sign; error += dx; } x1 += line_step; ipix = (float) error / dx; if (sign == line_step) ipix = 1 - ipix; draw_pixel(pic,pal,x1, y1, c); c+=c_step; if(c>250) c=250; } draw_pixel(pic,pal,x2, y2, c); c+=c_step; if(c>250) c=250; } else { if (y1 > y2) { tmp = x1; x1 = x2; x2 = tmp; tmp = y1; y1 = y2; y2 = tmp; } error = dy / 2; if (x2 > x1) sign = line_step; else sign = -line_step; draw_pixel(pic,pal,x1, y1, c); c+=c_step; if(c>250) c=250; while (y1 < y2) { if ((error -= dx) < 0) { x1 += sign; error += dy; } y1 += line_step; ipix = (float) error / dy; if (sign == line_step) ipix = 1 - ipix; draw_pixel(pic,pal,x1, y1, c); c+=c_step; if(c>250) c=250; } draw_pixel(pic,pal,x2, y2, c); c+=c_step; if(c>250) c=250; } } static void draw_pcm_spec(void) { int i,y, prev_y, spec; float pcm_step; spec = open("/tmp/spectrum-pcm",O_RDONLY|O_NONBLOCK); if(spec>0) read(spec,(void *) buffer,2*512*sizeof(short)); else memset(buffer,0,2*512*sizeof(short)); blur(pic, width, height, 3*(width+2)); pcm_step = 512/width; prev_y = (height / 2) + (buffer[0] >> 9); for(i = 0; i < width; i++){ y = (height / 2) + (buffer[(int)((float)i*pcm_step)] >> 9); if(mixed_blur){ y = (y + (height / 2) + (buffer[(int)((float)i*pcm_step)+512] >> 9))>>1; } if(y < 0) y = 0; if(y >= height) y = height - 1; draw_vert_line(pic,pal,i,prev_y,y); prev_y = y; } if(!mixed_blur){ for(i = 0; i < width; i++){ y = (height / 2) + (buffer[(int)((float)i*pcm_step)+512] >> 9); if(y < 0) y = 0; if(y >= height) y = height - 1; draw_vert_line(pic,pal2,i,prev_y,y); prev_y = y; } } if(spec>0) close(spec); } static void freq_single_channel(void) { int i,j,a, upside_down=0; upside_down = upside_down_right | upside_down_left; if(!invert_left && !invert_right){ for(i=0;i=a){ draw_pixel(pic,pal,i, height*upside_down+(1-upside_down)*2*j-j, (unsigned char)((float)(j+1)*colour_step)); } else { if(!freq_blur) draw_pixel(pic,pal,i, height*upside_down+(1-upside_down)*2*j-j, 0); } } } } } static void freq_dual_channels(void) { int i,j,a; for(i=0;i=a){ draw_pixel(pic,pal,i, (height/2)*upside_down_left+(1-upside_down_left)*2*j-j, (unsigned char)((float)(j+1)*2*colour_step)); } else { if(!freq_blur) draw_pixel(pic,pal,i, (height/2)*upside_down_left+(1-upside_down_left)*2*j-j, 0); } } } a = (bar[((int)((double)(i)*step+0.5))+256+1]+ bar[((int)((double)(i)*step+0.5))-1+256+1]+ bar[((int)((double)(i)*step+0.5))+1+256+1])/(3*2); if(!invert_right){ for(j=height/2;j=a){ draw_pixel(pic,pal,i, (height+height/2)*upside_down_right+(1-upside_down_right)*2*j-j, (unsigned char)((float)(j+1)*2*colour_step)); } else { if(!freq_blur) draw_pixel(pic,pal,i, (height+height/2)*upside_down_right+(1-upside_down_right)*2*j-j, 0); } } } } } static void draw_freq_spec(void) { int spec,i; spec = open("/tmp/spectrum-freq",O_RDONLY|O_NONBLOCK); if(spec>0) read(spec,(void *) buffer,2*512*sizeof(short)); else memset(buffer,0,2*512*sizeof(short)); if(spec>0) close(spec); if(freq_blur) blur(pic, width, height, 3*(width+2)); for(i=0;i<256;i++) bar[i] = ((short)((log(((double)buffer[i] * (i + 1)) - my_x0) * scale + my_y0))+2*bar[i])/3; for(i=256;i<512;i++) bar[i] = ((short)((log(((double)buffer[i] * ((i-256) + 1)) - my_x0) * scale + my_y0))+2*bar[i])/3; if(mixed) freq_single_channel(); else freq_dual_channels(); } static void draw_freq_flower(void) { int i, spec,a,x,y; double flower_step, angle=M_PI; spec = open("/tmp/spectrum-freq",O_RDONLY|O_NONBLOCK); if(spec>0) read(spec,(void *) buffer,2*512*sizeof(short)); else memset(buffer,0,2*512*sizeof(short)); if(spec>0) close(spec); blur(pic, width, height, 3*(width+2)); for(i=0;i<256;i++) bar[i] = 2*(((short)((log(((double)buffer[i] * (i + 1)) - my_x0) * scale + my_y0))+2*bar[i])/3)/3; for(i=256;i<512;i++) bar[i] = 2*(((short)((log(((double)buffer[i] * ((i-256) + 1)) - my_x0) * scale + my_y0))+2*bar[i])/3)/3; flower_step = 2*M_PI/width; for(i=0;i