Mercurial > audlegacy
view Plugins/Visualization/paranormal/client.c @ 1717:837983bac90f trunk
[svn] Fixed a lot of warnings that only showed up on *BSD.
author | js |
---|---|
date | Sat, 16 Sep 2006 16:26:54 -0700 |
parents | 14e6dd38e108 |
children | 3ee4c6d45c27 |
line wrap: on
line source
/* pnxmms - An xmms visualization plugin using the Paranormal * audio visualization library * * Copyright (C) 2001 Jamie Gennis <jgennis@mindspring.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifdef HAVE_CONFIG_H #include <config.h> #endif #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <stdio.h> #include <string.h> #include <errno.h> #include <gtk/gtk.h> #include <audacious/plugin.h> #include <libaudacious/configdb.h> #include <SDL/SDL.h> #include <SDL/SDL_thread.h> #include "pn.h" /* Paranormal visualization object */ static PnVis *vis; /* Paranormal audio data object */ static PnAudioData *audio_data; /* SDL window's surface */ static SDL_Surface *screen; /* Synchronization stuffs */ static SDL_Thread *render_thread; static int render_func (void *data); static gboolean kill_render_thread; static gboolean quit_timeout_func (gpointer data); static guint quit_timeout; static gboolean render_thread_finished; static SDL_mutex *vis_mutex; static SDL_mutex *audio_data_mutex; static gfloat intermediate_pcm_data[3][512]; static gfloat intermediate_freq_data[3][256]; /* PNXMMS Options */ static gboolean options_read = FALSE; static gboolean preset_changed = FALSE; static gchar *preset; static guint image_width = 320; static guint image_height = 240; /* Config dialog */ GtkWidget *config_dialog; GtkWidget *load_button; /* Config functions */ static void read_options (void); static void write_options (void); static void load_default_vis (void); static void create_config_dialog (void); /* Rendering functions */ static void draw_image (PnImage *image); /* XMMS interface */ static void pn_xmms_init (void); static void pn_xmms_cleanup (void); static void pn_xmms_about (void); static void pn_xmms_configure (void); static void pn_xmms_render_pcm (gint16 data[2][512]); static void pn_xmms_render_freq (gint16 data[2][256]); static VisPlugin pn_xmms_vp = { NULL, /* handle */ NULL, /* filename */ 0, /* xmms_session */ "Paranormal Visualization Studio " VERSION, 2, 2, pn_xmms_init, pn_xmms_cleanup, NULL, /* pn_xmms_about, */ pn_xmms_configure, NULL, /* disable_plugin */ NULL, /* playback_start */ NULL, /* pkayback_stop */ pn_xmms_render_pcm, pn_xmms_render_freq }; VisPlugin* get_vplugin_info (void) { return &pn_xmms_vp; } static void pn_xmms_init (void) { /* Load the saved options */ read_options (); /* Initialize SDL */ if (SDL_Init (SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE) < 0) { g_warning ("Unable to initialize SDL: %s\n", SDL_GetError ()); pn_xmms_vp.disable_plugin (&pn_xmms_vp); } screen = SDL_SetVideoMode (image_width, image_height, 32, SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_RESIZABLE); if (! screen) { g_warning ("Unable to create a new SDL window: %s\n", SDL_GetError ()); pn_xmms_vp.disable_plugin (&pn_xmms_vp); } SDL_WM_SetCaption ("Paranormal Visualization Studio " VERSION, PACKAGE); /* Initialize Paranormal */ pn_init (); /* Set up the visualization objects */ vis = pn_vis_new (image_width, image_height); pn_object_ref (PN_OBJECT (vis)); pn_object_sink (PN_OBJECT (vis)); if (! preset || ! pn_vis_load_from_file (vis, preset)) load_default_vis (); audio_data = pn_audio_data_new (); pn_object_ref (PN_OBJECT (audio_data)); pn_object_sink (PN_OBJECT (audio_data)); pn_audio_data_set_stereo (audio_data, FALSE); pn_audio_data_set_pcm_samples (audio_data, 512); pn_audio_data_set_freq_bands (audio_data, 256); /* Set up the render thread */ audio_data_mutex = SDL_CreateMutex (); vis_mutex = SDL_CreateMutex (); if (! audio_data_mutex || ! vis_mutex) { g_warning ("Unable to create mutex: %s\n", SDL_GetError ()); pn_xmms_vp.disable_plugin (&pn_xmms_vp); } kill_render_thread = FALSE; render_thread_finished = FALSE; render_thread = SDL_CreateThread (render_func, NULL); if (! render_thread) { g_warning ("Unable to create render thread: %s\n", SDL_GetError ()); pn_xmms_vp.disable_plugin (&pn_xmms_vp); } /* Create the quit-checker timeout */ quit_timeout = gtk_timeout_add (500, quit_timeout_func, NULL); } static void pn_xmms_cleanup (void) { if (quit_timeout != 0) { gtk_timeout_remove (quit_timeout); quit_timeout = 0; } if (render_thread) { kill_render_thread = TRUE; SDL_WaitThread (render_thread, NULL); render_thread = NULL; } if (audio_data_mutex) { SDL_DestroyMutex (audio_data_mutex); audio_data_mutex = NULL; } if (screen) { SDL_FreeSurface (screen); screen = NULL; } SDL_Quit (); if (vis) { pn_object_unref (PN_OBJECT (vis)); vis = NULL; } write_options (); } static void pn_xmms_about (void) { /* FIXME: This needs to wait until XMMS supports GTK+ 2.0 */ } static void pn_xmms_configure (void) { read_options (); create_config_dialog (); } static void pn_xmms_render_pcm (gint16 data[2][512]) { guint i; /* Set up the audio data */ for (i=0; i<512; i++) { intermediate_pcm_data[PN_CHANNEL_LEFT][i] = (gfloat)(data[0][i]) / 32768.0; intermediate_pcm_data[PN_CHANNEL_RIGHT][i] = (gfloat)(data[0][i]) / 32768.0; intermediate_pcm_data[PN_CHANNEL_CENTER][i] = .5 * (intermediate_pcm_data[PN_CHANNEL_LEFT][i] + intermediate_pcm_data[PN_CHANNEL_RIGHT][i]); } } static void pn_xmms_render_freq (gint16 data[2][256]) { guint i; /* Set up the audio data */ for (i=0; i<256; i++) { intermediate_freq_data[PN_CHANNEL_LEFT][i] = (gfloat)(data[0][i]) / 32768.0; intermediate_freq_data[PN_CHANNEL_RIGHT][i] = (gfloat)(data[0][i]) / 32768.0; intermediate_freq_data[PN_CHANNEL_CENTER][i] = .5 * (intermediate_freq_data[PN_CHANNEL_LEFT][i] + intermediate_freq_data[PN_CHANNEL_RIGHT][i]); } } static gboolean quit_timeout_func (gpointer data) { if (render_thread_finished) { pn_xmms_vp.disable_plugin (&pn_xmms_vp); quit_timeout = 0; return FALSE; } return TRUE; } static int render_func (void *data) { guint i; PnImage *image; guint last_time = 0, last_second = 0; gfloat fps = 0.0; guint this_time; SDL_Event event; while (! kill_render_thread) { /* Lock & copy the audio data */ SDL_mutexP (audio_data_mutex); for (i=0; i<3; i++) { memcpy (PN_AUDIO_DATA_PCM_DATA (audio_data, i), intermediate_pcm_data[i], 512 * sizeof (gfloat)); memcpy (PN_AUDIO_DATA_FREQ_DATA (audio_data, i), intermediate_freq_data[i], 256 * sizeof (gfloat)); } SDL_mutexV (audio_data_mutex); pn_audio_data_update (audio_data); /* Render the image */ SDL_mutexP (vis_mutex); image = pn_vis_render (vis, audio_data); SDL_mutexV (vis_mutex); /* Draw the image */ draw_image (image); /* Compute the FPS */ this_time = SDL_GetTicks (); fps = fps * .95 + (1000.0 / (gfloat) (this_time - last_time)) * .05; if (this_time > 2000 + last_second) { last_second = this_time; printf ("paranormal fps: %f\n", fps); } last_time = this_time; /* Handle window events */ while (SDL_PollEvent (&event)) { switch (event.type) { case SDL_QUIT: render_thread_finished = TRUE; return 0; case SDL_VIDEORESIZE: image_width = event.resize.w; image_height = event.resize.h; screen = SDL_SetVideoMode (image_width, image_height, 32, SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_RESIZABLE); printf ("changed to: w: %u, h: %u\n", image_width, image_height); pn_vis_set_image_size (vis, image_width, image_height); break; case SDL_KEYDOWN: switch (event.key.keysym.sym) { case SDLK_ESCAPE: render_thread_finished = TRUE; return 0; case SDLK_RETURN: if (event.key.keysym.mod & (KMOD_ALT | KMOD_META)) { /* Toggle fullscreen */ SDL_WM_ToggleFullScreen (screen); if (SDL_ShowCursor (SDL_QUERY) == SDL_ENABLE) SDL_ShowCursor (SDL_DISABLE); else SDL_ShowCursor (SDL_ENABLE); } break; case SDLK_BACKQUOTE: { char fname[20]; int i = 0; struct stat buf; do { sprintf (fname, "pnxmms_ss_%05u.bmp", i++); } while(!(stat(fname, &buf) != 0 && errno == ENOENT )); SDL_SaveBMP(screen, fname); } break; default: break; } break; } } /* don't lock the CPU :P */ g_usleep(10000); } return 0; } static void draw_image (PnImage *image) { guint width, height, src_stride, dest_stride; guint i; register PnColor *src; register Uint32 *dest; /* Lock the SDL surface */ SDL_LockSurface (screen); /* Get the dimentions */ width = pn_image_get_width (image); height = pn_image_get_height (image); src_stride = pn_image_get_pitch (image) >> 2; dest_stride = screen->pitch >> 2; src = pn_image_get_image_buffer (image); dest = (Uint32 *) screen->pixels; /* Copy the pixel data */ while (--height > 0) { for (i=0; i<width; i++) dest[i] = SDL_MapRGB (screen->format, src[i].red, src[i].green, src[i].blue); dest += dest_stride; src += src_stride; } /* Unlock the SDL surface */ SDL_UnlockSurface (screen); /* Draw it to the screen */ SDL_Flip (screen); } static void read_options (void) { ConfigDb *cfg; gint i; if (options_read == TRUE) return; cfg = bmp_cfg_db_open (); if (!cfg) return; if (bmp_cfg_db_get_int (cfg, "pnxmms", "image_width", &i)) image_width = i; if (bmp_cfg_db_get_int (cfg, "pnxmms", "image_height", &i)) image_height = i; bmp_cfg_db_get_string (cfg, "pnxmms", "preset", &preset); bmp_cfg_db_close (cfg); return; } static void write_options (void) { ConfigDb *cfg; cfg = bmp_cfg_db_open (); if (!cfg) fprintf (stderr, "PNXMMS: Unable to open XMMS config file!\n"); bmp_cfg_db_set_int (cfg, "pnxmms", "image_width", image_width); bmp_cfg_db_set_int (cfg, "pnxmms", "image_height", image_height); if (preset) bmp_cfg_db_set_string (cfg, "pnxmms", "preset", preset); bmp_cfg_db_close (cfg); } static void load_default_vis (void) { PnContainer *container; PnActuator *actuator; PnOption *option; /* Actuator List */ container = (PnContainer *) pn_actuator_list_new (); /* Scope */ actuator = (PnActuator *) pn_scope_new (); option = pn_actuator_get_option_by_name (actuator, "init_script"); pn_string_option_set_value (PN_STRING_OPTION (option), "samples = width/2;"); option = pn_actuator_get_option_by_name (actuator, "frame_script"); pn_string_option_set_value (PN_STRING_OPTION (option), "base = base + .04;\n" "red = abs (sin (.5 * pi + .1 * base));\n" "green = .5 * abs (sin (.5 * pi - .2 * base));\n" "blue = abs (sin (.5 * pi + .3 * base));"); option = pn_actuator_get_option_by_name (actuator, "sample_script"); pn_string_option_set_value (PN_STRING_OPTION (option), "x = 2 * iteration - 1;\n" "y = value;"); option = pn_actuator_get_option_by_name (actuator, "draw_method"); pn_list_option_set_index (PN_LIST_OPTION (option), 1); pn_container_add_actuator (container, actuator, PN_POSITION_TAIL); /* Distortion */ actuator = (PnActuator *) pn_distortion_new (); option = pn_actuator_get_option_by_name (actuator, "distortion_script"); pn_string_option_set_value (PN_STRING_OPTION (option), "intensity = .99 + .08 * r;\n" "r = .98 * atan (r);\n" "theta = theta + .01;"); option = pn_actuator_get_option_by_name (actuator, "polar_coords"); pn_boolean_option_set_value (PN_BOOLEAN_OPTION (option), TRUE); pn_container_add_actuator (container, actuator, PN_POSITION_TAIL); /* Add the actuator list to the vis */ pn_vis_set_root_actuator (vis, PN_ACTUATOR (container)); } static void apply_settings (void) { if (preset_changed) { preset_changed = FALSE; SDL_mutexP (vis_mutex); pn_vis_load_from_file (vis, preset); SDL_mutexV (vis_mutex); } write_options (); } static void destroy_config_dialog (GtkObject *user_data, gpointer data) { gtk_widget_destroy (GTK_WIDGET(config_dialog)); config_dialog = NULL; } static void apply_button_cb (GtkButton *button, gpointer data) { apply_settings (); } static void ok_button_cb (GtkButton *button, gpointer data) { apply_settings (); destroy_config_dialog (NULL, NULL); } static void cancel_button_cb (GtkButton *button, gpointer data) { destroy_config_dialog (NULL, NULL); } /* If selector != NULL, then it's 'OK', otherwise it's 'Cancel' */ static void load_preset_cb (GtkButton *button, GtkFileSelection *selector) { if (selector) { if (preset) g_free (preset); preset = g_strdup (gtk_file_selection_get_filename (selector)); gtk_label_set_text (GTK_LABEL (GTK_BIN (load_button)->child), preset); preset_changed = TRUE; } gtk_widget_set_sensitive (config_dialog, TRUE); } static void load_preset_button_cb (GtkButton *button, gpointer data) { GtkWidget *selector; selector = gtk_file_selection_new ("Load Preset"); gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (selector)->ok_button), "clicked", GTK_SIGNAL_FUNC (load_preset_cb), selector); gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (selector)->cancel_button), "clicked", GTK_SIGNAL_FUNC (load_preset_cb), NULL); gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (selector)->ok_button), "clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy), (gpointer) selector); gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (selector)->cancel_button), "clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy), (gpointer) selector); gtk_widget_set_sensitive (config_dialog, FALSE); gtk_widget_show (selector); } static void create_config_dialog (void) { GtkWidget *bbox, *button, *vbox, *frame, *table, *label; if (config_dialog != NULL) return; /* Create the dialog */ config_dialog = gtk_dialog_new (); gtk_window_set_title (GTK_WINDOW (config_dialog), PACKAGE " " VERSION " - Configuration"); gtk_widget_set_usize (config_dialog, 500, 300); gtk_container_border_width (GTK_CONTAINER (config_dialog), 8); gtk_signal_connect_object (GTK_OBJECT (config_dialog), "delete-event", GTK_SIGNAL_FUNC (destroy_config_dialog), NULL); /* OK / Cancel / Apply */ bbox = gtk_hbutton_box_new (); gtk_widget_show (bbox); gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END); gtk_button_box_set_spacing (GTK_BUTTON_BOX (bbox), 8); gtk_button_box_set_child_size (GTK_BUTTON_BOX (bbox), 64, 0); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (config_dialog)->action_area), bbox, FALSE, FALSE, 0); button = gtk_button_new_with_label ("OK"); gtk_widget_show (button); gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NORMAL); gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (ok_button_cb), NULL); gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0); button = gtk_button_new_with_label ("Cancel"); gtk_widget_show (button); gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NORMAL); gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (cancel_button_cb), NULL); gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0); button = gtk_button_new_with_label ("Apply"); gtk_widget_show (button); gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NORMAL); gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (apply_button_cb), NULL); gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0); /* The vertical box */ vbox = gtk_vbox_new (FALSE, 1); gtk_widget_show (vbox); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (config_dialog)->vbox), vbox, TRUE, TRUE, 0); /* General options */ frame = gtk_frame_new (NULL); gtk_widget_show (frame); gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0); gtk_frame_set_label (GTK_FRAME (frame), "General"); table = gtk_table_new (2, 1, TRUE); gtk_widget_show (table); gtk_container_add (GTK_CONTAINER (frame), table); label = gtk_label_new ("Preset File: "); gtk_widget_show (label); gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, GTK_FILL, 0, 3, 3); load_button = gtk_button_new_with_label (preset ? preset : "<default>"); gtk_widget_show (load_button); gtk_table_attach (GTK_TABLE (table), load_button, 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, 0, 3, 3); gtk_signal_connect (GTK_OBJECT (load_button), "clicked", GTK_SIGNAL_FUNC (load_preset_button_cb), NULL); /* Show it all */ gtk_widget_show (config_dialog); gtk_widget_grab_focus (config_dialog); }