Mercurial > audlegacy
changeset 522:60c744f652f4 trunk
[svn] amidi-plug (MIDI through ALSA seq) input plugin added, brand new and completely written from scratch :)
line wrap: on
line diff
--- a/Plugins/Input/Makefile.am Thu Jan 26 17:24:48 2006 -0800 +++ b/Plugins/Input/Makefile.am Thu Jan 26 18:43:59 2006 -0800 @@ -1,2 +1,2 @@ -ALL_PLUGINS = mpg123 aac modplug vorbis tonegen cdaudio sid wav flac console timidity musepack sexypsf adplug wma +ALL_PLUGINS = mpg123 aac modplug vorbis tonegen cdaudio sid wav flac console timidity musepack sexypsf adplug wma amidi-plug SUBDIRS = $(INPUT_PLUGINS)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/amidi-plug/Makefile.am Thu Jan 26 18:43:59 2006 -0800 @@ -0,0 +1,18 @@ +if ENABLE_AMIDIPLUG + +lib_LTLIBRARIES = libamidi-plug.la + +endif + +noinst_HEADERS = amidi-plug.h i_seq.h i_midi.h i_configure.h \ + i_fileinfo.h i_utils.h i_common.h + +libdir = $(plugindir)/$(INPUT_PLUGIN_DIR) + +libamidi_plug_la_LDFLAGS = $(PLUGIN_LDFLAGS) +libamidi_plug_la_LIBADD = $(GTK_LIBS) @ALSA_LIBS@ -lpthread +libamidi_plug_la_SOURCES = amidi-plug.c i_seq.c i_midi.c \ + i_configure.c i_utils.c i_fileinfo.c \ + amidi-plug.logo.xpm amidi-plug.midiicon.xpm + +INCLUDES = $(GTK_CFLAGS) @ALSA_CFLAGS@ -I$(top_builddir)/intl -I$(top_srcdir)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/amidi-plug/amidi-plug.c Thu Jan 26 18:43:59 2006 -0800 @@ -0,0 +1,687 @@ +/* +* +* Author: Giacomo Lozito <james@develia.org>, (C) 2005-2006 +* +* 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 +* +*/ + +#include "amidi-plug.h" + + +InputPlugin *get_iplugin_info(void) +{ + amidiplug_ip.description = g_strdup_printf(_("AMIDI-Plug %s (MIDI Player)"), AMIDIPLUG_VERSION); + return &amidiplug_ip; +} + + +static gint amidiplug_is_our_file( gchar * filename ) +{ +#ifdef MIDIFILE_PROBE_MAGICBYTES + FILE * fp; + gchar magic_bytes[4]; + + fp = fopen( filename , "rb" ); + fread( magic_bytes , 1 , 4 , fp ); + + if ( !strncmp( magic_bytes , "MThd" , 4 ) ) + { + fclose( fp ); + DEBUGMSG( "MIDI found, %s is a standard midi file\n" , filename ); + return TRUE; + } + + if ( !strncmp( magic_bytes , "RIFF" , 4 ) ) + { + /* skip the four bytes after RIFF, + then read the next four */ + fseek( fp , 4 , SEEK_CUR ); + fread( magic_bytes , 1 , 4 , fp ); + if ( !strncmp( magic_bytes , "RMID" , 4 ) ) + { + fclose( fp ); + DEBUGMSG( "MIDI found, %s is a riff midi file\n" , filename ); + return TRUE; + } + } + fclose( fp ); +#else + gchar * ext = strrchr( filename, '.' ); + /* check the filename extension */ + if ( ( ext ) && + (( !strcasecmp(ext,".mid") ) || ( !strcasecmp(ext,".midi") ) || + ( !strcasecmp(ext,".rmi") ) || ( !strcasecmp(ext,".rmid") )) ) + return TRUE; +#endif + return FALSE; +} + + +static void amidiplug_init( void ) +{ + gchar * alsaversion; + g_log_set_handler(NULL , G_LOG_LEVEL_WARNING , g_log_default_handler , NULL); + DEBUGMSG( "init, read configuration\n" ); + /* read configuration */ + alsaversion = (gchar *)snd_asoundlib_version(); /* get ALSA-lib version */ + i_configure_cfg_read( alsaversion ); + amidiplug_playing_status = AMIDIPLUG_STOP; +} + + +static void amidiplug_cleanup( void ) +{ + g_free( amidiplug_ip.description ); +} + + +static void amidiplug_configure( void ) +{ + if ( amidiplug_gui_prefs.config_win ) + { + return; + } + else + { + GSList * wports = NULL; + GSList * scards = NULL; + /* get an updated list of writable ALSA MIDI ports and ALSA-enabled sound cards*/ + DEBUGMSG( "get an updated list of writable ALSA MIDI ports\n" ); + wports = i_seq_port_get_list(); + DEBUGMSG( "get an updated list of ALSA-enabled sound cards\n" ); + scards = i_seq_card_get_list(); + /* display them in our nice config dialog */ + DEBUGMSG( "opening config window\n" ); + i_configure_gui( wports , scards ); + /* free the cards list and the ports list */ + i_seq_card_free_list( scards ); + i_seq_port_free_list( wports ); + } +} + + +static void amidiplug_aboutbox( void ) +{ + i_about_gui(); +} + + +static void amidiplug_file_info_box( gchar * filename ) +{ + i_fileinfo_gui( filename ); +} + + +static void amidiplug_stop( void ) +{ + DEBUGMSG( "STOP request at tick: %i\n" , midifile.playing_tick ); + pthread_mutex_lock( &amidiplug_playing_mutex ); + if (( amidiplug_playing_status == AMIDIPLUG_PLAY ) || + ( amidiplug_playing_status == AMIDIPLUG_STOP )) + { + amidiplug_playing_status = AMIDIPLUG_STOP; + pthread_mutex_unlock( &amidiplug_playing_mutex ); + pthread_join( amidiplug_play_thread , NULL ); + DEBUGMSG( "STOP activated (play thread joined)\n" ); + } + else if ( amidiplug_playing_status == AMIDIPLUG_PAUSE ) + { + amidiplug_playing_status = AMIDIPLUG_STOP; + DEBUGMSG( "STOP activated (from PAUSE to STOP)\n" ); + pthread_mutex_unlock( &amidiplug_playing_mutex ); + } + else /* AMIDIPLUG_ERR */ + { + DEBUGMSG( "STOP activated (in error handling, ok)\n" ); + pthread_mutex_unlock( &amidiplug_playing_mutex ); + } + /* kill the sequencer (while it has been already killed if we come from + pause, it's safe to do anyway since it checks for multiple calls */ + i_seq_off(); + /* free midi data (same as above) */ + i_midi_free( &midifile ); +} + + +static void amidiplug_pause( gshort paused ) +{ + if ( paused ) + { + DEBUGMSG( "PAUSE request at tick: %i\n" , midifile.playing_tick ); + pthread_mutex_lock( &amidiplug_playing_mutex ); + /* this cond is used to avoid race conditions */ + while ( amidiplug_playing_status != AMIDIPLUG_PLAY ) + pthread_cond_wait( &amidiplug_playing_cond , &amidiplug_playing_mutex ); + amidiplug_playing_status = AMIDIPLUG_PAUSE; + pthread_mutex_unlock( &amidiplug_playing_mutex ); + + pthread_join( amidiplug_play_thread , NULL ); + DEBUGMSG( "PAUSE activated (play thread joined)\n" , midifile.playing_tick ); + + /* kill the sequencer */ + i_seq_off(); + } + else + { + DEBUGMSG( "PAUSE deactivated, returning to tick %i\n" , midifile.playing_tick ); + /* revive the sequencer */ + i_seq_on( 0 , NULL ); + /* re-set initial tempo */ + i_midi_setget_tempo( &midifile ); + i_seq_queue_set_tempo( midifile.current_tempo , midifile.ppq ); + /* get back to the previous state */ + amidiplug_skipto( midifile.playing_tick ); + + pthread_mutex_lock( &amidiplug_playing_mutex ); + /* play play play! */ + DEBUGMSG( "PAUSE deactivated, starting play thread again\n" ); + pthread_create(&amidiplug_play_thread, NULL, amidiplug_play_loop, NULL); + /* this cond is used to avoid race conditions */ + while ( amidiplug_playing_status != AMIDIPLUG_PLAY ) + pthread_cond_wait( &amidiplug_playing_cond , &amidiplug_playing_mutex ); + pthread_mutex_unlock( &amidiplug_playing_mutex ); + } +} + + +static void amidiplug_seek( gint time ) +{ + DEBUGMSG( "SEEK requested (time %i), pausing song...\n" , time ); + pthread_mutex_lock( &amidiplug_playing_mutex ); + /* this cond is used to avoid race conditions */ + while ( amidiplug_playing_status != AMIDIPLUG_PLAY ) + pthread_cond_wait( &amidiplug_playing_cond , &amidiplug_playing_mutex ); + amidiplug_playing_status = AMIDIPLUG_PAUSE; + pthread_mutex_unlock( &amidiplug_playing_mutex ); + + pthread_join( amidiplug_play_thread , NULL ); + DEBUGMSG( "SEEK requested (time %i), song paused\n" , time ); + /* kill the sequencer */ + i_seq_off(); + /* revive the sequencer */ + i_seq_on( 0 , NULL ); + /* re-set initial tempo */ + i_midi_setget_tempo( &midifile ); + i_seq_queue_set_tempo( midifile.current_tempo , midifile.ppq ); + /* get back to the previous state */ + DEBUGMSG( "SEEK requested (time %i), moving to tick %i of %i\n" , + time , (gint)((time * 1000000) / midifile.avg_microsec_per_tick) , midifile.max_tick ); + midifile.playing_tick = (gint)((time * 1000000) / midifile.avg_microsec_per_tick); + amidiplug_skipto( midifile.playing_tick ); + /* play play play! */ + DEBUGMSG( "SEEK done, starting play thread again\n" ); + pthread_create(&amidiplug_play_thread, NULL, amidiplug_play_loop, NULL); +} + + +static gint amidiplug_get_time( void ) +{ + gint pt; + pthread_mutex_lock( &amidiplug_playing_mutex ); + if (( amidiplug_playing_status == AMIDIPLUG_PLAY ) || + ( amidiplug_playing_status == AMIDIPLUG_PAUSE )) + { + pthread_mutex_unlock( &amidiplug_playing_mutex ); + pthread_mutex_lock(&amidiplug_gettime_mutex); + pt = midifile.playing_tick; + pthread_mutex_unlock(&amidiplug_gettime_mutex); + return (gint)((pt * midifile.avg_microsec_per_tick) / 1000); + } + else if ( amidiplug_playing_status == AMIDIPLUG_STOP ) + { + pthread_mutex_unlock( &amidiplug_playing_mutex ); + DEBUGMSG( "GETTIME on stopped song, returning -1\n" , time ); + return -1; + } + else /* AMIDIPLUG_ERR */ + { + pthread_mutex_unlock( &amidiplug_playing_mutex ); + DEBUGMSG( "GETTIME on halted song (an error occurred?), returning -1 and stopping the player\n" , time ); + xmms_remote_stop(0); + return -1; + } +} + + +static void amidiplug_set_volume( gint l , gint r ) +{ + gchar mixer_card[10]; + snprintf( mixer_card , 8 , "hw:%i" , amidiplug_cfg.mixer_card_id ); + mixer_card[9] = '\0'; + /* set volume */ + i_seq_mixer_set_volume( l , r , mixer_card , amidiplug_cfg.mixer_control_name , + amidiplug_cfg.mixer_control_id ); +} + + +static void amidiplug_get_song_info( gchar * filename , gchar ** title , gint * length ) +{ + /* song title, get it from the filename */ + *title = G_PATH_GET_BASENAME(filename); + + /* sure, it's possible to calculate the length of a MIDI file anytime, + but the file must be entirely parsed to calculate it; this could lead + to performance loss, for now it's safer to calculate the length only + right before playing the file */ + *length = -1; + return; +} + + +static void amidiplug_play( gchar * filename ) +{ + gint port_count = 0; + DEBUGMSG( "PLAY requested, midifile init\n" ); + /* midifile init */ + i_midi_init( &midifile ); + + /* get the number of selected alsa ports */ + port_count = i_util_str_count( amidiplug_cfg.seq_writable_ports , ':' ); + if ( port_count < 1 ) + { + g_warning( "No ALSA ports selected\n" ); + amidiplug_playing_status = AMIDIPLUG_ERR; + return; + } + + DEBUGMSG( "PLAY requested, opening file: %s\n" , filename ); + midifile.file_pointer = fopen( filename , "rb" ); + if (!midifile.file_pointer) + { + g_warning( "Cannot open %s\n" , filename ); + amidiplug_playing_status = AMIDIPLUG_ERR; + return; + } + midifile.file_name = filename; + + switch( i_midi_file_read_id( &midifile ) ) + { + case MAKE_ID('R', 'I', 'F', 'F'): + { + DEBUGMSG( "PLAY requested, RIFF chunk found, processing...\n" ); + /* read riff chunk */ + if ( !i_midi_file_parse_riff( &midifile ) ) + WARNANDBREAKANDPLAYERR( "%s: invalid file format (riff parser)\n" , filename ); + + /* if that was read correctly, go ahead and read smf data */ + } + + case MAKE_ID('M', 'T', 'h', 'd'): + { + DEBUGMSG( "PLAY requested, MThd chunk found, processing...\n" ); + if ( !i_midi_file_parse_smf( &midifile , port_count ) ) + WARNANDBREAKANDPLAYERR( "%s: invalid file format (smf parser)\n" , filename ); + + if ( midifile.time_division < 1 ) + WARNANDBREAKANDPLAYERR( "%s: invalid time division (%i)\n" , filename , midifile.time_division ); + + DEBUGMSG( "PLAY requested, setting ppq and tempo...\n" ); + /* fill midifile.ppq and midifile.tempo using time_division */ + if ( !i_midi_setget_tempo( &midifile ) ) + WARNANDBREAKANDPLAYERR( "%s: invalid values while setting ppq and tempo\n" , filename ); + + DEBUGMSG( "PLAY requested, sequencer init\n" ); + /* sequencer on */ + if ( !i_seq_on( 1 , amidiplug_cfg.seq_writable_ports ) ) + WARNANDBREAKANDPLAYERR( "%s: ALSA problem, play aborted\n" , filename ); + + DEBUGMSG( "PLAY requested, setting sequencer queue tempo...\n" ); + /* set sequencer queue tempo using ppq and tempo (call only after i_midi_setget_tempo) */ + if ( !i_seq_queue_set_tempo( midifile.current_tempo , midifile.ppq ) ) + { + i_seq_off(); /* kill the sequencer */ + WARNANDBREAKANDPLAYERR( "%s: ALSA queue problem, play aborted\n" , filename ); + } + + /* fill midifile.length, keeping in count tempo-changes */ + i_midi_setget_length( &midifile ); + DEBUGMSG( "PLAY requested, song length calculated: %i msec\n" , (gint)(midifile.length / 1000) ); + + /* our length is in microseconds, but the player wants milliseconds */ + amidiplug_ip.set_info( G_PATH_GET_BASENAME(filename) , (gint)(midifile.length / 1000) , -1 , -1 , -1 ); + + /* play play play! */ + DEBUGMSG( "PLAY requested, starting play thread\n" ); + amidiplug_playing_status = AMIDIPLUG_PLAY; + pthread_create(&amidiplug_play_thread, NULL, amidiplug_play_loop, NULL); + break; + } + + default: + { + amidiplug_playing_status = AMIDIPLUG_ERR; + g_warning( "%s is not a Standard MIDI File\n" , filename ); + break; + } + } + + fclose( midifile.file_pointer ); + return; +} + + + +void * amidiplug_play_loop( void * arg ) +{ + snd_seq_event_t ev; + gint i; + gboolean rewind = FALSE; + + pthread_mutex_lock( &amidiplug_playing_mutex ); + if ( amidiplug_playing_status != AMIDIPLUG_PAUSE ) + { + DEBUGMSG( "PLAY thread, rewind tracks to their first event\n" ); + rewind = TRUE; + } + else + { + DEBUGMSG( "PLAY thread, do not rewind tracks to their first event (coming from a PAUSE status)\n" ); + amidiplug_playing_status = AMIDIPLUG_PLAY; + pthread_cond_signal( &amidiplug_playing_cond ); + } + pthread_mutex_unlock( &amidiplug_playing_mutex ); + + if ( rewind ) + { + /* initialize current position in each track */ + for (i = 0; i < midifile.num_tracks; ++i) + midifile.tracks[i].current_event = midifile.tracks[i].first_event; + snd_seq_start_queue(sc.seq, sc.queue, NULL); + } + + /* common settings for all our events */ + snd_seq_ev_clear(&ev); + ev.queue = sc.queue; + ev.source.port = 0; + ev.flags = SND_SEQ_TIME_STAMP_TICK; + + DEBUGMSG( "PLAY thread, start the play loop\n" ); + for (;;) + { + midievent_t * event = NULL; + midifile_track_t * event_track = NULL; + gint i, min_tick = midifile.max_tick + 1; + + /* search next event */ + for (i = 0; i < midifile.num_tracks; ++i) + { + midifile_track_t * track = &midifile.tracks[i]; + midievent_t * e2 = track->current_event; + if (( e2 ) && ( e2->tick < min_tick )) + { + min_tick = e2->tick; + event = e2; + event_track = track; + } + } + + /* check if the song has been stopped */ + pthread_mutex_lock( &amidiplug_playing_mutex ); + if ( amidiplug_playing_status != AMIDIPLUG_PLAY ) + { + DEBUGMSG( "PLAY thread, PAUSE or STOP requested, exiting from play loop\n" ); + event = NULL; + } + pthread_mutex_unlock( &amidiplug_playing_mutex ); + + if (!event) + break; /* end of song reached */ + + /* advance pointer to next event */ + event_track->current_event = event->next; + + /* output the event */ + ev.type = event->type; + ev.time.tick = event->tick - midifile.skip_offset; + ev.dest = sc.dest_port[event->port]; + + switch (ev.type) + { + case SND_SEQ_EVENT_NOTEON: + case SND_SEQ_EVENT_NOTEOFF: + case SND_SEQ_EVENT_KEYPRESS: + { + snd_seq_ev_set_fixed(&ev); + ev.data.note.channel = event->data.d[0]; + ev.data.note.note = event->data.d[1]; + ev.data.note.velocity = event->data.d[2]; + break; + } + case SND_SEQ_EVENT_CONTROLLER: + { + snd_seq_ev_set_fixed(&ev); + ev.data.control.channel = event->data.d[0]; + ev.data.control.param = event->data.d[1]; + ev.data.control.value = event->data.d[2]; + break; + } + case SND_SEQ_EVENT_PGMCHANGE: + case SND_SEQ_EVENT_CHANPRESS: + { + snd_seq_ev_set_fixed(&ev); + ev.data.control.channel = event->data.d[0]; + ev.data.control.value = event->data.d[1]; + break; + } + case SND_SEQ_EVENT_PITCHBEND: + { + snd_seq_ev_set_fixed(&ev); + ev.data.control.channel = event->data.d[0]; + ev.data.control.value = ((event->data.d[1]) | ((event->data.d[2]) << 7)) - 0x2000; + break; + } + case SND_SEQ_EVENT_SYSEX: + { + snd_seq_ev_set_variable(&ev, event->data.length, event->sysex); + break; + } + case SND_SEQ_EVENT_TEMPO: + { + snd_seq_ev_set_fixed(&ev); + ev.dest.client = SND_SEQ_CLIENT_SYSTEM; + ev.dest.port = SND_SEQ_PORT_SYSTEM_TIMER; + ev.data.queue.queue = sc.queue; + ev.data.queue.param.value = event->data.tempo; + DEBUGMSG( "PLAY thread, processing tempo event with value %i on tick %i\n" , + event->data.tempo , event->tick ); + pthread_mutex_lock(&amidiplug_gettime_mutex); + midifile.current_tempo = event->data.tempo; + pthread_mutex_unlock(&amidiplug_gettime_mutex); + break; + } + default: + { + DEBUGMSG( "PLAY thread, encountered invalid event type %i\n" , ev.type ); + break; + } + } + + pthread_mutex_lock(&amidiplug_gettime_mutex); + midifile.playing_tick = event->tick; + pthread_mutex_unlock(&amidiplug_gettime_mutex); + + snd_seq_event_output(sc.seq, &ev); + snd_seq_drain_output(sc.seq); + snd_seq_sync_output_queue(sc.seq); + } + + /* schedule queue stop at end of song */ + snd_seq_ev_set_fixed(&ev); + ev.type = SND_SEQ_EVENT_STOP; + ev.time.tick = midifile.max_tick - midifile.skip_offset; + ev.dest.client = SND_SEQ_CLIENT_SYSTEM; + ev.dest.port = SND_SEQ_PORT_SYSTEM_TIMER; + ev.data.queue.queue = sc.queue; + snd_seq_event_output(sc.seq, &ev); + snd_seq_drain_output(sc.seq); + /* snd_seq_sync_output_queue(sc.seq); */ + + pthread_mutex_lock( &amidiplug_playing_mutex ); + if ( amidiplug_playing_status != AMIDIPLUG_PAUSE ) + { + amidiplug_playing_status = AMIDIPLUG_STOP; + DEBUGMSG( "PLAY thread, song stopped/ended\n" ); + + } + pthread_mutex_unlock( &amidiplug_playing_mutex ); + + pthread_exit(NULL); +} + + +/* amidigplug_skipto: re-do all events that influence the playing of our + midi file; re-do them using a time-tick of 0, so they are processed + istantaneously and proceed this way until the playing_tick is reached; + also obtain the correct skip_offset from the playing_tick */ +void amidiplug_skipto( gint playing_tick ) +{ + snd_seq_event_t ev; + gint i; + + /* this check is always made, for safety*/ + if ( playing_tick >= midifile.max_tick ) + playing_tick = midifile.max_tick - 1; + + /* initialize current position in each track */ + for (i = 0; i < midifile.num_tracks; ++i) + midifile.tracks[i].current_event = midifile.tracks[i].first_event; + + /* common settings for all our events */ + snd_seq_ev_clear(&ev); + ev.queue = sc.queue; + ev.source.port = 0; + ev.flags = SND_SEQ_TIME_STAMP_TICK; + + snd_seq_start_queue(sc.seq, sc.queue, NULL); + + DEBUGMSG( "SKIPTO request, starting skipto loop\n" ); + for (;;) + { + midievent_t * event = NULL; + midifile_track_t * event_track = NULL; + gint i, min_tick = midifile.max_tick + 1; + + /* search next event */ + for (i = 0; i < midifile.num_tracks; ++i) + { + midifile_track_t * track = &midifile.tracks[i]; + midievent_t * e2 = track->current_event; + if (( e2 ) && ( e2->tick < min_tick )) + { + min_tick = e2->tick; + event = e2; + event_track = track; + } + } + + /* unlikely here... unless very strange MIDI files are played :) */ + if (!event) + { + DEBUGMSG( "SKIPTO request, reached the last event but not the requested tick (!)\n" ); + break; /* end of song reached */ + } + + /* reached the requested tick, job done */ + if ( event->tick >= playing_tick ) + { + DEBUGMSG( "SKIPTO request, reached the requested tick, exiting from skipto loop\n" ); + break; + } + + /* advance pointer to next event */ + event_track->current_event = event->next; + + /* output the event */ + ev.type = event->type; + ev.time.tick = event->tick; + ev.dest = sc.dest_port[event->port]; + + switch (ev.type) + { + /* do nothing for these + case SND_SEQ_EVENT_NOTEON: + case SND_SEQ_EVENT_NOTEOFF: + case SND_SEQ_EVENT_KEYPRESS: + { + break; + } */ + case SND_SEQ_EVENT_CONTROLLER: + { + snd_seq_ev_set_fixed(&ev); + ev.data.control.channel = event->data.d[0]; + ev.data.control.param = event->data.d[1]; + ev.data.control.value = event->data.d[2]; + ev.time.tick = 0; + snd_seq_event_output(sc.seq, &ev); + snd_seq_drain_output(sc.seq); + snd_seq_sync_output_queue(sc.seq); + break; + } + case SND_SEQ_EVENT_PGMCHANGE: + case SND_SEQ_EVENT_CHANPRESS: + { + snd_seq_ev_set_fixed(&ev); + ev.data.control.channel = event->data.d[0]; + ev.data.control.value = event->data.d[1]; + ev.time.tick = 0; + snd_seq_event_output(sc.seq, &ev); + snd_seq_drain_output(sc.seq); + snd_seq_sync_output_queue(sc.seq); + break; + } + case SND_SEQ_EVENT_PITCHBEND: + { + snd_seq_ev_set_fixed(&ev); + ev.data.control.channel = event->data.d[0]; + ev.data.control.value = ((event->data.d[1]) | ((event->data.d[2]) << 7)) - 0x2000; + ev.time.tick = 0; + snd_seq_event_output(sc.seq, &ev); + snd_seq_drain_output(sc.seq); + snd_seq_sync_output_queue(sc.seq); + break; + } + case SND_SEQ_EVENT_SYSEX: + { + snd_seq_ev_set_variable(&ev, event->data.length, event->sysex); + ev.time.tick = 0; + snd_seq_event_output(sc.seq, &ev); + snd_seq_drain_output(sc.seq); + snd_seq_sync_output_queue(sc.seq); + break; + } + case SND_SEQ_EVENT_TEMPO: + { + snd_seq_ev_set_fixed(&ev); + ev.dest.client = SND_SEQ_CLIENT_SYSTEM; + ev.dest.port = SND_SEQ_PORT_SYSTEM_TIMER; + ev.data.queue.queue = sc.queue; + ev.data.queue.param.value = event->data.tempo; + pthread_mutex_lock(&amidiplug_gettime_mutex); + midifile.current_tempo = event->data.tempo; + pthread_mutex_unlock(&amidiplug_gettime_mutex); + ev.time.tick = 0; + snd_seq_event_output(sc.seq, &ev); + snd_seq_drain_output(sc.seq); + snd_seq_sync_output_queue(sc.seq); + break; + } + } + } + + midifile.skip_offset = playing_tick; + + return; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/amidi-plug/amidi-plug.h Thu Jan 26 18:43:59 2006 -0800 @@ -0,0 +1,115 @@ +/* +* +* Author: Giacomo Lozito <james@develia.org>, (C) 2005-2006 +* +* 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 +* +*/ + +#ifndef _I_AMIDIPLUG_H +#define _I_AMIDIPLUG_H 1 + +#define AMIDIPLUG_STOP 0 +#define AMIDIPLUG_PLAY 1 +#define AMIDIPLUG_PAUSE 2 +#define AMIDIPLUG_ERR 3 + +#include "i_common.h" +#include <audacious/plugin.h> +#include <audacious/beepctrl.h> +#include <pthread.h> +#include "i_configure.h" +#include "i_seq.h" +#include "i_midi.h" +#include "i_fileinfo.h" +#include "i_utils.h" + + +/* if this is defined, possible midi files are + checked by looking at their first (magic) bytes + instead of just reading the file extension */ +#define MIDIFILE_PROBE_MAGICBYTES 1 + + +static pthread_t amidiplug_play_thread; +static pthread_mutex_t amidiplug_gettime_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t amidiplug_playing_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t amidiplug_playing_cond = PTHREAD_COND_INITIALIZER; + +gint amidiplug_playing_status = AMIDIPLUG_STOP; + +midifile_t midifile; +sequencer_client_t sc = +{ + NULL, /* seq */ + 0, /* client_port */ + 0, /* queue */ + NULL, /* dest_port */ + 0 /* dest_port_num */ +}; + +amidiplug_cfg_t amidiplug_cfg = +{ + NULL, /* seq_writable_ports */ + 0, /* mixer_card_id */ + NULL, /* mixer_control_name */ + 0 /* mixer_control_id */ +}; + +void * amidiplug_play_loop( void * ); +void amidiplug_skipto( gint ); +static void amidiplug_init( void ); +static void amidiplug_cleanup( void ); +static void amidiplug_aboutbox( void ); +static void amidiplug_configure( void ); +static gint amidiplug_is_our_file( gchar * ); +static void amidiplug_play( gchar * ); +static void amidiplug_stop( void ); +static void amidiplug_pause( gshort ); +static void amidiplug_seek( gint ); +static gint amidiplug_get_time( void ); +static void amidiplug_set_volume( gint , gint ); +static void amidiplug_get_song_info( gchar * , gchar ** , gint * ); +static void amidiplug_file_info_box( gchar * ); + +InputPlugin amidiplug_ip = +{ + NULL, /* handle */ + NULL, /* filename */ + NULL, /* description */ + amidiplug_init, /* init */ + amidiplug_aboutbox, /* aboutbox */ + amidiplug_configure, /* configure */ + amidiplug_is_our_file, /* is_our_file */ + NULL, /* scan_dir */ + amidiplug_play, /* play_file */ + amidiplug_stop, /* stop */ + amidiplug_pause, /* pause */ + amidiplug_seek, /* seek */ + NULL, /* set_eq */ + amidiplug_get_time, /* get_time */ + NULL, /* get_volume */ + amidiplug_set_volume, /* set_volume */ + amidiplug_cleanup, /* cleanup */ + NULL, /* get_vis_type */ + NULL, /* add_vis_pcm */ + NULL, /* set_info */ + NULL, /* set_info_text */ + amidiplug_get_song_info, /* get_song_info */ + amidiplug_file_info_box, /* file_info_box */ + NULL /* output */ +}; + +#endif /* !_I_AMIDIPLUG_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/amidi-plug/amidi-plug.logo.xpm Thu Jan 26 18:43:59 2006 -0800 @@ -0,0 +1,743 @@ +/* XPM */ +static char * amidiplug_xpm_logo[] = { +"398 123 617 2", +" c #FFFFFF", +". c #FCFCFC", +"+ c #FAFAFA", +"@ c #F9F9F9", +"# c #F8F8F8", +"$ c #F7F7F7", +"% c #F5F5F5", +"& c #F4F4F4", +"* c #F3F3F3", +"= c #F1F1F1", +"- c #EFEFEF", +"; c #EEEEEE", +"> c #F0F0F0", +", c #EDEDED", +"' c #EBEBEB", +") c #EAEAEA", +"! c #E9E9E9", +"~ c #E8E8E8", +"{ c #E3E3E3", +"] c #E2E2E2", +"^ c #E0E0E0", +"/ c #DEDEDE", +"( c #E4E4E4", +"_ c #DADADA", +": c #5C5C5C", +"< c #4B4B4B", +"[ c #4A4A4A", +"} c #464646", +"| c #454545", +"1 c #414141", +"2 c #404040", +"3 c #3C3C3C", +"4 c #383838", +"5 c #373737", +"6 c #393939", +"7 c #3A3A3A", +"8 c #3B3B3B", +"9 c #363636", +"0 c #3D3D3D", +"a c #3E3E3E", +"b c #3F3F3F", +"c c #424242", +"d c #434343", +"e c #444444", +"f c #474747", +"g c #484848", +"h c #494949", +"i c #4C4C4C", +"j c #4D4D4D", +"k c #4E4E4E", +"l c #343434", +"m c #333333", +"n c #323232", +"o c #313131", +"p c #303030", +"q c #2F2F2F", +"r c #2E2E2E", +"s c #2D2D2D", +"t c #2C2C2C", +"u c #2B2B2B", +"v c #2A2A2A", +"w c #292929", +"x c #282828", +"y c #272727", +"z c #262626", +"A c #252525", +"B c #1E1E1E", +"C c #1C1C1C", +"D c #1B1B1B", +"E c #1A1A1A", +"F c #181818", +"G c #161616", +"H c #202020", +"I c #A0A0A0", +"J c #FEFEFE", +"K c #747474", +"L c #000000", +"M c #010101", +"N c #020202", +"O c #030303", +"P c #040404", +"Q c #050505", +"R c #060606", +"S c #070707", +"T c #080808", +"U c #090909", +"V c #0A0A0A", +"W c #0C0C0C", +"X c #0D0D0D", +"Y c #0E0E0E", +"Z c #0F0F0F", +"` c #101010", +" . c #111111", +".. c #121212", +"+. c #131313", +"@. c #141414", +"#. c #151515", +"$. c #171717", +"%. c #191919", +"&. c #1D1D1D", +"*. c #1F1F1F", +"=. c #DFDFDF", +"-. c #232323", +";. c #252523", +">. c #2B2B28", +",. c #2C2C29", +"'. c #2C2C2A", +"). c #2D2D2A", +"!. c #2D2D2B", +"~. c #2E2E2B", +"{. c #2E2E2C", +"]. c #2F2F2C", +"^. c #30302D", +"/. c #242423", +"(. c #272723", +"_. c #272724", +":. c #282824", +"<. c #292925", +"[. c #292926", +"}. c #2A2A26", +"|. c #2D2D28", +"1. c #2E2E2A", +"2. c #2F2F2A", +"3. c #30302B", +"4. c #2E302F", +"5. c #2E3131", +"6. c #303333", +"7. c #313434", +"8. c #303434", +"9. c #2F312F", +"0. c #2E2E29", +"a. c #2C2C28", +"b. c #2C2C27", +"c. c #2B2B26", +"d. c #2C2C26", +"e. c #2E2E28", +"f. c #2E2E27", +"g. c #2D2D27", +"h. c #1E1E1B", +"i. c #282825", +"j. c #33332F", +"k. c #32322F", +"l. c #32322E", +"m. c #31312E", +"n. c #30302C", +"o. c #242422", +"p. c #A4A4A4", +"q. c #868686", +"r. c #0B0B0B", +"s. c #171716", +"t. c #A2A295", +"u. c #BEBEAE", +"v. c #BEBEAF", +"w. c #BEBEB0", +"x. c #BFBFB0", +"y. c #C0C0B0", +"z. c #C0C0B2", +"A. c #C1C1B2", +"B. c #C2C2B2", +"C. c #7E7E74", +"D. c #5F5F4F", +"E. c #B9B998", +"F. c #BCBC99", +"G. c #BCBC9A", +"H. c #BDBD9A", +"I. c #BEBE9A", +"J. c #BEBE9B", +"K. c #C1C19E", +"L. c #C2C29E", +"M. c #C3C39F", +"N. c #9EAA9F", +"O. c #92A4A4", +"P. c #92A5A5", +"Q. c #93A6A6", +"R. c #94A6A6", +"S. c #A8B3A3", +"T. c #C4C4A0", +"U. c #C5C5A0", +"V. c #C6C6A1", +"W. c #C6C6A0", +"X. c #C7C7A1", +"Y. c #C9C9A2", +"Z. c #7C7C65", +"`. c #949487", +" + c #CDCDBC", +".+ c #CDCDBB", +"++ c #A3A394", +"@+ c #0B0B0A", +"#+ c #191918", +"$+ c #8B8B80", +"%+ c #9E9E92", +"&+ c #9F9F92", +"*+ c #A0A093", +"=+ c #A0A094", +"-+ c #A1A194", +";+ c #67675F", +">+ c #686857", +",+ c #D2D2AB", +"'+ c #D3D3AC", +")+ c #D4D4AD", +"!+ c #D5D5AD", +"~+ c #D5D5AE", +"{+ c #D6D6AE", +"]+ c #D6D6AF", +"^+ c #D7D7AF", +"/+ c #AEB6A0", +"(+ c #9AA69A", +"_+ c #9AA698", +":+ c #9AA699", +"<+ c #B5BCA3", +"[+ c #DBDBB1", +"}+ c #DADAB1", +"|+ c #DBDBB0", +"1+ c #DADAB0", +"2+ c #969679", +"3+ c #6C6C64", +"4+ c #9E9E91", +"5+ c #9E9E90", +"6+ c #99998C", +"7+ c #98988B", +"8+ c #848478", +"9+ c #111110", +"0+ c #B0B0B0", +"a+ c #959595", +"b+ c #0C0C0E", +"c+ c #0E0E10", +"d+ c #131314", +"e+ c #696957", +"f+ c #D8D8B0", +"g+ c #D6D6AD", +"h+ c #D7D7AE", +"i+ c #D8D8AF", +"j+ c #DBDBB2", +"k+ c #DCDCB2", +"l+ c #DCDCB1", +"m+ c #A8A888", +"n+ c #0F0F11", +"o+ c #0E0E0F", +"p+ c #0A0A0C", +"q+ c #09090A", +"r+ c #080809", +"s+ c #070708", +"t+ c #060608", +"u+ c #0B0B0C", +"v+ c #181817", +"w+ c #1C1C1B", +"x+ c #6F6F5C", +"y+ c #D7D7B0", +"z+ c #D9D9B0", +"A+ c #D9D9B1", +"B+ c #DADAB2", +"C+ c #B9B995", +"D+ c #161615", +"E+ c #161614", +"F+ c #141413", +"G+ c #C0C0C0", +"H+ c #A5A5A5", +"I+ c #A4A497", +"J+ c #AAAA9C", +"K+ c #AAAA9D", +"L+ c #ABAB9D", +"M+ c #ACAC9E", +"N+ c #ACAC9F", +"O+ c #ADAD9F", +"P+ c #AEAEA0", +"Q+ c #5B5B54", +"R+ c #777762", +"S+ c #DCDCB3", +"T+ c #DDDDB3", +"U+ c #DDDDB2", +"V+ c #C5C59F", +"W+ c #4F4F46", +"X+ c #B6B6A6", +"Y+ c #BABAAA", +"Z+ c #B9B9AA", +"`+ c #B8B8A8", +" @ c #4F4F49", +".@ c #595959", +"+@ c #3C3C39", +"@@ c #BCBCAD", +"#@ c #BDBDAE", +"$@ c #C0C0B1", +"%@ c #5B5B55", +"&@ c #808069", +"*@ c #DBDBB3", +"=@ c #DCDCB4", +"-@ c #DDDDB4", +";@ c #DEDEB4", +">@ c #CECEA6", +",@ c #57574C", +"'@ c #BDBDAC", +")@ c #C4C4B3", +"!@ c #C3C3B2", +"~@ c #63635B", +"{@ c #CBCBCB", +"]@ c #ABABAB", +"^@ c #282826", +"/@ c #292927", +"(@ c #2A2A28", +"_@ c #2B2B29", +":@ c #84846C", +"<@ c #D6D6B0", +"[@ c #DEDEB3", +"}@ c #DEDEB2", +"|@ c #D5D5AC", +"1@ c #3F3F36", +"2@ c #232321", +"3@ c #222220", +"4@ c #212120", +"5@ c #21211F", +"6@ c #20201E", +"7@ c #1F1F1D", +"8@ c #6B6B6B", +"9@ c #FBFBFB", +"0@ c #515144", +"a@ c #80806A", +"b@ c #81816A", +"c@ c #81816B", +"d@ c #82826B", +"e@ c #82826C", +"f@ c #83836C", +"g@ c #84846D", +"h@ c #84846E", +"i@ c #85856E", +"j@ c #86866E", +"k@ c #85856D", +"l@ c #7E7E67", +"m@ c #7E7E66", +"n@ c #7D7D66", +"o@ c #7A7A63", +"p@ c #D3D3D3", +"q@ c #BCBCBC", +"r@ c #212121", +"s@ c #222222", +"t@ c #242424", +"u@ c #525252", +"v@ c #D4D4D4", +"w@ c #AFAFAF", +"x@ c #636363", +"y@ c #D6D6D6", +"z@ c #353535", +"A@ c #505050", +"B@ c #C3C3C3", +"C@ c #818181", +"D@ c #4F4F4F", +"E@ c #565656", +"F@ c #585858", +"G@ c #5D5D5D", +"H@ c #5E5E5E", +"I@ c #5F5F5F", +"J@ c #606060", +"K@ c #646464", +"L@ c #676767", +"M@ c #666666", +"N@ c #686868", +"O@ c #6A6A6A", +"P@ c #656565", +"Q@ c #6C6C6C", +"R@ c #707070", +"S@ c #616161", +"T@ c #717171", +"U@ c #727272", +"V@ c #6E6E6E", +"W@ c #737373", +"X@ c #7A7A7A", +"Y@ c #757575", +"Z@ c #777777", +"`@ c #797979", +" # c #535353", +".# c #7B7B7B", +"+# c #767676", +"@# c #6D6D6D", +"## c #7E7E7E", +"$# c #575757", +"%# c #515151", +"&# c #626262", +"*# c #7C7C7C", +"=# c #838383", +"-# c #848484", +";# c #858585", +"># c #888888", +",# c #5A5A5A", +"'# c #7D7D7D", +")# c #8C8C8C", +"!# c #8D8D8D", +"~# c #909090", +"{# c #919191", +"]# c #929292", +"^# c #939393", +"/# c #949494", +"(# c #898989", +"_# c #969696", +":# c #979797", +"<# c #555555", +"[# c #989898", +"}# c #828282", +"|# c #8E8E8E", +"1# c #8B8B8B", +"2# c #8F8F8F", +"3# c #545454", +"4# c #787878", +"5# c #878787", +"6# c #999999", +"7# c #8A8A8A", +"8# c #ECECEC", +"9# c #7F7F7F", +"0# c #5B5B5B", +"a# c #6F6F6F", +"b# c #696969", +"c# c #9A9A9A", +"d# c #FDFDFD", +"e# c #AAAAAA", +"f# c #808080", +"g# c #9B9B9B", +"h# c #9C9C9C", +"i# c #C1C1C1", +"j# c #F2F2F2", +"k# c #CCCCCC", +"l# c #9D9D9D", +"m# c #E5E5E5", +"n# c #9E9E9E", +"o# c #F6F6F6", +"p# c #C8C8C8", +"q# c #9F9F9F", +"r# c #BFBFBF", +"s# c #A1A1A1", +"t# c #BEBEBE", +"u# c #DDDDDD", +"v# c #BABABA", +"w# c #A2A2A2", +"x# c #DCDCDC", +"y# c #A3A3A3", +"z# c #A6A6A6", +"A# c #ACACAC", +"B# c #ADADAD", +"C# c #AEAEAE", +"D# c #B1B1B1", +"E# c #B2B2B2", +"F# c #B4B4B4", +"G# c #B8B8B8", +"H# c #B9B9B9", +"I# c #BBBBBB", +"J# c #BDBDBD", +"K# c #C6C6C6", +"L# c #C7C7C7", +"M# c #CACACA", +"N# c #CECECE", +"O# c #D2D2D2", +"P# c #D8D8D8", +"Q# c #D9D9D9", +"R# c #D7D7D7", +"S# c #DBDBDB", +"T# c #A8A8A8", +"U# c #D1D1D1", +"V# c #D0D0D0", +"W# c #CFCFCF", +"X# c #C9C9C9", +"Y# c #B7B7B7", +"Z# c #C5C5C5", +"`# c #C4C4C4", +" $ c #B6B6B6", +".$ c #B5B5B5", +"+$ c #B3B3B3", +"@$ c #A7A7A7", +"#$ c #A9A9A9", +"$$ c #C2C2C2", +"%$ c #D5D5D5", +"&$ c #CDCDCD", +"*$ c #E6E6E6", +"=$ c #E7E7E7", +"-$ c #E1E1E1", +";$ c #8A8989", +">$ c #6D6B6B", +",$ c #646262", +"'$ c #A4A3A3", +")$ c #AEADAD", +"!$ c #D4D3D3", +"~$ c #818080", +"{$ c #969595", +"]$ c #A5A4A4", +"^$ c #8A8888", +"/$ c #838181", +"($ c #727070", +"_$ c #817F7F", +":$ c #858484", +"<$ c #868484", +"[$ c #777575", +"}$ c #6E6C6C", +"|$ c #888686", +"1$ c #BFBEBE", +"2$ c #898888", +"3$ c #797878", +"4$ c #706E6E", +"5$ c #9F9E9E", +"6$ c #7A7878", +"7$ c #DFDEDE", +"8$ c #656363", +"9$ c #8D8B8B", +"0$ c #747373", +"a$ c #666464", +"b$ c #C6C5C5", +"c$ c #EAE9E9", +"d$ c #999898", +"e$ c #BDBCBC", +"f$ c #939292", +"g$ c #CAC9C9", +"h$ c #9A9999", +"i$ c #7E7D7D", +"j$ c #6C6A6A", +"k$ c #686666", +"l$ c #8C8B8B", +"m$ c #6F6D6D", +"n$ c #D8D7D7", +"o$ c #7B7979", +"p$ c #8E8D8D", +"q$ c #AAA9A9", +"r$ c #9E9D9D", +"s$ c #AFAEAE", +"t$ c #8B8A8A", +"u$ c #7E7C7C", +"v$ c #959494", +"w$ c #919090", +"x$ c #8F8E8E", +"y$ c #6B6969", +"z$ c #767575", +"A$ c #929191", +"B$ c #7C7B7B", +"C$ c #6F6E6E", +"D$ c #949393", +"E$ c #737171", +"F$ c #828181", +"G$ c #B7B6B6", +"H$ c #A9A8A8", +"I$ c #939191", +"J$ c #B2B1B1", +"K$ c #B5B4B4", +"L$ c #FAF9F9", +"M$ c #ABA9A9", +"N$ c #7F7D7D", +"O$ c #BEBDBD", +"P$ c #878585", +"Q$ c #747272", +"R$ c #D1D0D0", +"S$ c #A6A4A4", +"T$ c #9B9999", +"U$ c #C1C0C0", +"V$ c #BCBBBB", +"W$ c #DAD9D9", +"X$ c #C0BFBF", +"Y$ c #B1B0B0", +"Z$ c #969494", +"`$ c #908F8F", +" % c #ABAAAA", +".% c #9C9B9B", +"+% c #D7D6D6", +"@% c #DEDDDD", +"#% c #C7C6C6", +"$% c #A6A5A5", +"%% c #807F7F", +"&% c #7C7A7A", +"*% c #CDCCCC", +"=% c #CFCECE", +"-% c #676565", +";% c #9A9898", +">% c #716F6F", +",% c #696767", +"'% c #797777", +")% c #C5C4C4", +"!% c #B9B8B8", +"~% c #706F6F", +"{% c #727171", +"]% c #A1A0A0", +"^% c #6A6868", +"/% c #7D7B7B", +"(% c #8D8C8C", +"_% c #B3B2B2", +":% c #BAB9B9", +"<% c #CBCACA", +"[% c #696868", +"}% c #717070", +"|% c #9D9B9B", +"1% c #7A7979", +"2% c #C3C2C2", +"3% c #ECEBEB", +"4% c #EFEEEE", +"5% c #8E8C8C", +"6% c #767474", +"7% c #ADACAC", +"8% c #989696", +"9% c #B4B3B3", +"0% c #ACABAB", +"a% c #757373", +"b% c #C4C3C3", +"c% c #807E7E", +"d% c #787676", +"e% c #A7A6A6", +"f% c #8F8D8D", +"g% c #BBBABA", +"h% c #908E8E", +"i% c #D0CFCF", +"j% c #7D7C7C", +"k% c #838282", +"l% c #9D9C9C", +"m% c #868585", +"n% c #9B9A9A", +"o% c #8C8A8A", +"p% c #A3A2A2", +"q% c #C8C7C7", +"r% c #DBDADA", +"s% c #9E9C9C", +"t% c #E1E0E0", +"u% c #848383", +"v% c #888787", +"w% c #858383", +"x% c #848282", +"y% c #757474", +"z% c #A09F9F", +" ", +" ", +" ", +" ", +" ", +" ", +" . + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @ # # # # # # # # # # # # # # # # $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % & * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * = = = = = = = = = = = = = - ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; - - - - - - - - - - - - - > > > > > > ; , , , ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; , ' ' ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ~ ~ ~ ~ ~ ~ { ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ^ / / / / / ( # ", +" _ : < [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ } } } } } } } } } } } } } } } } | 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 5 5 5 5 5 5 4 4 4 4 4 4 4 4 4 6 6 6 6 7 7 7 7 7 7 8 8 3 3 3 4 4 4 4 6 6 6 6 7 7 7 7 7 4 9 9 9 9 9 5 5 4 4 4 4 4 4 4 6 7 7 7 7 8 8 3 3 3 0 0 a a b 2 2 1 1 c c d e e | } } | e e } } } f g g h [ [ [ < i i i i i j j j k k k j j j j j j i i i < < [ [ h g g f e c c 1 2 b b a 0 3 8 7 7 4 4 5 9 9 l l m n n o p p q r r s s t t u v v w x x x y y z A B C C C C C C C C D D D E E E E E E E E F G G G G G H I J ", +" . K L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L M M M M N N N O O P P Q R R S T U V W W X Y Y Z ` .....+.@.#.G G $.F F %.E D D C C &.&.B B B B B *.*.*.*.*.*.*.B B B B &.&.C C D D E E F F F G G #.@.@.+... .` ` Z Y Y X W W V U T T S R R Q P P P O N N N N N N N N N N M M M M M M M M M M M M M L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L m ' ", +" =.-.L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L M M M M M N N N O P P Q Q R S T U V W X X V ;.>.,.'.).!.~.{.].^./.E (._.:.:.<.[.}.|.1.2.2.2.3.3.4.5.5.6.7.8.8.8.8.8.9.2.2.1.1.0.0.|.a.b.b.c.d.e.f.g.g.h.i.j.k.l.l.m.^.n.n.].o.R T S R Q Q P O O N N N M M M M M L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L O p.J ", +" J q.L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L M M M M M N N O O P P Q R R S T U r.W X X Y s.t.u.v.w.x.y.y.z.A.B.C.D.E.F.G.H.I.J.J.K.L.L.M.M.M.M.N.O.O.P.Q.Q.R.R.R.R.S.T.T.U.V.W.W.W.W.W.W.W.X.Y.Y.Y.Y.Z.`. + + + +.+.+.+.+.+++@+U T S R Q Q P O O N N N M M M M L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L a > ", +" ] x L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L M M M M N N N O O P P Q R S T U V W W X Y Y #+$+%+%+&+&+*+=+-+-+t.;+>+,+,+'+'+)+)+!+~+{+{+]+^+^+^+/+(+_+_+:+(+(+(+(+(+<+[+}+}+[+[+[+[+[+[+[+[+|+|+|+1+|+2+3+%+%+%+4+5+5+5+6+7+8+9+V T T R R Q P P O O N N N M M M M L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L T 0+ ", +" J a+L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L M M M M M N N N O P P Q R R S T V V W X X Y Z Y ` b+c+` ...d+@.#.G F e+,+'+'+)+)+~+~+{+]+^+^+f+f+f+{+!+g+{+{+{+h+h+h+h+i+j+j+j+k+k+k+k+k+k+l+l+[+[+[+[+|+m+n+` o+b+p+q+r+r+T s+t+U V U T S R Q P P O O N N N M M M M L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L k % ", +" ) o L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L M M M M N N N O O P P Q R R T T V r.W X Y Y Z u+@.@.@.#.G s.v+F %.w+E x+'+'+)+!+~+{+{+]+^+y+f+f+z+A+A+}+B+B+B+j+j+j+k+k+k+k+k+k+k+k+k+k+k+k+k+k+k+k+l+l+l+C+v+E F v+s.s.D+E+@.F+D+@+V V T S R R Q P P O N N N M M M M M L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L W G+ ", +" H+L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L M M M M N N N O O P P Q R S T U V W W X Y Z ` ,.I+J+K+L+M+M+N+O+P+P+Q+R+'+)+!+~+{+]+^+y+f+f+f+A+A+B+B+B+j+j+j+S+S+S+S+S+S+S+S+S+T+T+T+T+T+U+U+k+k+k+k+k+k+V+W+X+Y+Y+Y+Y+Y+Y+Y+Z+`+ @r.V T T S R Q P P O O N N N M M M M L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L .@$ ", +" - 8 L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L M M M M N N N O O P P Q R R S T V V W X Y Y Z ` +@`+@@#@#@u.v.x.y.$@y.%@&@)+!+~+{+]+^+y+f+f+A+A+B+B+B+j+j+*@S+S+S+=@=@-@-@-@-@-@-@-@-@;@T+T+T+T+T+T+U+U+U+U+>@,@'@)@)@!@!@!@!@!@!@!@~@W V U T S R Q P P O O N N N M M M M L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L ` {@ ", +" ]@Q L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L M M M M N N N O O P P Q R S T U V r.W X Y Y Z ` #.^@^@^@/@(@(@_@'.'.{.*.:@{+{+{+<@f+f+f+A+B+B+B+B+j+S+=@=@=@=@-@;@;@;@;@;@;@;@;@;@;@;@;@;@;@;@;@;@;@;@;@[@}@|@1@o.2@2@3@4@5@6@6@7@7@9+W V V T S R R Q P P O N N N N M M M M L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L 8@9@ ", +" & [ L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L M M M M M N N N O O P P Q R S T U V W W X Y Z ` ` ....+.@.#.G G F F %.E D 0@a@a@a@b@c@d@e@e@f@g@g@h@h@h@i@i@i@i@j@j@j@j@j@j@j@j@j@j@j@j@i@i@k@g@:@&@l@l@l@m@n@o@<.G @.@.+... .` Z Y Y X W r.V T T R R Q P P O O N N N M M M M L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L F p@ ", +" q@V L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L M M M M N N N O O P P Q R R S T V r.W X Y Y Z ` .....+.@.#.G $.F %.E E D C &.B B *.H r@r@s@s@-.-.t@t@t@A A A A A A A A t@t@t@-.-.s@s@r@H H *.B B &.C D E %.F F G G #.@.+... .` ` Z Y X W W V U T S R Q Q P O O N N N M M M M M L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L K 9@ ", +" % u@L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L M M M M N N N M M M N P R S T U U Q Q Q R T Z ` ...+.Z V V r.r.#.%.E D C C B B *.H H r@s@s@-.-.G . ...#.t@A A A A r@.... .` D -.-.s@s@r@H H *.B &.C C E E %.$.W T T T V .... .` Z V P P O O S T S R R P N M M L L N N M M M M L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L D v@ ", +" J w@r.L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L M M M M N N M L L L L O Q R S T S L L L L O Y Z ` ` .V L L L L ..$.F F %.E D D C C &.B B *.H *.r.N N N T H s@s@s@r@D N N N N +.H *.B B &.&.C C D E E F F $.G @.P L L L N ` ` ` ` Y R L L L L P V U T T P L L L L L P Q Q P P P P P P P P P P P P N L L L L L N P P P P L L L L L L O O O O O O O O O O O O N N O M L L L L L M M L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L x@& ", +" y@A L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L M L L L L L N N N N N M L L M M O P Q R R R R S T T T T T U T R O N N N P W Y Y Y T Q O O O N U ..+.+.@.@.@.G G $.$.F %.E E F O L M L L M C -.t@A G L L L L L Z r q p p W L L L L L w 6 7 7 8 3 3 a a a b b 2 2 2 A L L L L L r@b b a 3 Z L L L L O p 6 4 4 5 9 z@l m n o p q r s E L L L L L +.*.C F +.N L L L L L N N M L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L T a+. ", +" , A@L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L M M M M L L L L L M M M M N N N N N M L N O O O O Q R R R L L O P O O Q V V r.r.W W Y Z Y Y Z ` ` +. .L L M M M L @.D C H ` L L L L L T z z y x U L L L L L C r r r r q o p p p p p p p o C L L L L L ` q s t t U L L L L L E z -.s@r@r@B E &.E %.F $.G G ` L L L L L Q ......@.N L L L L L P r.T T Q L L L L L L N P N N Q O M P N N N N N X .V L L L L L L L L L L L L L L L L L G B@ ", +" + C@L L L L L L L L L L L L L L L L L L L L R A Z W W W M L L L L L L U X X V L L L L L L Y l 9 9 9 5 5 4 B B 4 &.` ` ` O L L L L L P ` ` ` X L L L L L L t@.. . .T L L L L L +.2 c c c c d d C w e e A @.@. .L L L L L @.d &.@.@.r.L L L L L b j j j k k D@2 Z j u@u@| F F G N L L L L 2 E@4 F F ` L L L L &.F@.@t %.E U M M M N < G@G@H@H@H@I@b F J@K@K@K@d C C r.P P P .H@L@M@n C F P P P P t@N@O@O@O@O@O@P@#.k O@8@8@Q@O@p E R M M M M 1 R@R@N@t@ .L L L L T S@T@U@G@%.P L L L L B V@U@U@U@U@Q@G E@W@W@W@W@W@W@4 P L L L L T P@X@X@Y@*.L L L L L &.K X@X@X@X@< -.Z@X@X@`@`@`@`@: P L L L L M #.#.#+#*.L L L L L ..@#X@X@F@O L L L L L t Y@Z@Z@Z@i p W@+#+#+#Y@Y@.###N@Z L L L L L L L L L L L L L L L L L 7 ] ", +" J 0+Z L L L L L L L L L L L L L L L L L L L L A l F F F ` L L L L L L Q $.%.F V L L L L L L 9 E@E@E@$#$#$#H@0 h u@r@D D G N L L L L L G C C C ` L L L L L .4 C C C T L L L L L 6 K@K@P@P@M@M@L@n %#L@P@r B B G L L L L L 6 K@A *.*.W L L L L W &#R@T@T@T@U@U@.@H T@K K .@H r@&.M L L L P K@`@} s@s@@.L L L L 9 ##*#7 t@t@W M M M T V@=#-#-#;#;#q.$#s@=#>#>#>#,#y z Z P Q Q +.'#)#!#k y s@R Q Q Q w )#~#~#~#~#{#)#-.J@]#]#]#]#]#A@A W N M M M c ^#/#~#8 C L L L L N U@a+a+>#u W L L L L $.(#_#_#:#:#a+6 <#:#:#:#:#[#[#M@V L L L L L : [#[#:#A@L L L L L V *#[#[#[#[#C@r@}#[#[#[#:#:#:#|#r@L L L L L p {#_#a+I@L L L L L L : /#/#1#z L L L L L W +#{#{#~#-#0 U@~#2#2#|#|#|#|#!#: P L L L L L L L L L L L L L L L L L M@& ", +" y@A L L L L L L L L L L L L L L L L L L L L Y b &.F F G P L L L L L L ` %.%.@.M L L L L L @.A@E@E@$#$#$#F@J@4 $#b E E D r.L L L L L U r@D D E Q L L L L L s t C C F M L L L L R #K@P@P@P@M@M@K@q &#N@H@s@B B W L L L L N 3#,#H *.B S L L L L D Q@R@T@T@U@U@U@j 9 K K K k r@r@%.L L L L ` V@4#a s@s@Z L L L L | ##*#9 t@-.U M M N Y K -#-#;#;#q.q.<#s@-#>#(#(#G@y y .R R R ..*#!#|#u@x -.T R R R -.1#~#{#{#{#]#~#r #^#]#]#^#^#&#A ..N N M M u {#/#/#i H O L L L L $#_#_#]#a @.L L L L P Y@:#:#:#:#[#H@s ^#[#[#[#[#[#5#H L L L L L p /#[#6#*#Y L L L L L u@[#[#[#[#_#3 E@[#[#[#[#[#[#[#,#L L L L L T W@_#_#7#B L L L L L B >#/#/#M@P L L L L L z@|#]#]#{#O@g (#~#~#2#2#2#|#|#5#p L L L L L L L L L L L L L L L L L T a+. ", +" 8#D@L L L L L L L L L L L L L L L L L L L L N l o $.F F X L L L L L L T F %.F U L L L L L M 6 E@E@E@$#$#$#H@} [ E@z E E F O L L L L L &.B D D @.L L L L L R c H C C Z L L L L L *.S@K@P@P@M@M@M@F@5 M@N@D@&.B C R L L L L ` x@[ B *.D N L L L L n R@T@T@T@U@U@U@6 j K K Y@c r@r@@.L L L L E K 4#5 s@s@r.L L L L k 9#.#l t@s@T N N N Z Y@-#;#;#q.q.5#3#t@;#(#(#7#K@y y ..R R R ..'#|#|#: x t@V S R R H (#{#]#]#]#]#]#c 2 ]#^#^#/#/#K A F N N N N C )#a+a+x@s@T L L L L 4 a+_#_#F@E L L L L L F@[#[#[#[#[#9#C -#[#[#[#[#6#a+0 O L L L L Z -#6#6#/#q L L L L L *.2#6#6#6#6#U@A !#6#6#6#[#[#[#(#E L L L L L 8 /#:#:#0#L L L L L L G@a+a+!#s L L L L L T a#]#]#]#)#< M@~#~#~#~#~#2#2#2#Y@` L L L L L L L L L L L L L L L L L G B@ ", +" # ##L L L L L L L L L L L L L L L L L L L L L C c D $.F #.N L L L L L M +.F F +.M L L L L L F %#E@E@$#$#$#F@J@9 F@} D E E Z L L L L L Q v D D E U L L L L L B a D C D R L L L L L 2 K@P@P@P@M@M@L@0 %#N@N@3 B B %.L L L L L -.b#5 *.*.G L L L L L i T@T@T@U@U@U@R@x : K K K 4 r@r@Y L L L L t@4#+#n s@r@U L L L L 0#9#`@p t@s@T N N N $..#;#;#q.q.5#># #x q.7#7#7#N@y x @.T T T Y `@2#2#x@x A W T T T D q.]#]#]#^#^#^#u@t ]#/#/#/#/#C@w C N N N N Y C@_#_#4#t@X L L L L s@~#:#:#W@B P L L L L n a+[#[#[#[#{#s@b#6#6#6#6#6#6#M@V L L L L L S@c#c#c#I@M L L L L Q K c#c#c#c#{#v O@c#c#6#6#6#6#[#D@L L L L L W ##[#[#7#C L L L L L B 7#_#_#R@T L L L L L p !#^#^#]#4#c =#{#{#~#~#~#~#2#|#A@L L L L L L L L L L L L L L L L L L 4 ^ ", +" d#/ >#W L L L L L L L L L L L L L L L L L L L L S 2 t $.$.$.V L L L L L L V F F F T L L L L L O a E@E@$#$#$#$#H@h g F@r E E F Q L L L L L C z D D $.N L L L L L 0 u C C G L L L L L V $#K@P@P@M@M@M@K@p J@N@K@t B B ..L L L L L 2 N@v *.*.Y L L L L Q H@R@T@T@U@U@W@O@y O@K Y@T@q r@H V L L L L l X@K s s@H S L L M L K@9#4#r t@r@R N N O %.*#;#q.q.5#>#>#%#v >#7#1#1#b#y x G T U U U Y@~#~#Q@x z X U U U @.}#^#^#/#/#/#/#J@t@2#a+a+a+a+)#n H O O N N N W@_#_#>#t @.L M L L X =#[#[#>#w U L L L L E !#6#6#6#6#6#k d [#c#c#c#c#c#;#D L L L L L n :#c#c#q.@.L L L L L 2 [#c#c#c#c#G@m a+c#c#c#c#c#c#}#` L L L L L < :#[#[#0#L L L L L L H@_#_#{#z@L L L L L R M@/#/#^#{#F@E@~#]#{#{#{#~#~#~#-#t@L L L L L L L L L L L L L L L L L L P@& ", +" + e#X L L L L L L L L L L L L L L L L L L L L L s 2 %.$.$...M L L L L L N #.F F ..L L L L L L D u@E@E@$#$#$#F@ $#k B E E .L L L L L O n &.D D Y L L L L L ` [ *.C C W L L L L L t@&#K@P@P@M@M@M@.@z@L@N@G@r@B &.U L L L L P $#&#s@B B T L L L L +.N@T@T@U@U@U@W@J@x R@K Y@V@x r@*.S L L L L f X@R@x s@*.P L M M T Q@f#Z@t t@H P O O O C 9#q.5#5#>#>#(#3#c (#1#1#)#8@y x G V V V U Y@~#{#K x x ` V V V Z *#/#/#/#/#/#a+U@w )#_#_#_#_#]#a -.S P O O N S@:#:#]#7 E L M M M L K [#[#/#8 ` L L L L P X@6#6#c#c#c#T@*.|#c#c#c#c#c#_#6 N L L L L .q.g#g#:#5 L L L L L F 1#g#g#g#g#(#s@'#g#c#c#c#c#c#:#a L L L L L G q.6#6#1#C L L L L L s@)#:#:#+#V L L L L L t@1#/#/#/#-#c 4#]#]#]#]#{#{#~#~#O@T L L L L L L L L L L L L L L L L L T a+. ", +" ! h L L L L L L L L L L L L L L L L L L L L L @.g y $.$.G R L L L L L L X F F $.R L L L L L P 1 E@E@$#$#$#F@H@[ f F@9 %.E %.R L L L L L #.o E D %.Q L L L L L r 0 D C E P L L L L L e K@P@P@P@M@M@N@2 [ N@N@< &.&.E N L L L L #.P@3#B B D N L L L L z a#T@T@U@U@W@W@A@l K Y@Y@L@-.H &.N L L L L $#X@Q@A s@&.N M M M Y U@f#K x t@*.P O O P r@}#5#5#>#>#(#7#<#g 7#)#)#!#T@x w $.W W W U K {#]#X@w x ` W W W T +#/#a+a+a+_#_#9#z ;#_#_#_#_#_#< t@V P P O O i :#[#:#< H N M M M M F@6#6#6#E@%.L L L L L 0#c#c#c#c#c#1#D X@c#c#g#g#g#g#x@T L L L L L M@h#h#h#O@P L L L L L N@h#h#h#h#c#} i c#g#g#g#g#g#g#X@U L L L L L $#6#c#[#F@L L L L L M &#[#:#/#a L L L L L M I@a+/#/#/#N@i |#^#]#]#]#]#{#{#|#c L M L L L L L L L L L L L L L L L L G i#J ", +" # W@L L L L L L L L L L L L L L L L L L L L L Q 3 0 F $.$.Z L L L L L L P G F F ` L L L L L L B #E@E@$#$#$#F@	 E@ #r@E E +.L L L L L L l t@D D ..L L L L L Q [ v D C @.L L L L L ` ,#K@P@P@M@M@M@L@o I@N@L@5 &.&.G L L L L L s Q@c B B G L L L L L 2 T@T@U@U@U@W@W@a f Y@Y@Y@G@H H E L L L L O K@.#M@s@s@E M M M M $.4#C@U@y t@B O P P P t@=#5#>#>#(#(#7#u@g 7#)#!#!#Y@w w $.W W X U R@]#]#}#s w +.X X W T R@_#_#_#_#_#_#5#t@*#:#:#:#:#[#H@z Y P P P O n _#[#[#K@r@R M M M M z@:#6#6#W@B N L L L L l [#c#c#c#c#:#o F@g#g#g#g#g#g#-#F L L L L L m 6#h#h#|#D L L L L L n [#h#h#h#h#`@t@)#h#h#h#h#h#g#_#l L L L L L C !#c#c#7#E L L L L L s@|#[#[###` L L L L L C q.a+a+a+!#g @#/#^#^#]#]#]#]#{#f#%.L M L L L L L L L L L L L L L L L L 9 ^ ", +" d#p.r.L L L L L L L L L L L L L L L L L L L L L s@[ -.$.$.G P L L L L L L ` F F G Q L L L L L Q c E@E@$#$#$#F@H@h } .@b %.E %.T L L L L L ` 0 E E E T L L L L L C k &.D D U L L L L L x x@P@P@P@M@M@M@: o M@N@x@y &.&.X L L L L L [ Q@l B B Y L L L L N $#T@T@U@U@U@W@R@v ,#Y@Y@+#u@H H G L L L L X @#.#H@r@s@F L M M M B *#C@V@A t@D P P Q Q u ;#>#>#(#7#7#1#%#g 1#!#|#|#+#w w F X X Y T O@^#^#q.p v @.Y Y Y r.N@_#_#_#:#:#:#|#t R@[#[#[#[#[#a#z +.Q Q P P s@]#6#6#4#-.r.M M M M -.^#c#c#(#x T L L L L E 2#g#g#g#g#g#J@r _#h#h#h#h#h#:#9 N L L L L ..(#h#h#g#f L L L L L Y =#h#h#h#h#:#q S@h#h#h#h#h#h#h#R@P L L L L L x@c#c#c#E@L L L L L M &#[#[#_#g L L L L L L <#a+_#a+a+K d >#/#/#^#^#]#]#]#]#J@P L M L L L L L L L L L L L L L L L L K@j# ", +" k#F L L L L L L L L L L L L L L L L M L L L L W | 4 $.$.$.W L L L L L L S $.F F Z L L L L L L s@3#E@E@$#$#$#F@	 E@E@x %.E #.M L L L L L q r E E G M L L L L L 2 7 D D F N L L L L N h P@P@P@M@M@M@L@| h N@N@F@B &.C R L L L L U G@M@y B &.T L L L L ` M@T@T@U@U@W@W@8@t@M@Y@Y@+#f H H .L L L L %.K *#E@s@s@@.M M M N t@##}#Q@t@A E P Q Q R t q.>#(#7#7#1#1#%#h )#|#|#2#`@v v F Y Y Y U O@/#/#)#9 v $.Z Z Z Y G@:#:#[#[#[#[#^#4 &#[#[#[#6#6#C@x E Q R Q Q @.>#c#c#7#t .N M M M Z ;#c#c#a+7 W L L L L P .#g#g#g#h#h#C@D 5#h#h#h#h#h#h#H@S L L L L L N@l#l#l#+#R L L L L L .@l#l#l#l#l#N@u a+l#l#l#h#h#h#^#x L L L L L A ]#g#g#7#E L L L L L s@2#6#6#-#@.L L L L L F ;#_#_#_#]# #H@^#/#/#/#^#^#^#]#)#9 L M M L L L L L L L L L L L L L L L R ]#. ", +" m#d L L L L L L L L L L L L L L L L L L L L L N l h *.$.$.@.N L L L L L M ..F F G P L L L L L S f E@E@$#$#$#$#I@h } .@g E %.%.V L L L L L U e *.E E W L L L L L ` #y D D .L L L L L @.G@K@P@P@M@M@M@M@p : N@N@g C B %.M L L L L %.N@: *.B D O L L L L C @#T@U@U@U@W@W@&#z a#Y@+#Y@8 H H W L L L L s@4#*#j s@s@Z N N N O r f#}#L@t@A F S T U U 7 >#(#7#7#1#1#)#D@j !#|#2#~###s v &.#.G $.#.O@/#a+|#7 u &.E D D D F@[#[#[#[#[#6#:#d A@6#6#c#c#c#)#p B #.%.E %.C '#c#c#/#7 %.Z #.@.@.+.W@g#g#c#j #.U Y Y X X H@h#h#h#h#h#^#r@8@h#h#h#l#l#l#=##.L P O O N 9 c#l#n#/#s@L L L L L A :#n#n#n#n#2#-.+#l#l#l#l#l#l#l#K@L L L L L Q R@h#h#c#$#L L L L L M K@c#6#[#<#L L L L L L D@_#:#_#_#}#2 ##a+/#/#/#/#^#^#^#`@ .L N L L L L L L L L L L L L L L L L #.i#J ", +" o#O@L L L L L L L L L L L L L L L L L M L L L L D < n G $.$.Y L L L L L L U $.F F +.L L L L L L A <#E@E@$#$#$#F@x@9 E@F@q %.%.F R L L L L L A 3 %.E E T L L L L L r A@C D D W L L L L L p K@P@P@P@M@M@M@H@p M@b#N@z@&.&.$.L L L L L n Q@< C &.E M L L L L m R@T@U@U@U@W@K #v W@+#+#K m H H V L L L L m X@*#e s@s@Y N N P R b }#}#&#t@A F S S T T c (#7#7#1#)#)#)#i D@|#2#~#~#}#q u H $.F F F O@a+_#]#2 t -.r@s@s@-.F@6#6#6#6#c#c#6#k | c#c#c#c#c#/#8 s@t@[ $#z@y *#c#g#c#[ B E H &.4 b W@g#g#g#O@D Y #.@.+. .,#h#h#h#h#h#g#} | h#l#l#l#l#l#[#l N Q Q P O v c#n#n#l# #L M L L L &./#n#n#n#n#l#A@b g#n#n#n#n#l#l#2#C L L L L L L@h#h#h#1#E L L L L L F@c#c#c#(#E L L L L L 4 _#:#:#:#_#&#D@{#a+a+/#/#/#/#^#]# #L M N L L L L L L L L L L L L L L L L z@/ ", +" d#I V L L L L L L L L L L L L L L L L M L L L L S 2 f C $.$.$.+.L L L L L N @.$.F F G M L L L L T g E@E@$#$#$#$#I@i | .@D@B %.%.%.T L L L L Q | z E E E V L L L L Q i 7 E D D ` L L L L O k K@P@P@M@M@L@N@} } b#b#K@x &.&.F L L L L L i @#8 &.&.D O L L L L i T@T@U@U@W@W@W@d e +#+#+#R@u H H r.L L L L e *#.#3 s@s@Y L L L L < }#=#J@t@A G L L L L } 7#7#1#)#)#!#!#[ #~#~#{#]#=#q t %.L L L L N@_#:#a+} t E L L L L 3#c#c#c#c#c#c#c#: 4 [#g#g#g#h#c#g A R 5 h G L ##g#g#g#M@r@R L M t@G Y@h#h#h#;#-.R L L L L x@l#h#l#l#l#l#U@*.{#l#n#n#n#n#n#,#R L L L L 4 l#n#n#n#C@X L L L L x c#n#n#n#n#n#f#H >#n#n#n#n#n#n#l#F@L L L L L `@l#h#h#g#F@L L L L L R@g#c#c#c#: L L L L L F@[#[#[#:#:#1#} U@_#_#a+a+/#/#/#/#>#x L N N L L L L L L L L L L L L L L L L J@j# ", +" p#F L L L L L L L L L L L L L L L L M L L L L L v k 7 s@H C %.G O L L M L B A s@B D F R N L M L u <#E@E@$#$#$#F@x@5 E@.@e y t@H C X N L M M &.k t y s@B .N L L M B 0#6 v z r@G Q N L R F I@P@P@M@M@L@L@N@p 0#b#b#I@l t z B S P L Q ` I@8@d p x H r.S L T ` S@T@U@U@W@W@K U@u E@+#+#Z@R@b n w @.W L S r.<#*#.#k 5 r F W L R W $#=#=#N@a l *.X M R W #7#1#)#)#!#|#|#[ <#{#{#]#]#>#u@a -...S Q .V@:#[#:#M@c y ..T N ..H@g#c#g#g#h#h#h#8@o a+h#h#h#h#h#R@0 C 4 a D E ;#h#h#h#=#c C +.M t@%.f#h#h#h#_# #H $.N ` F U@l#l#l#l#n#n#)#F .#n#n#n#n#n#n#5#r D S V D E@n#n#q#q#c#e C V U C e n#q#q#q#q#q#c#9 ,#n#q#q#q#q#n#n#(#x +.P C z 7#l#l#l#l#)#t G L E B C@g#g#g#g#|#o %.L %.&.S@[#[#[#[#[#[#U@| )#_#_#_#a+a+a+/#/#T@V L O L L L L L L L L L L L L L L L L R ]#. ", +" ] 0 L L L L L L L L L L L L L L L L M M L L L L ..g D@k k j [ g | 1 e +.a e k %#A@k i h } f #.0 } %#E@E@E@$#$#$#H@k e .@.@.@F@E@3#%#i i &.4 i u@G@: : .@E@%#A@t@n A@E@&#S@J@H@,#E@3#o A 3#.@P@M@M@M@M@L@L@I@p M@b#b#b#b#L@K@J@0#d G F@H@Q@V@@#Q@b#K@J@k ` ,#&#R@U@U@W@W@K K @#A P@+#+#Z@4#Z@Y@R@8@x@@.F@@#+#'###'#*#4#U@b#@. #U@*#-#-#;#-#f#`@W@&.h X@C@)#)#!#!#|#2#|#h E@{#]#^#^#/#/#~#5#q.c u q.]#[#6#6#6#_#)#7#<#r@q.]#h#h#h#h#h#h#h#+#w ~#l#l#l#l#l#h#:#2#f#| .#|#c#l#l#l#l#6#~#f#G @#|#[#l#l#l#l#g#]#>#B I@{#[#n#n#n#n#n#n#c#p ,#n#n#n#n#q#q#q#:#^#d 6 ]#[#I q#q#q#q#c#/#F@v 2#[#I I I I I I I a#t@^#q#q#q#q#q#q#n#_#4#E f#a+l#n#n#n#n#l#a+}#C R@/#c#h#h#h#g#g#/#(#v K@{#_#c#6#6#[#[#[#]#j &#_#_#_#_#_#a+a+/#]#| L M O L L L L L L L L L L L L L L L L @.r#J ", +" % M@L L L L L L L L L L L L L L L L L N L L L L P 7 D@D@A@A@A@A@%#%#E@,#z@u@u@ # # # #3#3#E@J@p 3#E@E@E@E@$#$#$#F@K@z@E@.@.@.@,#,#,#0#0#P@n <#: G@H@H@I@I@I@J@P@m u@S@S@&#&#&#&#x@x@M@8 < P@P@P@M@M@M@L@L@N@h d N@b#b#O@O@O@8@8@8@A@p Q@@#@#V@V@V@a#a#R@F@-.V@T@U@U@U@W@W@K K K@t@V@+#+#Z@4#4#4#`@X@@#B V@*#*#'#####9#9#f#+#@.N@=#=#-#;#;#q.5#>#}#B 0#7#1#)#!#!#|#2#2#|#h $#]#^#^#/#a+a+_#_#:#g r _#6#6#c#c#c#g#g#h#M@*./#h#h#l#l#l#l#l#l#}#z 7#n#n#n#n#n#n#n#n#{#| X@l#l#l#l#l#l#l#l#:#q S@l#l#l#l#l#l#n#n#h#3 f l#n#n#n#n#n#n#n#n#.@t 6#q#q#q#q#q#q#q#q#K C ]#I I I I I I I I 5#C -#I I I I I I I I /#-.V@I I I q#q#q#q#q#c#5 ,#n#n#n#n#n#n#n#n#h#u@d [#l#h#h#h#h#h#g#g#O@3 {#c#c#c#6#6#6#[#[#'#2 -#:#:#_#_#_#a+a+a+=#E L O N L L L L L L L L L L L L L L L L 9 / ", +" . c#T L L L L L L L L L L L L L L L L N M L L L L H j D@D@A@A@A@A@%#%#K@8 j u@u@ # # #3#3#3#J@c h <#E@E@E@E@$#$#$#H@k c .@.@.@,#,#,#,#0#H@E@6 G@H@H@H@H@I@I@I@J@J@n I@S@S@&#&#&#x@x@x@P@q H@P@P@P@M@M@M@L@L@N@o ,#b#b#b#O@O@O@8@8@8@7 i @#@#@#V@V@V@a#a#R@} 4 T@T@U@U@U@W@K K K F@z@K +#Z@Z@4#4#`@`@X@P@z Y@*#'#'#####9#f#f#T@C R@=#-#-#;#q.q.5#>#C@s@K@1#)#)#!#|#2#2#~#2#h F@^#/#/#a+a+_#:#:#[#D@n _#c#c#c#g#g#h#h#h#U@H {#l#n#n#n#n#n#n#n#)#q 9#n#n#n#n#n#n#n#n#:#9 K@n#n#n#n#n#n#n#n#h#f g l#n#n#n#n#n#n#n#n#K@t@:#n#n#n#n#n#n#n#q#C@E (#q#q#q#q#q#q#q#I {#&.U@I I I I I I I I h#9 F@I I I I I I I I q#F@z@g#I I I I I I I q#+#x 2#q#q#q#n#n#n#n#n#(#q X@l#l#l#h#h#h#h#h#/#c L@c#c#c#c#c#6#6#6#_#: E@/#:#:#:#_#_#_#a+/#x@R L P M L L L L L L L L L L L L L L L L J@j# ", +" B@#.L L L L L L L L L L L L L L L L M N L L L L W e D@D@A@A@A@A@%#%#,#u@a u@u@u@ # # #3#3#$#J@5 3#<#E@E@E@$#$#$#F@P@5 <#.@.@.@,#,#,#0#: P@7 u@G@H@H@H@H@I@I@J@x@} g S@S@S@&#&#&#x@x@K@<#6 K@P@P@P@M@M@M@L@L@&#s P@b#b#b#O@O@O@8@8@b#r S@@#@#@#V@V@V@a#a#V@9 <#T@T@U@U@W@W@K K K f | +#+#Z@Z@4#4#`@X@X@,#7 X@*#'#####9#9#f#C@O@o 4#-#-#;#q.q.5#>#>###l V@)#)#!#|#2#2#~#{#|#g ,#/#/#a+_#_#:#:#[#6#J@} _#c#g#g#h#h#h#l#l#f#z@)#n#n#n#n#n#n#q#q#/#4 K q#q#q#q#q#q#q#q#h#[ A@n#n#n#n#n#n#n#n#n#L@l [#n#n#n#n#n#n#n#n#-#*.(#n#n#n#q#q#q#q#q#a+H Q@q#q#q#q#I I I I n#d f n#I I I I I I I I 8@-._#I I I I I I I I >#*.}#I I I I I I I I [#m x@q#q#q#q#q#n#n#n#h#F@e [#l#l#l#l#h#h#h#h#Z@7 )#g#g#c#c#c#6#6#6#7#c `@[#:#:#:#_#_#_#a+~#5 L N Q L L L L L L L L L L L L L L L L R ]#9@ ", +" / 9 L L L L L L L L L L L L L L L L L O L L L L L p k D@D@A@A@A@A@%#u@x@z@D@u@u@ # # #3#3#3# i <#E@E@E@E@$#$#$#H@A@c .@.@.@,#,#0#: : H@H@9 : G@H@H@H@I@I@I@J@K@n 0#S@S@&#&#&#&#x@x@M@7 u@P@P@P@M@M@M@M@L@N@i a N@b#b#b#O@O@O@8@8@I@n O@@#@#V@V@V@a#a#R@O@r P@T@U@U@U@W@W@K K W@4 $#+#+#Z@4#4#4#`@X@X@i } *#*#'#####9#f#f#C@ ##-#-#;#q.5#>#>#(#*#z@Y@)#!#|#|#2#~#{#{#|#} H@/#a+_#_#:#[#[#6#c#M@} _#g#h#h#h#l#l#n#n#;#9 (#q#q#q#q#I I I I 6#c L@I I I I I I q#q#q#,#b h#q#q#q#q#q#q#q#q#*#z !#n#n#n#n#n#n#n#n#a+v R@q#q#q#q#q#q#q#q#n#| c n#I I I I I I I I K H /#I I I I s#s#s#s#{#H `@s#s#s#s#s#s#s#s#n#0 D@q#I I I I I I I I 8@r /#I q#q#q#q#q#q#n#7#r X@n#n#l#l#l#l#h#h#:#g I@c#g#g#c#c#c#c#6#[#8@h ~#[#[#:#:#:#_#_#_#*#+.L P P L L L L L L L L L L L L L L L L +.t#J ", +" j#H@L L L L L L L L L L L L L L L L L O M L L L L F [ D@D@D@A@A@A@%#%#I@[ e u@u@u@ # # #3#3#.@,#4 <#<#E@E@E@E@$#$#F@P@z@<#.@,#,#0#0#0#: : K@a k G@H@H@H@H@I@I@I@&#<#7 S@S@S@&#&#&#x@x@x@x@q S@P@P@P@M@M@M@L@L@N@m E@N@b#b#O@O@O@O@8@Q@g c Q@@#@#V@V@V@a#a#R@J@q @#T@U@U@U@W@W@K K V@q x@+#Z@Z@4#4#`@`@X@`@2 #*#'#'###9#9#f#C@}#.@0 f#-#;#q.q.5#>#(#7#4#m Z@!#!#|#2#~#{#{#]#2#| &#a+_#_#:#[#[#6#c#c#b#f :#h#l#l#n#n#n#n#q#)#9 =#I I I I I I I I l#[ $#I I I I I I I I I V@l [#I I q#q#q#q#q#q#2#w *#q#q#q#q#q#q#q#q#h#e D@n#q#q#q#q#q#q#q#I 8@&.^#I I I I I I I I {#&.+#s#s#s#s#s#s#s#s#q#e | q#s#s#s#s#s#s#s#s#+#H ~#s#s#s#s#I I I I ^#v V@I I I q#q#q#q#q#l#3#e 6#n#n#n#l#l#l#l#h#*#5 q.g#g#g#g#c#c#c#6#]#[ N@[#[#[#:#:#:#_#_#a+E@L L R N L L L L L L L L L L L L L L L L l u# ", +" . ~#Q L L L L L L L L L L L L L L L L N O L L L L R a D@D@D@A@A@A@A@%#3#J@9 %#u@u@ # # # #3#3#K@4 k <#<#E@E@E@$#$#$#H@A@1 ,#,#,#0#0#0#: : G@&#n 0#G@H@H@H@H@I@I@I@M@5 3#S@S@S@&#&#&#x@x@P@j 3 K@P@P@P@M@M@M@L@L@S@t K@N@b#b#O@O@O@8@8@O@n F@@#@#@#V@V@V@a#a#R@D@0 R@T@U@U@U@W@K K K N@q @#+#Z@Z@4#4#`@X@X@4#5 J@*#'#####9#f#f#C@}#A@e }#-#;#q.5#>#>#(#7#+#z@##!#|#2#~#~#{#]#^#2#e P@_#_#:#[#[#6#c#c#g#O@} :#l#n#n#n#q#q#q#I ~#4 *#I I s#s#s#s#s#s#I E@< I s#s#s#s#s#I I I '#v |#I I I I I I I I [#4 S@q#q#q#q#q#q#q#q#q#I@a c#q#q#q#q#I I I I !#H '#I I I I I I I I q#d g I s#s#s#s#s#s#s#s#Z@B ~#s#s#s#s#s#s#s#s#[#y K@s#s#s#s#s#s#s#I I I@z@[#I I I I q#q#q#q#>#s .#n#n#n#n#l#l#l#l#6#%# #6#h#g#g#g#c#c#c#c#X@1 (#[#[#[#:#:#:#_#_#)#u L N S L L L L L L L L L L L L L L L L L H@j# ", +" v#@.L L L L L L L L L L L L L L L L M P L L L L L y k D@D@D@A@A@A@A@%# [ u@u@u@ # # #3#3#,#E@3 <#<#E@E@E@E@$#$#F@M@z@E@,#,#,#0#0#0#: : &#} f G@G@H@H@H@I@I@I@J@I@n I@S@S@S@&#&#&#x@x@L@l $#K@P@P@P@M@M@M@L@N@A@0 N@N@b#b#O@O@O@8@8@P@s P@Q@@#@#V@V@V@a#a#a#7 u@T@T@U@U@W@W@K K K ,#l W@+#Z@4#4#4#`@X@X@W@o b#'#'#####9#f#f#C@C@g j -#;#q.q.5#>#(#7#7#a#9 f#|#2#2#~#{#]#^#^#2#e L@:#:#[#6#6#c#g#g#h#8@e _#n#n#q#q#I I I I a+a +#s#w#w#w#w#w#w#w#w#S@e n#w#w#w#s#s#s#s#s#1#v f#I I I I I I I I n#k [ n#I I I I I I q#I *#n )#I I I I I I I I g#b K@I I I I I s#s#s#s#R@t@_#s#s#s#s#s#s#s#s#:#s@b#w#w#w#w#w#w#s#s#s#H@u c#s#s#s#s#s#s#s#s#~#x Z@I I I I I I q#q#l#3#e c#n#n#n#n#n#l#l#l#;#5 C@h#h#g#g#g#g#c#c#_#3#,#_#[#[#[#[#:#:#_#_#W@V L Q R L L L L L L L L L L L L L L L L R 2#9@ ", +" x#o L L L L L L L L L L L L L L L L L P M L L L L ` f D@D@D@A@A@A@A@A@F@F@7 u@u@u@u@ # # #3#3#K@4 A@<#<#E@E@E@$#F@F@J@A@b ,#,#,#,#0#0#0#: : K@m ,#G@G@H@H@H@I@I@I@K@d h S@S@S@&#&#&#&#x@K@J@q &#K@P@P@M@M@M@M@L@O@m <#N@N@b#b#O@O@O@8@Q@.@m 8@Q@@#@#V@V@V@a#a#T@q &#T@T@U@U@W@W@K K +#k d +#+#Z@4#4#`@`@X@X@R@p U@'#####9#f#f#C@}#C@d E@;#;#q.5#>#>#(#7#1#R@7 ;#|#2#~#{#]#]#^#/#~#} L@[#[#6#6#c#g#g#h#l#@#c a+q#q#I I I I s#s#[#c V@w#w#w#w#w#w#w#w#y#Q@3 c#w#w#w#w#w#w#w#w#_#9 R@s#s#s#s#I I I I I  c#I I I I I I I I ]#9 +#I I I I I I I I I x@%#h#I I s#s#s#s#s#s#^#4 ;#s#s#s#s#s#s#w#w#s#$#k I w#w#w#w#w#w#w#w#|#z (#s#s#s#s#s#s#s#s#I 3#i q#I I I I I I q#q#>#r 7#q#n#n#n#n#n#l#l#g#$#A@h#h#h#g#g#g#c#c#c#;#b >#6#[#[#[#[#:#:#_#/#g L L T O L L L L L L L L L L L L L L L L +.t#J ", +" > F@L L L L L L L L L L L L L L L L L O P L L L L L 7 <#E@E@E@E@$#$#F@F@c#9 <#,#,#0#0#0#: : : *#8@c H@H@&#@#V@V@V@a#a#c#4 8@R@R@R@T@T@T@U@U@5#M@k Y@+#+#+#+#+#Z@Z@4#h#z@Y@.#*#*#*#*#'#'#'#|#K@3#9#9#f#f#f#C@C@}#}#g#z@'#-#-#-#;#;#q.q.5#/#G@: >#(#7#7#7#1#1#)#)#6#l (#{#]#]#]#/#/#/#a+n#0#&#[#[#[#6#c#c#g#h#l#^#0 [#q#I s#w#w#p.p.H+z#A@U@]@A#B#C#w@0+D#E#F#>#2 A#G#H#v#I#J#t#r#G+I#k f#K#L#p#M#{@k#N#O#v@{#g M#P#P#P#P#Q#Q#_ _ R#E@~#S#u#/ / / / / =.=.e#e P#=.=.=.=.=.=.=.=.x#3#-#=./ / / / / u#u#u#T#p {@x#x#/ / u#u#u#x#_ #*#x#S#S#S#_ _ Q#P#R#y#[ G+v@p@O#U#V#W#N#N#X#K@;#{@M#M#X#p#p#p#L#L#I F@Y#K#K#K#Z#`#`#`#B@r#0#2#G+G+G+r#t#t#t#J#J#_#0#F#v#v#v#H#G#G#G#G# $G@I $.$.$F#F#+$E#E#E#_#N@F#0+w@C#C#B#B#A#A#e#�+A#T#T#@$z#z#H+H+p.7#Y L N V M L L L L L L L L L L L L L L L M l u# ", +" + )#L L L L L L L L L L L L L L L L L N R L L L L L L [ O@O@8@8@Q@Q@Q@@#V@e#t 8@R@R@T@T@U@U@W@W@1#&#u@+#+#f#y#p.p.H+z#H+D#6 n#z#z#z#z#z#@$T#T#+$P@W@#$#$e#e#e#e#e#]@]@D#4 p.B#C#C#C#w@w@0+0+H#K@K E#E#+$+$F#F#.$.$ $0+3 B#G#G#H#v#v#I#q@q@i#K@X@r#r#G+G+i#$$$$B@`#0+e v#L#p#p#X#M#M#{@k#k#J@=#W#V#U#O#O#p@v@%$y@C#g &$Q#_ S#x#u#/ =.^ S#F@^#m#*$=$~ ! ' 8#, - e#[ ( & o## @ 9@d#J & E@@$ q@<#d# &#q@ {@E@ K@G# &$g : e# i#j > J d#. j#&#p.o#% & j#= > - ; , w@O@S#~ ~ *$*$( ( ] ] _ a#@$/ u#x#S#_ Q#P#R#R#p.*#k#p@O#U#V#W#N#N#k#K#R@F#X#p#L#K#Z#`#`#$$$$g#|#`#t#t#q@q@I#v#H#G#F#Y@K# $F#+$E#E#D#0+w@C#}#L L L R T L L L L L L L L L L L L L L L L M ,#> ", +" J F# .L L L L L L L L L L L L L L L L L R N L L L L L M z@O@O@8@Q@Q@Q@@#@#V@[#2 S@R@R@T@U@U@U@W@K ##;#d +#+#X@I H+H+z#z#z#C#} ]#z#@$@$@$@$T#T#T#B#q.I@#$#$e#e#e#e#]@]@A#w@[ c#B#C#C#C#w@w@0+0++$##K@E#E#+$+$F#F#.$.$ $0+| H+G#G#H#v#v#I#q@q@t#W@b#r#r#G+G+i#$$$$B@`#C#a E#L#p#p#X#M#M#{@k#M#&#K W#V#V#O#O#p@v@%$y@C#c M#Q#_ S#x#u#/ =.^ _ 3#~#m#*$*$~ ! ) 8#, ; T#[ ( & o#$ # + . J * <#@$ I#E@. H@q@ i#0# .@G+ r#E@ J [ G+ z#3## J . 9@! } .$o#% & j#j#> - ; , ~#&#{ ! ~ =$*$m#( ] ] U#[ +$/ u#x#S#_ _ P#R#R#-#'#U#p@O#U#V#W#N#&$k#v#$#q@X#p#L#K#Z#`#`#$$$$K h#$$t#t#q@q@I#v#H#G#z#b#B@F#F#+$E#D#0+0+w@C#: L L L M V Q L L L L L L L L L L L L L L L L R 2#9@ ", +" S#u L L L L L L L L L L L L L L L L L Q P L L L L L L V z u@3#3#<#E@E@E@$#$#8@6 | F@.@,#.@F@F@F@.@,#,#t ,#0#: +###########.#p P@.#*#*#*#*#'#'#'###0#a *#######9#9#9#9#f###m Q@f#C@}#}#}#}#}#=#-#,#d f#f#f#C@C@}#}#}#=#.#q T@-#;#;#;#q.q.q.5#5#[ h >#(#7#7#1#1#)#)#)#X@r 9#|#2#~#~#~#|#!#!#!#g u@~#~#~#{#]#]#^#^#/#4#l 1#_#:#[#[#6#c#c#g#[#c N@q#q#I h#h#h#l#n#q#+#2 c#y#p.H+z#z#w#y#p.q#g U@#$e#]@B#C#w@0+E#+$##g C#G#v#v#I#I#q@q@q@F#g -#t#t#t#t#t#t#t#r#r#;#[ q@r#r#v#v#v#H#H#H#E#2 !#G#G#G#G#Y#Y# $q@ $Z@h +$F#F#F#F#+$E#G#G+I m C@e##$T#z#H+p.y#`#D#0#0 ^#_#a+/#/#]#]#6#V#1#v V@|#)#)#1#7#7#(#E#M#k 2 ;#q.;#-#-#-#=#7#M#A#x 8@f#9#9#####'#'#^#k#K@3 V@V@V@V@Q@Q@Q@8@:#]@t H@b#b#N@N@N@L@L@M@h#H@2 P@K@x@x@&#&#&#: J@1#q 0#,#,#,#.@F@F@F@$#u@%.L L L L O W N L L L L L L L L L L L L L L L L E r#J ", +" > F@M L L L L L L L L L L L L L L L L O T L L L L L L O $.C C C C C C C C C C C C C C C C C C C C C C &.&.&.C &.&.C C C C &.B r@t@A z z z z z z z z z y z z z z z z z z z z z y z z z z z z z z z z y y z z z z z z z z y x x y y y y y y y y y x x x x x x x x x x x x x w x x x x x x v v v v v v v v u u u u u t t t t s s s s r r r q q q p p p o o n n n m m l l l z@z@9 9 9 5 5 5 4 4 4 6 6 6 7 7 7 7 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 7 7 7 7 6 6 6 4 4 4 5 5 5 9 9 z@z@l l l m m n n n o o p p q .@p r r r s s t t t t 3 Z@v v v v v v w w w w @#W@x x x x x y y y y s ]@H@z z z z z z z z z .@i#[ A A A A A A A A z g#v#6 t@t@t@t@t@t@t@t@z@F#^#t@-.-.-.-.-.-.-.-.1 .$ #s@s@s@s@s@s@s@s@s@A@g#u r@r@r@r@r@r@r@r@H J@M@*.H H H H H H H H C P L L L L L T V L L L L L L L L L L L L L L L L Y g =. ", +" 9@2#Q L L L L L L L L L L L L L L L L N V N L L L L L L ` D E D D D D D D C C C C C C C C C C C C C C C C C C C C &.&.B B s@t@z z z z z z z z z z z z z z z z z z z y z z z z z z z z z z z y z z z z z z z z z z z y z z z z y y y y y y x y y y y y y y y y y y x y y x x x x x x x x w v x w w w w w w v v v t u v u t t t t s s r r p q q q p p p o o n n l z@m l l l z@z@9 9 9 5 7 7 4 6 7 7 7 7 7 8 3 3 2 3 3 3 3 3 3 3 3 3 3 2 c 3 3 3 3 8 8 7 7 7 7 d 0 4 4 4 4 5 9 9 9 9 7 d 5 m l l l m m n n n P@f o p p p q q r r r m 2#3 s t t t t t t t t 3#6#o v v t t t t t t u ~#{#r r r r r r r r s 3 G#C@r s s t t t t t t P@p#R@t t t t t t t t v f#t#g u u u u u u u u v {#g#r v s s s s s s t o h#b#t t t t t t t t t 9 _#1 u u u v v v v v v D L L L L L M Z W L L L L L L L L L L L L L L L R r K@j# ", +" v#+.L L L L L L L L L L L L L L L L N G X L L L L L L E g [ [ < < < < j j i i i i k k k k k k %#A@D@D@A@A@A@A@A@%# #E@: 0#,#,#0#0#0#0#: G@H@J@S@I@J@J@J@J@J@J@S@S@S@M@&#&#&#&#&#&#K@K@K@K@P@O@M@P@P@M@M@M@M@M@L@L@O@@#b#N@N@O@Q@Q@Q@Q@@#V@U@T@V@V@a#a#R@R@R@R@R@U@`@K U@W@W@W@K K K Y@+#`@##Z@Z@Z@4#4#`@`@X@X@X@=#}#*#'#}#-#;#;#q.q.5#(#2#7#7#7#1#)#)#|#|#2#~#a+[#]#]#^#/#a+_#_#:#[#[#s#I n#q#I I s#w#w#y#y#z#B#z#z#z#z#@$@$T#T#T##$w@+$e#e#e#e#e#e#e#]@]@]@Y#D#e#e#e#e#e#e#e#e#e#B#v#0+e#A#B#B#A#A#A#A#A#.$I#C#A#A#A#A#A#A#A#A#A#t#G#A#A#A#A#A#A#A#A#A#0+Z#+$A#B#w@0+0+0+0+0+0+I#L#+$F#F#F#F#F#F#F#F#F#`#Z#F#F#F#F#F#F#F#F#F# $M#G+F#F#F#F#F#F#F#F#E#v#M#H#E#E#E#E#E#E#E#E#D#q@Z#E#D#+$+$E#E#E#E#E#E#J#J#0+0+0+0+0+w@w@C#C#w@J#E#B#B#A#A#A#]@]@e#e#)#Z L L L L L T C ..O L L L L M M N N N P P P O M .r./#. ", +" ' 9 L L L L L L L L L L L L L L L L L ..H P L L L L L S i K@K@K@P@P@P@M@M@M@L@L@L@N@N@N@b#b#O@O@O@O@8@8@Q@Q@Q@V@T@Y@+#Z@4#4#4#4#`@`@`@X@X@X@X@.#.#.#*#*#*#'#'#'#########9#9#f#f#f#f#C@C@}#}#}#=#=#=#-#-#-#;#;#q.q.q.5#5#>#>#>#(#(#(#7#7#1#1#)#)#)#!#!#|#|#|#2#2#~#~#{#{#]#]#]#^#/#/#/#a+_#_#:#:#[#[#6#c#c#c#g#h#h#l#n#n#q#I I s#w#y#p.p.H+z#z#@$T##$e#]@A#A#B#C#w@0+D#E#+$F#F#.$ $Y#G#H#v#I#I#q@J#t#r#r#G+i#$$$$B@`#`#Z#Z#K#K#L#L#p#p#p#X#X#M#M#M#M#M#M#{@{@{@{@{@{@{@{@{@{@{@{@{@{@{@{@{@M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#{@{@{@{@{@{@{@{@{@{@{@{@{@{@{@k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#{@{@{@{@{@{@{@{@{@{@M#M#M#M#M#M#M#X#X#X#X#X#p#p#p#p#L#L#L#L#K#K#K#K#Z#Z#Z#`#`#`#B@B@B@$$$$$$i#i#G+G+G+r#r#r#t#t#v#J@L L L L L L ..z x W T R S T U V V V U T T R N L L t ' ", +" ~ t@U N L L L L L L L L L L L L L L S w E L L L L L L q &#K@K@K@P@P@M@M@M@M@L@L@N@N@N@N@b#b#O@O@O@8@8@Q@V@T@K +#Z@Z@Z@4#4#4#4#`@`@`@`@X@X@X@.#.#.#*#*#*#*#'#'#'#######9#9#9#f#f#f#C@C@C@}#}#}#=#=#-#-#-#-#;#;#q.q.q.5#5#>#>#>#(#(#7#7#7#1#1#)#)#)#!#!#|#|#|#2#2#~#~#{#{#]#]#^#^#/#/#/#a+_#_#:#:#[#[#6#c#c#g#g#h#h#l#n#n#q#I s#w#w#y#p.p.H+z#@$T#T##$e#]@A#B#C#C#0+0+D#E#+$F#.$ $Y#G#G#v#v#I#q@J#t#t#r#G+i#$$$$B@`#`#Z#K#K#L#L#p#p#p#X#X#M#M#M#M#{@{@{@{@{@k#k#k#k#k#k#k#k#k#k#k#k#{@{@{@{@{@{@{@{@{@M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#{@{@{@{@{@{@{@{@{@{@{@{@{@{@k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#{@{@{@{@{@{@{@{@{@M#M#M#M#M#M#M#X#X#X#X#X#p#p#p#p#L#L#L#L#K#K#K#K#Z#Z#Z#`#`#`#B@B@B@$$$$$$i#i#G+G+G+r#r#r#t#t#]@r L L L L L r.&.[ 4 F ..Z Z Y X r.U R P N M L L L 3 & ", +" # j t@t@@.U Q N M L L L L L L L L L r@0 V L L L L L ..,#K@K@K@P@P@P@M@M@M@L@L@L@N@N@N@b#b#b#O@O@8@@#R@K +#+#+#Z@Z@Z@Z@4#4#4#4#`@`@`@X@X@X@X@.#.#.#*#*#*#*#'#'#########9#9#9#f#f#f#C@C@C@}#}#}#=#=#-#-#-#;#;#;#q.q.q.5#5#>#>#>#(#(#7#7#7#1#1#)#)#)#!#!#|#|#|#2#~#~#~#{#{#]#]#^#^#/#/#a+a+_#_#:#:#[#[#6#c#c#g#h#h#l#n#n#q#I I s#w#w#y#p.H+z#z#@$T##$e#e#A#A#B#C#w@0+D#E#+$F#F# $ $Y#G#H#v#I#q@J#t#t#r#G+i#$$$$B@`#`#Z#K#K#L#L#p#p#X#X#M#M#M#M#{@{@{@k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#{@{@{@{@{@{@{@{@{@M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#{@{@{@{@{@{@{@{@{@{@{@{@{@{@{@k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#{@{@{@{@{@{@{@{@{@M#M#M#M#M#M#X#X#X#X#X#p#p#p#p#L#L#L#L#K#K#K#K#Z#Z#Z#`#`#`#B@B@B@$$$$$$i#i#G+G+G+r#r#t#t#t#>#W L L L L U H n A@s@+.V S P N M L L L L L L L L 4#J ", +" J _#U @.Y V U T S Q P O M M L L L .%#3 N L L L L N c K@K@K@K@P@P@P@M@M@M@L@L@L@N@N@N@b#b#O@Q@R@W@Y@+#+#+#+#Z@Z@Z@Z@4#4#4#4#`@`@`@`@X@X@X@.#.#.#*#*#*#*#'#'#'#########9#9#f#f#f#f#C@C@}#}#}#}#=#=#-#-#-#;#;#;#q.q.q.5#5#>#>#>#(#(#7#7#7#1#1#)#)#)#!#!#|#|#|#2#~#~#~#{#{#]#]#^#^#/#/#a+a+_#_#:#[#[#[#6#c#c#g#h#h#l#n#n#q#I I s#w#w#y#p.H+z#z#T#T##$e#]@A#A#C#C#w@0+D#E#+$F#.$ $Y#G#H#v#v#q@q@J#t#r#G+G+i#$$B@`#`#Z#K#K#L#L#p#p#X#X#M#M#{@{@{@k#k#k#k#k#k#k#k#&$&$&$&$&$&$&$&$k#k#k#k#k#k#k#k#k#k#k#{@{@{@{@{@{@{@{@{@M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#M#{@{@{@{@{@{@{@{@{@{@{@{@{@{@{@k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#{@{@{@{@{@{@{@{@{@M#M#M#M#M#M#X#X#X#X#X#p#p#p#p#L#L#L#L#K#K#K#Z#Z#Z#Z#`#`#`#B@B@B@$$$$i#i#i#G+G+G+r#r#t#t#G#k L L L L N x D@u P L L L L L L L L L L L L L Q J# ", +" O#` P O M L L L L L M M M L L L ..G@t O L L L L t@I@K@K@K@P@P@P@M@M@M@M@L@L@N@N@N@b#8@a#U@Y@Y@Y@+#+#+#+#Z@Z@Z@Z@4#4#4#4#4#`@`@`@X@X@X@X@.#.#.#*#*#*#*#'#'#'#######9#9#9#f#f#f#f#C@C@}#}#}#=#=#=#-#-#-#;#;#q.q.q.q.5#5#>#>#>#(#(#7#7#7#1#1#)#)#)#!#!#|#|#|#2#~#~#~#{#{#]#]#^#^#/#/#a+a+_#_#:#[#[#6#6#c#c#g#h#h#l#n#n#q#I I s#w#y#p.p.H+z#@$T#T#e#e#]@A#B#C#w@0+D#E#E#F#F# $ $Y#G#H#v#I#q@J#t#r#G+G+i#$$B@`#`#Z#K#K#L#p#p#X#X#M#M#M#{@{@k#k#k#k#k#&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$k#k#k#k#k#k#k#k#k#{@{@{@{@{@{@{@{@{@{@M#M#M#M#M#M#M#M#M#M#M#M#M#M#{@{@{@{@{@{@{@{@{@{@{@{@{@{@{@{@k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#{@{@{@{@{@{@{@{@{@M#M#M#M#M#M#X#X#X#X#p#p#p#p#p#L#L#L#K#K#K#K#Z#Z#Z#`#`#`#B@B@B@$$$$$$i#i#i#G+G+G+r#r#t#t#s#C L L L N B S@H L L L L L L L L L L L L L L y ~ ", +" > z@N N L L L L L L L L L L L L M s@H T L L L U u@K@K@K@K@P@P@P@M@M@M@L@L@L@N@O@V@U@K Y@Y@Y@Y@+#+#+#+#+#Z@Z@Z@Z@4#4#4#4#`@`@`@`@X@X@X@.#.#.#.#*#*#*#'#'#'#########9#9#9#f#f#f#C@C@C@}#}#}#=#=#=#-#-#-#;#;#q.q.q.q.5#5#>#>#>#(#(#7#7#7#1#1#)#)#)#!#!#|#|#2#2#~#~#~#{#{#]#]#^#^#/#/#a+a+_#_#:#[#[#6#6#c#c#g#h#h#l#n#n#q#I s#w#w#y#p.p.z#z#@$T##$e#e#A#A#B#C#w@0+D#E#+$F#.$ $Y#G#H#v#v#q@q@J#t#r#G+i#$$$$B@`#Z#K#K#L#p#p#X#X#M#M#{@{@k#k#k#k#&$&$&$&$N#N#N#N#N#N#N#N#N#N#N#N#N#&$&$&$&$&$&$&$k#k#k#k#k#k#k#k#{@{@{@{@{@{@{@{@{@{@{@{@M#M#M#M#M#M#M#M#{@{@{@{@{@{@{@{@{@{@{@{@{@{@{@{@{@{@k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#{@{@{@{@{@{@{@{@M#M#M#M#M#M#X#X#X#X#X#p#p#p#p#p#L#L#L#K#K#K#K#Z#Z#Z#`#`#`#B@B@B@$$$$$$i#i#G+G+G+r#r#r#t#q@4#S L L P &.n P L L L L L L L L L L L L L L 3#+ ", +" d#+#L M L L L L L L L L L L L L L ..t@W L L L l &#x@K@K@K@P@P@P@M@M@M@L@b#@#U@K K Y@Y@Y@Y@+#+#+#+#+#+#Z@Z@Z@4#4#4#4#4#`@`@`@X@X@X@X@X@.#.#.#*#*#*#*#'#'#'#######9#9#9#9#f#f#f#C@C@C@}#}#}#=#=#=#-#-#-#;#;#q.q.q.5#5#5#>#>#>#(#(#7#7#7#1#1#)#)#)#!#!#|#|#2#2#~#~#~#{#]#]#]#^#^#/#/#a+_#_#:#:#[#[#6#c#c#g#g#h#l#l#n#q#I I s#w#y#p.p.H+z#@$T#T#e#e#A#A#B#C#w@0+D#E#+$F#.$ $Y#G#H#v#I#q@J#t#r#G+i#$$$$`#`#Z#K#K#p#p#X#M#M#M#{@k#k#&$&$&$N#N#N#W#W#W#W#W#W#W#V#V#V#V#V#V#W#W#W#W#W#N#N#N#N#N#N#N#N#N#&$k#k#k#k#k#k#k#k#k#k#k#k#{@{@{@{@{@{@{@{@{@{@{@{@{@{@{@{@{@{@{@{@{@{@{@{@{@{@{@{@{@{@k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#{@{@{@{@{@{@{@{@M#M#M#M#M#M#M#X#X#X#X#p#p#p#p#p#L#L#L#K#K#K#K#Z#Z#Z#`#`#`#`#B@B@$$$$$$i#i#i#G+G+G+r#r#t#t#F#a L L T z A L L L L L L L L L L L L L L L l# ", +" v#O L L L L L L L L L L L L L L U t@..M L $.,#&#x@x@K@K@K@K@K@P@N@Q@T@Y@+#+#+#+#+#+#+#+#+#+#Z@Z@4#4#4#4#4#4#4#`@`@`@X@X@X@X@X@X@.#.#.#*#*#*#*#'#'#'#########9#9#9#f#f#f#f#C@C@C@}#}#}#=#=#=#-#-#-#;#;#;#q.q.q.5#5#>#>#>#(#(#(#7#7#7#1#1#)#)#!#!#|#|#|#2#2#~#~#~#{#]#]#]#^#/#/#a+a+_#_#:#[#[#6#6#c#g#g#h#l#n#n#q#I s#s#w#y#p.H+z#z#T#T#e#e#A#A#C#C#0+D#E#+$F#.$ $Y#G#v#v#q@J#t#r#G+i#$$B@`#Z#K#L#p#X#M#{@k#k#&$N#N#W#V#V#U#O#O#O#O#p@v@v@v@v@v@v@v@v@v@v@v@v@v@v@v@v@p@p@p@O#O#O#O#U#U#U#V#V#V#V#W#W#N#N#N#N#N#N#N#&$k#k#k#k#k#k#k#k#k#k#k#{@{@{@{@{@{@{@{@{@{@{@{@{@{@{@{@{@{@{@{@{@{@k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#k#{@{@{@{@{@{@M#M#M#M#M#M#M#M#M#M#X#X#X#p#p#p#p#p#p#p#L#K#K#K#K#K#K#Z#Z#`#`#`#`#`#B@$$$$$$$$$$i#G+G+G+G+r#t#t#t#t#t#/#..N r.s G L L L L L L L L L L L L L L @.R# ", +" ( s@L L L L L L L L L L L L L L N *.C C +.2 J@J@J@J@J@S@S@&#M@U@Z@4#4#4#4#4#4#4#4#4#4#4#4#4#4#4#`@`@`@X@X@X@X@X@X@X@X@.#.#.#.#.#.#*#*#*#*#*#'#'#'#############9#9#f#f#f#f#f#f#f#}#}#}#}#}#}#=#-#-#-#-#-#-#;#q.q.q.q.5#5#5#>#>#>#(#(#7#7#7#1#1#1#)#)#!#!#|#|#|#2#2#~#~#{#{#]#]#^#^#/#a+a+_#_#:#[#[#6#c#c#g#h#h#n#n#q#I s#w#y#p.p.H+z#T#T#e#e#A#A#C#w@0+D#E#+$F# $Y#G#H#v#I#q@t#t#G+i#$$B@`#Z#K#L#p#p#X#M#{@k#k#&$N#N#W#V#V#U#U#U#O#O#O#O#p@p@p@p@p@p@p@p@p@O#O#O#O#O#O#O#O#U#U#U#V#V#V#V#V#W#W#W#N#N#N#N#N#N#N#N#N#N#&$&$&$&$N#&$&$&$&$&$N#N#N#N#N#N#N#N#N#N#N#N#N#W#W#W#W#W#W#V#V#V#V#V#V#V#V#V#V#V#V#V#V#V#V#V#W#W#W#W#W#W#N#N#N#N#N#N#&$&$&$k#k#k#k#{@{@{@M#M#M#M#X#p#p#p#p#L#L#K#K#K#K#Z#`#`#`#B@B@B@$$$$$$i#G+G+G+G+G+r#t#t#t#J#J#q@q@q@I#I#v#v#v#H#H#G#F#F@F @.r V L L L L L L L L L L L L L L 7 * ", +" + ,#L L L L L L L L L L L L L L L &.a [ s@ #.@.@.@,#H@J@J@S@N@*#f#f#f#f#f#f#f#f#f#f#f#f#f#f#f#f#f#f#f#f#f#f#C@C@C@C@C@C@C@}#}#}#}#}#}#=#-#-#-#-#-#-#;#;#;#q.q.q.q.5#>#>#>#>#>#(#(#(#(#7#7#7#7#1#)#)#)#)#)#!#!#|#|#|#2#2#2#~#~#~#{#{#]#]#^#]#/#/#/#/#a+a+_#:#[#[#6#6#c#c#g#g#h#h#l#l#n#n#q#I I I w#w#w#y#p.p.H+z#z#@$T#T##$e#]@]@A#B#w@0+0+D#E#+$F#F#.$ $Y#G#H#v#v#I#q@J#t#t#r#G+i#$$$$`#`#Z#K#L#p#M#{@k#k#&$N#N#W#V#U#U#O#O#v@v@%$y@P#Q#Q#_ _ S#x#x#u#/ / =.^ ^ -$] ] { ( m#m#*$=$~ ~ ~ ~ ! ! ) ) ) ) ) ' 8#8#, , ; ; ; - - > > > > = j#j#j#j#* * & & & & % % o#o#o#o#o#$ $ $ $ # # # # # # # # # # # # # # # $ $ o#o#o#o#% % & & & * * j#j#j#= > > > - ; ; ; ; ; , 8#8#8#' ) ! ~ *$m#( ( { ] -$^ =./ u#x#S#_ Q#P#R#y@y@%$v@p@O#O#U#V#W#W#N#&$&$k#{@M#M#X#X#p#A#i 8 p O L L L L L L L L L L L L L L 4#J ", +" q#L L L L L L L L L L L L L L L T z +.s@%#u@u@u@ #E@.@I@M@8@K 9#7#^#:#6#c#c#c#c#c#c#c#c#c#c#c#c#c#c#c#c#g#g#g#h#h#h#h#h#h#h#l#l#n#n#n#n#n#q#I I I I I s#w#w#w#w#y#p.p.p.p.H+H+z#z#z#@$T#T#T##$#$e#e#]@]@A#A#B#B#C#C#w@w@0+0+D#D#E#E#+$F#F#.$.$ $Y#Y#G#G#H#v#v#I#q@q@J#t#t#r#G+G+i#$$$$B@`#Z#Z#K#L#p#p#X#M#M#k#k#&$N#N#V#V#U#O#O#v@v@%$y@R#P#P#_ _ S#x#u#/ =.^ ^ ] ] ( ( m#*$=$~ ! ) ' 8#, ; - > = j#* & % o#$ # @ + 9@. . d#d#J J J J d#. + + # o#% & j#= > - ; 8#' ) ! ~ =$*$m#( { ] ] ^ ^ / N#u@u ..L L L L L L L L L L L L L L Q J# ", +" %$+.L L L L L L L L L L L L L L L L L $.z@a } [ < < i i i j A@3#0#P@U@##1#_#l#s#w#y#y#y#y#y#y#y#y#y#p.p.p.p.p.p.p.H+H+H+H+z#z#z#z#@$@$@$T#T#T##$#$#$e#e#e#]@]@A#A#A#B#B#C#C#C#w@0+0+0+D#D#E#E#+$+$F#F#.$.$ $Y#Y#G#G#H#H#v#v#I#q@q@J#t#t#r#G+G+i#$$$$B@`#`#Z#K#K#L#p#p#X#M#M#k#k#&$N#N#W#V#U#O#O#p@v@%$y@y@R#P#Q#_ _ x#x#u#/ =.^ -$] { ( ( m#*$=$~ ! ) ' 8#, ; - > = j#* & % o#$ # @ + 9@. . d#J J J . 9@+ # $ o#& & j#= > - ; 8#8#) ) ~ ~ =$m#y@F#)#o L L L L L L L L L L L L L L L L y ~ ", +" & d L L L L L L L L L L L L L L L L L L L O W @.D A s n 4 3 2 c e | } g k <#&#R@=#]#h#H+T#e#e#e#e#e#e#e#]@]@]@]@]@A#A#A#A#B#B#B#B#C#B#B#C#C#C#C#w@w@0+0+0+D#D#E#E#E#+$+$F#F#.$.$ $ $Y#Y#G#G#H#H#v#v#I#q@q@J#J#t#r#r#G+G+i#$$$$B@`#`#Z#K#K#L#p#p#X#M#{@{@k#&$N#N#W#V#U#O#O#p@v@v@y@y@R#P#Q#_ _ x#x#u#/ =.^ ^ ] ] ( ( m#*$=$~ ! ) ' 8#, ; - > = j#* & % o#$ # @ + 9@. d#J J J . 9@+ @ # $ o#& & j#= > - 8#! =$*$m#( ] v@e#+#| G L L L L L L L L L L L L L L L L L 3#+ ", +" J -#L L L L L L L L L L L L L L L L L L L L L L L L L L L R V Z +.D z p 4 b } [ D@E@H@Q@.#|#I C#G#t#G+G+G+G+G+G+r#t#J#q@I#H#G# $F#D#w@C#C#C#C#w@w@0+0+0+0+D#E#E#E#E#+$F#F#F#.$ $ $ $Y#G#G#G#H#v#v#v#I#q@q@J#J#t#t#r#G+G+i#$$$$B@`#`#Z#K#K#L#p#p#X#M#M#{@k#&$N#N#W#V#V#U#O#p@v@v@%$y@R#P#P#_ _ S#x#u#/ / =.^ -$] { ( m#*$=$~ ! ! ) ' 8#, ; - > = j#* & % o#$ # @ + 9@. J J J J . 9@+ # $ o#% & * j#> ; *$/ y@W#M#v#^#0#x R L L L L L L L L L L L L L L L L L L L l# ", +" i#Q L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L M U Z G C y z@2 i 3#S@R@C@_#T# $G+Z#L#K#B@G+t#I#H# $F#D#C#A#]@]@A#A#A#A#B#B#C#C#C#C#w@w@0+0+D#D#D#E#E#+$+$F#F#.$.$ $ $Y#Y#G#G#H#H#v#v#I#q@q@J#t#t#r#r#G+G+i#$$$$B@`#`#Z#K#K#L#p#X#X#M#{@{@k#&$N#N#W#V#U#O#O#p@v@%$y@y@R#P#Q#_ _ S#x#u#/ / ^ ^ ] ] { ( m#*$*$~ ~ ) ) 8#8#; ; - > = j#* & % o#$ # + + . d#J J J J . + @ # o#% & * j#> ; *$u#v@r#)#} @.L L L L L L L L L L L L L L L L L L L L L @.R# ", +" ) t L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L N V ..%.r@v 7 [ G@T@-#_#H+w@+$F#+$0+C#]@T#T#T#T#T##$#$#$e#e#e#]@]@]@A#A#B#B#B#C#C#w@w@0+0+0+D#D#E#E#+$+$F#F#.$.$ $ $Y#G#G#H#H#v#v#I#q@q@J#J#t#r#r#G+G+i#$$$$B@`#`#Z#K#K#L#p#p#X#M#M#k#k#&$N#N#W#V#V#O#O#p@v@v@y@y@R#P#P#_ _ S#x#u#/ / ^ ^ -$] { ( m#*$=$~ ! ) ) ' 8#, ; - > = j#* & o#o## # + 9@. d#J J J . 9@@ # o#% & j#= > - 8#^ `#}#l T L L L L L L L L L L L L L L L L L L L L L L L 7 * ", +" . P@L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L P V ` E x 7 i G@V@##5#q.=#=#=#=#-#-#-#-#-#-#;#q.q.q.q.q.5#5#5#>#>#>#>#(#7#7#7#7#1#1#)#)#)#)#!#|#1#7#1#1#)#)#)#!#|#|#|#2#2#~#~#~#{#]#]#]#^#^#/#/#a+_#_#_#:#:#_#/#/#a+a+_#_#:#[#[#6#6#c#c#g#h#h#h#[#6#6#c#c#g#h#h#l#n#n#q#I I I w#w#y#y#p.p.H+z#@$@$T##$e#e#]@A#A#B#C#C#A#e#e#]@A#A#B#C#w@0+0+D#E#+$F#F#.$ $Y#G#H#v#I#q@q@t#t#G+G+i#i#$$$$$$B@B@`#`#`#Z#Z#K#$$$$$$$$$$B@B@`#`#`#Z#Z#K#K#K#K#L#L#p#p#p#p#X#X#M#M#M#{@{@k#k#k#M#K#K#K#L#L#L#p#p#p#p#p#p#p#`#i#i#i#i#i#i#i#i#G+G+G+G+G+G+G+r#r#r#t#t#t#t#J#J#q@q@q@I#I#v#v#v#H#H#G#G#Y#Y# $ $ $.$F#w@A#e##$T#z#H+p.y#w#I q#n#l#h#g#6#[#:#_#a+/#/#]#]#{#~#2#|#|#!#)#)#7#7#7#-#j H L L L L L L L L L L L L L L L L L L L L L L L L L L 4#J ", +" z#L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L M M L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L M M M N N N N O P P Q R R R S T V W X Z ...+.#.G $.F %.E C C &.B *.H H r@s@s@-.t@A A A t@t@t@t@-.s@s@r@H *.B &.C D E %.F $.G @.+... .` Z Y X W r.U T R Q Q P O N N N M M M L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L Q J# ", +" _ %.L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L M M M M N N N O P P Q R S T U r.W X Y Y ` ` ....@.@.G G F F E E D C &.B B *.H H H r@r@r@s@s@s@r@r@r@H H *.*.B &.C C E E %.F G G @.@.....` ` Y Y X r.V T S R Q P P O N N N M M M L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L y ~ ", +" o#} L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L M M M M N N N O O P Q R R T T V r.W X Y Z ` ` ....@.@.#.G $.F F %.E D C C C &.&.B B B B B B B B B &.&.C C D E E %.F $.G #.@.@.....` ` Y Y X W r.U T S R Q P O O N N M M M M L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L 3#+ ", +" J >#L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L M M M M N N N O O P P Q R S T U V W X Y Y Z ` ` ....+.@.@.G G $.F F F %.E E E E D D D D D D E E E E %.%.F F $.G G @.@.+.....` ` Y Y X W r.V T S R Q P P O O N N M M M M L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L I ", +" p#V L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L M M M M N N N O P P Q R R S T V r.W X Y Y Y ` ` .....+.@.@.#.G G G $.F F F F F F F F F F F F $.G G G #.@.@.+..... .` ` Y Y X W r.V U T R R Q P P O N N N M M M M L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L +.R# ", +" ; p L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L M M M M N N N O O P P Q R R T T V r.W W X Y Y Z ` ` .......+.@.@.@.@.#.G G G G G G G G #.@.@.@.@.+....... .` ` Z Y Y X W r.V U T S R Q P P O O N N N M M M L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L 7 * ", +" . 8@L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L M M M M M N N N O O P P Q R R T T U V r.W X Y Y Y Z ` ` ` .............+.+.@.@.+.+............. .` ` ` Z Y Y X X W r.V U T S R Q P P O O N N N M M M M L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L `@J ", +" E#L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L M M M M N N N N O P P P Q R R S T U V r.W W X Y Y Y Y Y ` ` ` ` ` ` ` ` . .` ` ` ` ` ` ` ` Y Y Y Y X W W r.V V T T S R R Q P P O N N N N M M M M L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L P G+ ", +" ] H L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L M M M M N N N N O P P P Q R R S T T U V r.r.W W X X Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y X X W W r.V V U T T R R Q P P P O O N N N M M M M L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L y ~ ", +" # j L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L M M M M M N N N N O O P P Q Q R R S T T U V V V r.W W W W W W X X X X X X W W W W W W r.V V U T T T R R R Q P P P O O N N N M M M M L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L E@+ ", +" J _#L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L M M M M M N N N N O O P P P P R R R R S T T T U U V V V V V V V V V V V V V U U T T T S S R R R Q P P P O O N N N N M M M M L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L I ", +" O#Z L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L M M M M M N N N N N N N N N O O O O O O O O O O O O O O N N N N N N N N M M M M M L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L +.P# ", +" j#a L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L h % ", +" J {#O L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S R Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y X ..+.+.+.+.+.+.+.+.+.G F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F E C C C C C C C C C C C C C C C C C C C C C C C C C C C C C B s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@s@-.z z z z z z z z z v t t t t t t t t t t t t t t t q 3 w# ", +" ; &$t#q@q@q@q@q@q@q@q@q@B#Y@B#q@q@q@q@q@q@q@q@q@q@q@q@q@q@q@q@q@q@q@q@q@q@q@q@q@q@q@q@q@q@q@q@q@q@q@q@q@q@q@q@q@q@q@q@q@q@q@q@q@q@q@q@q@q@q@q@G+$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$M#&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$&$N#O#O#O#O#O#O#O#O#O#O#O#O#O#O#O#O#O#O#O#O#O#O#O#O#O#O#O#O#O#O#O#O#O#O#O#O#O#O#O#O#O#O#O#O#O#O#O#O#O#O#v@R#R#R#R#R#R#R#R#R#R#R#R#R#R#R#R#R#R#R#R#R#R#R#R#R#R#R#R#R#R#R#R#R#R#R#R#S#x#x#x#x#x#x#x#x#x#=.^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ] ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( =$=$=$=$=$=$=$=$=$=$=$=$=$=$=$=$=$=$=$~ ) ) ) ) ) ) ) ) ) 8#, , , , , , , , , , , , , , , - % . ", +" 5#2#r U@[ R# ", +" k s@p $#s A@) ", +" X#i v A@-#X#A@c# ", +" X#.@z G# $#v R# ", +" X#0#K n#u@G# X#X#^#^# ", +" X#3#-# G#i ) X#^#X#X#X#X# ", +" G#| G# n#l X#T#T#X# X#X# ", +" ) ) ) ) ) ) ) ) ) G#5 #$) ) ) c {#) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) R#G#5#G#R#) ) ) ) ) G#G#) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ", +" T#T#T#T#T#T#T#T#T#T#s $#T#T#u 9 T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#a#c#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#a#c#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#c#a#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#;$>$,$,$y#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#-#-#T#T#T#T#T#T#T#T#T#T#T#T#c#a#a#-#T#T#T#T#T#T#T#T#-#-#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#a#c#T#T#T#T#T#T#T#T#T#T# ", +" ) d !# n n ) T#) '$)$ T#) !$~$,$,${$ ]$,$>$^$/ !$/$,$,$($;$= B@_$,$,$:$<$[$}$|$1$. !$/$,$,$($;$= ) T# %$/$,$,$:$2$3$4$5$% = ,$6$ X#X# ) T#T#) X#X# T#) ", +" a#n $.b -# T#) 7$8$9$ T#) . ,$,$0$ ] a$,$b$ 9@,$,$=. 9@,$a$+ c$d$,$^$9@ 9@,$,$=. ) T# . ,$a$+ e$,$f$ g$,$h$ X#X# ) T#T#) ^# T#) ", +" ) ) ) ) ) ) ) ) R#C@G A 5 G#) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) c#R#) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ~ i$,$j$! ) ) ) ) ) ) c#R#) ) ) S#k$,$,$S#) ) ) ) ) ) l$m$,$u#) ) ) ) ) ) ) ) n$,$m$! ) ) ) ) ) ) ) ) n$,$o$) ) ) ) ) p$,$q$) ) ) ) ) ) ) ) n$,$m$! ) ) ) ) ) ) ) ) R#c#) ) ) ) ) ) ) ) ) Q#,$o$) ) ) ( ,$a$! ) ) ) ) ) ) r$,$s$) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) G#G#) ) ) ) ) ) ) G#c#R#) ) ) ) ) ) ) ) ) ) ) ) ) G#G#) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) c#R#) ) ) ) ) ) ) ) ) ) ", +" T#T#T#T#T#T#T#`@r T S G T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#a#c#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#t$u$,$,$l#T#T#T#T#T#T#a#c#T#T#T#v$0$j$,$w$T#T#T#T#T#x$2$8$y$T#T#T#T#T#T#T#T#T#f$,$z$T#T#T#T#T#T#T#T#T#A$,$B$T#T#T#T#T#d$,$C$T#T#T#T#T#T#T#T#f$,$z$T#T#T#T#T#T#T#T#T#c#a#T#T#T#T#T#T#T#T#T#D$,$B$T#T#T#H+,$,$@$T#T#T#T#T#T#E$,$[#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#-#-#T#T#T#T#T#-#S@-#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#S@T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#a#c#T#T#T#T#T#T#T#T#T#T# ", +" `@8 Q W b '#X# T#) > F$+ 4$,$K# T#) G$]$d$,$H$ o#x$S#,$I$ J$,$q$ s$,$G$ @ ,$a$J J$,$q$ ) T# K$,$G# -$,$o$ 9@k$a$L$ M$,$,$v$ . N$,$E$ J O$_$P$y$,$,$,$Q$+ X#X# ) T#X# X#X# T#) ", +" T#5 l +.G#R#-#K ) T#) h$R$ x$,$S$ T#) T$U$V$,$<$ H$W$X$,$Y$ Z$,$b$ `$,$v@ d#,$,$9@ Z$,$b$ ) T# d$,$%$ %,$J$ / ,$_$ d#a$,$K$ o#,$w$ .%8$!$ +%8$J#P#@% X#X# X#T#) ^# ) X#X#X# T#) ", +" ) ) ) ) ) 5#6 ` #$) c#X@5 $#g#) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) c#R#) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) #%l$) ) $%,$%%) ) ) ) ) ) c#R#) ) ) &%*%=%,$-%*$) ) v@{$) ;%,$U$) ) ) ) ) ) ) ) ) [$,$R$) ) ) ) ) ) ) ) ) >%,$/ ) ) ) ) ) u#,$,%) ) ) ) ) ) ) ) [$,$R$) ) ) ) ) ) ) ) ) R#c#) ) ) ) ) ) ) ) ) '%,$=.) ) =%k$z$( ) ) ) ) ) ) Y$,$d$) ) ) ) ) ) ) x#,$,$)%) ) {@,$]$) ) ) ) ) ) !%,$f$) ) -$,$Q$) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) G#G#) ) G#) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) G#G#) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) R#5#c#G#I@#$) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) c#R#) ) ) ) ) ) ) ) ) ) ", +" T#T#T#T#T#.@F 9 c#P@2 p y u@s $#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#a#c#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#z#~%5$T#T#D$,$a$z#T#T#T#T#T#a#c#T#T#@$a$H+@$a$,$6#T#T#3$s#T#{%,$]%T#T#T#T#T#T#T#T#H+8$8$z#T#T#T#T#T#T#T#T#s#,$^%T#T#T#T#T#T#:#,$>%T#T#T#T#T#T#T#H+8$8$z#T#T#T#T#T#T#T#T#T#c#a#T#T#T#T#T#T#T#T#z#8$y$T#H+!#k$4$5$T#T#T#T#T#T#T#/%,$(%T#T#T#T#T#T#T#:#,$,$y#T#T#7#,$A$T#T#T#T#T#T#Q$,$/#T#T#q#,$-%T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#-#-#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#c#a#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#-#a#T#T#c#-#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#a#c#T#T#T#T#T#T#T#T#T#T# ", +" -#..X@) | {#X#'#X#-#i T#) _%s$ = ,$,$7$ T#) { 6$ ^$,$:% <%G# d#[%}% @%,$u$ U#,$x$ G$,$$% @%,$u$ ) T# ^ ,$}$^$P$|%{@d# 1%,$] 2%,$[$ .%,$3% 4$,$4% g$,$5% X#X# ^# X#^#X# X#T#T# T#) ", +" G#+.R# I@{#) c#T# n R# T#) ) o$@ 6%,$1$ T#) #%Z$ 7%,$8%# 5%. m#,$x$ U$,$d$ 9%,$0% 2$,$=. U$,$d$ + 9$;$:$a%l$@ b%,$S$ & ,$^%d# 0%,${$ B$}$ c%,$% ;$a$S# X#X# X#X# X#^#X# X#^#X#) T#) ", +" ) ) ) ) ) ) v }#) |#x K M@c#R#8 R#) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) c#R#) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ;$d%_$_$_$_$_$}$,${$) ) ) ) ) c#R#) ) ]%e%) ) U$,$E$'$K#) ) :%,$'$) ) ) ) ) ) ) ) ) .%,$q$) ) ) ) ) ) ) ) ) f%,$g%) ) ) ) ) %$8$|$) ) ) ) ) ) ) ) .%,$q$) ) ) ) ) ) ) ) ) ) R#c#) ) ) ) ) ) ) ) 5$,$J$) ) ) ) ) ) ) ) ) ) ) ) `#,$/$) ) ) ) ) ) ) ) h%,$q$) ) { 8$P$) ) ) ) ) ) ) i%>%r#! %a$G$) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) G#G#) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) G#G#) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) R#c#G#) R#c#G#) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) c#R#) ) ) ) ) ) ) ) ) ) ", +" T#T#T#T#T#T#9 } -#T#`@x l a#T#v !#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#a#c#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#A$j%T#T#T#T#T#T#(%,$m$T#T#T#T#T#a#c#T#T#[$]#T#T#w#,$,$&%T#T#T#k%,$A$T#T#T#T#T#T#T#T#T#0$,$D$T#T#T#T#T#T#T#T#T#>$,$l%T#T#T#T#T#3$a$l#T#T#T#T#T#T#T#T#0$,$D$T#T#T#T#T#T#T#T#T#T#c#a#T#T#T#T#T#T#T#T#6%,${$T#T#T#T#T#T#T#T#T#T#T#T#m%,$F$T#T#T#T#T#T#T#T#>%,$a+T#T#:#,$k%T#T#T#T#T#T#T#T#c#~%Q$B$n%T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#-#-#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#S@T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#-#a#!#-#a#a#c#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#a#c#T#T#T#T#T#T#T#T#T#T# ", +" G#i '#X# ) S@) 2 ) T#) o#(%# c$,$8$o# T#) E$! 6$^%, o%,$! J }$,$3% * ,$-%d# G$8$K# J }$,$3% ) T# 4$,$, `$,$<% >$,$4% p%,$q% r%m$3% X#X# ^# X#5#n#T#T#X#) T#) ", +" *#| X# G#`@a#a# T#) Z$x# 9@,$,$K# T#) 3%,$9@ l%9% + ^%,$9@ @%,$,$. #%,$4$. 3%s%>$<% @%,$,$. ) T# t%,$,$. d#}$,$= ,%,$N#v@p%P$,$t% E$,$N#=$; J X#X# X#X# ) n#S@K T#X#) ) X#X#T#^#^#^#^#^#^#^#K ^# T#) ", +" ) ) ) ) ) ) ) ) G#m b b A@$.S@) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) c#R#) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) R$6$,$u%) ) ) ) ) ) `#o$,$,$^%J#) ) ) c#X#:$>%,$i$2%) ) ) ) ) ) v%'%,$,$j%F#) ) ) ) ) S#:$}$,$,$i$b$) ) ) ) ) &$w%^%,$,$E$x%u$N$$%/ ) ) ) ) ) ) ) ) S#:$}$,$,$i$b$) ) ) ) ) ) ) ) ) R#c#) ) ) ) ) x#:$m$,$,$N$F#) ) ) ) ) ) ) ) ) 9%o$,$,$y%s$) ) ) ) ) ) ) ]$^%>%z%{ '%,$z$u#) ) ) ) ) ) [$,$,$,$,$j$s$) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) G#G#) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) G#G#) ) ) ) ) ) ) ) R#G#G#c#5#.@3#*#5#5#5#5#c#G#G#R#) ) ) ) G#c#5#G#) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) c#R#) ) ) ) ) ) ) ) ) ) ", +" T#T#T#T#T#T#T#T#T#c#$#A@d 4 T#T#T#T#z#g#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#a#c#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#a#c#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#c#a#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#s#[$u$@$T#@$A$,$-%T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#-#-#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#S@a#S@S@S@S@S@S@a#-#-#c#T#T#T#T#T#T#T#T#T#T#T#T#T#T#-#S@-#c#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#T#a#c#T#T#T#T#T#T#T#T#T#T# ", +" ) P@) X#J@A# u%,$; { ,$^$ ) T#X# ", +" } n#X#h < N@ 4$,$U# ~ N$B$3% X#K ) ) X#X#X#X#X#X#X#X# ", +" u@n# A@i G@G# 7$`$}$/$9$9$1$9@ X#K ^#^#T#X#X#X#X#X#X#-#X#X#X#X#X#X#X#X#X#X#X#X# ", +" S@5 `@-#c#|# X#G#^#X#X#X#X#X#X#X#X#X#X#X#T#) ", +" X#K k ) c#P@) ) T#^#X#X# ", +" n#U@`@ R#8 X#X#T# ", +" X#N@v `@R#) 8 `@ ) ", +" n#I@x g G@6 X# ", +" 6#s# ", +" ", +" ", +" "};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/amidi-plug/amidi-plug.midiicon.xpm Thu Jan 26 18:43:59 2006 -0800 @@ -0,0 +1,312 @@ +/* XPM */ +static char * amidiplug_xpm_midiicon[] = { +"48 52 257 2", +" c None", +". c #000000", +"+ c #232323", +"@ c #1F1F1F", +"# c #DADADA", +"$ c #FFFFFF", +"% c #F6F6F6", +"& c #CFCFCF", +"* c #707070", +"= c #FEFEFE", +"- c #FBFBFB", +"; c #EDEDED", +"> c #C0C0C0", +", c #F7F7F7", +"' c #D7D7D7", +") c #F1F1F1", +"! c #B7B7B7", +"~ c #D2D2D2", +"{ c #AEAEAE", +"] c #070707", +"^ c #646464", +"/ c #FDFDFD", +"( c #B8B8B8", +"_ c #DCDCDC", +": c #A4A4A3", +"< c #0E0E0E", +"[ c #3A3A3A", +"} c #454545", +"| c #4E4E4E", +"1 c #BFBFBF", +"2 c #F5F5F4", +"3 c #B5B5B5", +"4 c #F9F9F9", +"5 c #FCFCFC", +"6 c #CBCBCB", +"7 c #A5A5A5", +"8 c #505050", +"9 c #424242", +"0 c #434343", +"a c #959595", +"b c #F4F4F4", +"c c #ACACAC", +"d c #ECECEC", +"e c #C3C3C3", +"f c #C2C2C2", +"g c #C9C9C8", +"h c #A8A8A8", +"i c #787878", +"j c #464646", +"k c #FCFCFB", +"l c #F4F4F3", +"m c #ABABAB", +"n c #515151", +"o c #474747", +"p c #464645", +"q c #5D5D5C", +"r c #A9A9A9", +"s c #777777", +"t c #FDFDFC", +"u c #FAFAFA", +"v c #F2F2F2", +"w c #F3F3F3", +"x c #AAAAAA", +"y c #A0A09F", +"z c #8A8A8A", +"A c #7A7A7A", +"B c #6C6C6C", +"C c #5A5A5A", +"D c #A4A4A4", +"E c #A2A2A2", +"F c #9F9F9F", +"G c #949494", +"H c #484848", +"I c #818181", +"J c #A3A3A3", +"K c #A1A1A1", +"L c #B2B2B2", +"M c #393939", +"N c #9C9C9C", +"O c #767676", +"P c #E7E7E7", +"Q c #C6C6C5", +"R c #BABAB9", +"S c #6B6B6B", +"T c #FAFAF9", +"U c #F8F8F7", +"V c #686867", +"W c #F6F6F5", +"X c #F5F5F5", +"Y c #EDEDEB", +"Z c #9D9D9D", +"` c #A3A3A2", +" . c #535353", +".. c #393938", +"+. c #9B9B9A", +"@. c #9E9E9E", +"#. c #676767", +"$. c #B1B1B1", +"%. c #6A6A6A", +"&. c #FBFBFA", +"*. c #F9F9F8", +"=. c #383838", +"-. c #676766", +";. c #F3F3F2", +">. c #B3B3B3", +",. c #A1A1A0", +"'. c #A2A2A1", +"). c #747474", +"!. c #AFAFAE", +"~. c #666666", +"{. c #F2F2F1", +"]. c #696969", +"^. c #F8F8F8", +"/. c #F1F1F0", +"(. c #939392", +"_. c #9C9C9B", +":. c #9E9E9D", +"<. c #777776", +"[. c #F2F2F0", +"}. c #F0F0F0", +"|. c #F7F7F6", +"1. c #F0F0EF", +"2. c #EFEFEE", +"3. c #EFEFED", +"4. c #F3F3F1", +"5. c #F1F1EF", +"6. c #EEEEED", +"7. c #EEEEEC", +"8. c #383837", +"9. c #373737", +"0. c #EEEEEE", +"a. c #EDEDEC", +"b. c #EFEFEF", +"c. c #ECECEB", +"d. c #373736", +"e. c #F0F0EE", +"f. c #363636", +"g. c #EBEBEA", +"h. c #606060", +"i. c #B0B0AF", +"j. c #8F8F8F", +"k. c #B6B6B6", +"l. c #999998", +"m. c #9D9D9C", +"n. c #9B9B99", +"o. c #999999", +"p. c #9A9A99", +"q. c #B1B1B0", +"r. c #8A8A89", +"s. c #616160", +"t. c #EAEAE9", +"u. c #EAEAE8", +"v. c #ECECEA", +"w. c #555555", +"x. c #E9E9E8", +"y. c #E9E9E7", +"z. c #9F9F9E", +"A. c #737373", +"B. c #B5B5B4", +"C. c #737372", +"D. c #B4B4B3", +"E. c #8C8C8B", +"F. c #AAAAA9", +"G. c #959594", +"H. c #979797", +"I. c #A7A7A7", +"J. c #989898", +"K. c #898988", +"L. c #626261", +"M. c #363635", +"N. c #EBEBE9", +"O. c #E8E8E7", +"P. c #E8E8E6", +"Q. c #9B9B9B", +"R. c #8D8D8C", +"S. c #717170", +"T. c #979796", +"U. c #B3B3B2", +"V. c #898989", +"W. c #70706E", +"X. c #929291", +"Y. c #949493", +"Z. c #616161", +"`. c #E7E7E6", +" + c #E6E6E4", +".+ c #6D6D6C", +"++ c #9A9A9A", +"@+ c #969696", +"#+ c #989897", +"$+ c #969695", +"%+ c #6C6C6B", +"&+ c #E5E5E4", +"*+ c #E7E7E5", +"=+ c #E5E5E3", +"-+ c #E4E4E2", +";+ c #B1B1AF", +">+ c #353535", +",+ c #BAB8B4", +"'+ c #6E6B62", +")+ c #565248", +"!+ c #23211D", +"~+ c #4F4F4F", +"{+ c #949492", +"]+ c #A7A7A5", +"^+ c #989896", +"/+ c #A5A5A3", +"(+ c #E6E5E4", +"_+ c #625E55", +":+ c #9C9A94", +"<+ c #D8D7D5", +"[+ c #89867F", +"}+ c #626262", +"|+ c #E6E6E5", +"1+ c #D7D6D3", +"2+ c #5A564D", +"3+ c #656259", +"4+ c #F5F4F4", +"5+ c #69655C", +"6+ c #D5D4D1", +"7+ c #8F8D86", +"8+ c #A7A7A6", +"9+ c #888887", +"0+ c #868685", +"a+ c #353534", +"b+ c #959593", +"c+ c #CCCBC8", +"d+ c #C4C2BF", +"e+ c #C4C3BF", +"f+ c #716D65", +"g+ c #E3E2E0", +"h+ c #67635A", +"i+ c #67645B", +"j+ c #59564C", +"k+ c #6E6E6D", +"l+ c #919190", +"m+ c #ACACAB", +"n+ c #6D6D6D", +"o+ c #90908F", +"p+ c #8B8881", +"q+ c #C0BEBA", +"r+ c #8C8982", +"s+ c #706D64", +"t+ c #E0DFDD", +"u+ c #E4E4E3", +"v+ c #DDDDDB", +"w+ c #68645C", +"x+ c #D3D2D0", +"y+ c #8B8882", +"z+ c #F7F6F6", +"A+ c #85827B", +"B+ c #E3E3E1", +"C+ c #A3A3A1", +"D+ c #8D8D8D", +"E+ c #E3E3E2", +"F+ c #E2E2E0", +"G+ c #E1E1DF", +"H+ c #8C8C8C", +" . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + @ ", +". # $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ % & * . ", +". $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ = = = = = = = = = = = = - % ; > . ", +". $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ = = = = = = = = = = = = = = , ' $ ) ! . ", +". $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ = = = = = = = = = = = = = = = = , ~ $ $ ; { ] ", +". $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ ^ > = = = = = = = = = = = = = = / / % ( $ / $ _ : < ", +". $ $ $ $ $ $ $ $ $ $ $ $ $ $ = = [ } | 1 = = = = = = = [ [ [ [ [ [ / 2 3 $ 4 5 $ 6 7 . ", +". $ $ $ $ $ $ $ $ $ $ $ $ = = = = [ > 8 9 0 a = = = / / [ [ [ [ [ [ 5 b c d e 6 ( f g h . ", +". $ $ $ $ $ $ $ $ $ $ [ = = = = = [ = = 1 i j / / / / / [ 5 5 5 5 [ k l m n o p j j q r . ", +". $ $ $ $ $ $ $ $ = = [ = = = = = [ = / / / s / t 5 5 5 [ 5 5 k - [ u v w > x y z A B } . ", +". $ $ $ $ $ C D D D E [ F D D D E [ D G G G H G I J J K [ J J J L M N E J O , P Q g R A . ", +". $ $ $ $ = S = = = = [ / / / / / [ 5 5 5 5 [ 5 k - - - [ - T 4 4 M 4 , U V W X X X Y r . ", +". $ $ = = = S E D D F [ D D J s [ [ J J J K [ Z J J ` .M N E F M ..+.F @.#.X 2 2 w w $.. ", +". $ = = / / %./ / / t [ 5 5 5 [ [ [ - - - - [ &.u u M M M *.*.=.=.=.% 2 2 -.b l w ;.;.3 . ", +". $ / / / / %.K J @.[ [ >.J J s [ K J ` ,.M M N E '.O M @.F F ).=.!.@.@.@.~.;.;.;.{.{.3 . ", +". $ / t 5 5 ].5 5 [ [ [ - - - &.&.u u u M M M *.^.^.^., W W W 2 b b l l ;.~.v v {././.3 . ", +". $ 5 5 5 5 (.J J s [ s ` ` E E E E E E _.M @.K K y F F F F @.:.:.:.Z Z Z <.[././.}.}.3 . ", +". $ k k - - - - &.&.u u u u u T T 4 ^.^.^.U U |.X X X 2 l l l w ;.{.{.{.{.[.}.}.1.2.3.3 . ", +". $ - - - &.&.u u u u T T T 4 4 ^.^.U U , % X X 2 2 l w w w 4.{.{.{.) /.5.1.1.2.6.6.7.3 . ", +". $ &.u u u u u T T 4 M M M M M M , , % 2 2 2 b l w ;.;.8.9.9.9.9.9.5.1.1.0.0.6.7.a.a.3 . ", +". $ u u T T 4 4 4 4 4 M M M M M ..W W 2 b b b ;.;.;.;.{.9.9.9.9.9.9.b.6.6.6.7.a.a.d c.3 . ", +". $ T 4 4 4 4 *.*.^., M , |.|.W =.b b l l ;.;.9.v {././.9./.1.1.2.d.6.6.7.a.Y Y c.c.c.3 . ", +". $ 4 *.*.*.^.^., |.|...|.X X b =.l l ;.v v {.9.[./.}.}.9.e.2.6.6.f.a.a.Y Y c.c.g.g.g.3 . ", +". $ ^.^.^.^.h.i.y F j.=.k.:.:.:.=.l.Z m.m.m.n.9.o._._.l.9.p.o.o.q.f.r.l.l.s.g.g.g.t.u.3 . ", +". $ U |.|.|.#.% % 2 2 =.l w w ;.9.{.{.) /.5.1.9.1.1.2.7.f.a.a.a.Y f.v.v.g.w.g.t.x.x.y.3 . ", +". $ % % % W #.).z.A.=.=.B.Z C.9.9.D.N _._._.E.9.F.p.G.f.f.H.l.G f.f.I.J.K.L.x.x.y.y.y.3 . ", +". $ W W W 2 ~.b ;.8.8.8.{.) 9.9.9.5.1.b.2.2.2.d.7.a.f.f.f.c.v.f.f.M.N.x.x.L.x.y.O.O.P.3 . ", +". $ X b l l ~.l.Z Q.9.R.N N m 9.E.+.+.+.+.S.f.f.T.U.V.f.l.J.J.W.M.X.T.T.Y.Z.O.O.P.P.P.3 . ", +". $ l l ;.v ~.{.{./././.}.1.1.2.2.2.0.a.a.f.f.f.c.c.g.g.g.N.N.x.y.y.O.O.O.^ P.`.`.`. +3 . ", +". $ v {.{.{..+N N N _._._.+.+.++p.o.o.l.l.V.f.@+J.J.J.#+#+T.T.T.T.@+$+$+$+%+`.`. + +&+3 . ", +". $ {.{.{./.1.1.1.1.1.2.3.6.6.a.a.Y c.v.v.g.g.g.g.t.t.x.y.y.y.P.P.P.P.`.`.*+ +&+&+&+&+3 . ", +". $ ) /.1.1.1.1.2.2.3.6.6.a.a.c.c.v.v.g.g.N.t.t.t.x.y.y.O.P.P.P.P.`.*+*+ + +&+&+=+=+=+3 . ", +". $ 1.1.b.2.2.2.3.6.6.f.c.c.c.v.v.f.N.N.t.t.t.x.y.O.O.P.P.P.P.*+*+*+ + +&+=+=+=+=+=+-+3 . ", +". $ 2.2.2.2.3.6.7.c.c.f.f.c.v.N.N.M.M.t.u.O.O.O.O.P.P.P.`.*+*+*+ + +=+=+=+=+=+=+=+-+-+3 . ", +". $ 2.2.6.6.7.c.c.c.c.f.$.f.N.N.t.M.;+>+O.O.O.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+'+", +". $ 6.6.Y c.c.v.g.g.g.f.N.N.u.u.u.>+O.P.P.`.`.,+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+!+", +". $ Y c.v.g.~+I.J.#+{+M.]+^+^+@+$+>+/+$+$+$+$+,+)+$ (+_+)+)+:+$ $ )+$ $ $ $ )+$ $ = W <+[+)+)+!+", +". $ v.g.g.g.}+t.t.t.t.M.u.P.P.P.P.>+`.*+*+*+|+,+)+$ $ 1+2+3+4+$ $ )+)+$ $ )+)+$ $ )+5+6+$ 7+)+!+", +". $ N.N.t.t.}+8+#+9+M.>+/+/+$+0+a+a+: $+a G.b+,+)+$ c+$ d+e+c+$ $ )+)+$ $ )+)+$ $ )+)+f+$ g+)+!+", +". $ t.t.t.u.L.x.x.>+>+>+P.*+*+a+a+a+ + +=+=+=+,+)+$ h+l $ 4+i+$ $ )+)+$ $ )+)+$ $ )+)+j+$ 4 )+!+", +". $ u.x.x.x.L.Y.Y.k+>+l+$+$+m+n+a+o+b+b+b+b+X.,+)+$ )+p+q+r+)+$ $ )+)+$ $ )+)+$ $ )+)+s+$ t+)+!+", +". $ x.x.x.P.Z.`.`.`.*+*+*+|+|+ +=+=+=+=+u+u+v+,+)+$ )+)+)+)+)+$ $ )+)+$ $ )+)+$ $ )+w+x+= y+)+!+", +". $ y.`.`.`.%+$+$+$+a a a G.b+b+b+Y.Y.{+{+{+$+,+)+$ )+)+)+)+)+$ $ )+$ $ $ $ )+$ $ = z+1+A+)+)+!+", +". $ `.*+*+*+|+|+|+|+ + +=+u+u+u+-+-+-+-+-+-+-+,+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+!+", +". $ *+|+|+|+ + + + +u+u+-+-+-+-+-+-+-+-+-+B+B+'+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+", +". $ |+ + + + +&+u+-+-+-+-+-+-+-+-+-+-+B+B+B+B+B+: : : ` ` ` ` C+C+C+C+C+C+C+C+C+C+C+C+D+. ", +". # + + +=+-+-+-+-+-+-+-+-+-+-+E+B+B+B+B+B+B+B+B+F+F+F+F+G+G+G+G+G+G+G+G+G+G+G+G+G+G+++. ", +". f 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 ++H+. ", +" . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +" ", +" ", +" "};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/amidi-plug/i_common.h Thu Jan 26 18:43:59 2006 -0800 @@ -0,0 +1,61 @@ +/* +* +* Author: Giacomo Lozito <james@develia.org>, (C) 2005-2006 +* +* 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 +* +*/ + +#ifndef _I_COMMON_H +#define _I_COMMON_H 1 + + +#include "config.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <glib.h> + +#define _(String) (String) +#define N_(String) String +#define textdomain(Domain) +#define bindtextdomain(Package, Directory) + +#define WARNANDBREAK(...) { g_warning(__VA_ARGS__); break; } +#define WARNANDBREAKANDPLAYERR(...) { amidiplug_playing_status = AMIDIPLUG_ERR; g_warning(__VA_ARGS__); break; } + +#ifdef DEBUG +#define DEBUGMSG(...) { fprintf(stderr, "amidi-plug(%s:%s:%d): ", __FILE__, __FUNCTION__, (int) __LINE__); fprintf(stderr, __VA_ARGS__); } +#else +#define DEBUGMSG(...) +#endif /* DEBUG */ + + +#define AMIDIPLUG_VERSION "0.1" +#define PLAYER_NAME "Audacious" +#define G_PATH_GET_BASENAME(x) g_path_get_basename(x) +#define G_STRING_PRINTF(...) g_string_printf(__VA_ARGS__) + +/* multi-purpose data bucket */ +typedef struct +{ + gint bint[2]; + gchar * bcharp[2]; + gpointer bpointer[2]; +} +data_bucket_t; + +#endif /* !_I_COMMON_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/amidi-plug/i_configure.c Thu Jan 26 18:43:59 2006 -0800 @@ -0,0 +1,433 @@ +/* +* +* Author: Giacomo Lozito <james@develia.org>, (C) 2005-2006 +* +* 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 +* +*/ + + +#include "i_configure.h" + +/* internals */ +void i_configure_upd_portlist( void ); +void i_configure_upd_mixercardlist( void ); +gchar * i_configure_read_seq_ports_default( gchar * ); +gboolean i_configure_ev_checktoggle( GtkTreeModel * , GtkTreePath * , GtkTreeIter * , gpointer ); +void i_configure_ev_changetoggle( GtkCellRendererToggle * , gchar * , gpointer ); + + +void i_configure_gui( GSList * wports , GSList * scards ) +{ + GtkWidget *configwin_vbox; + GtkWidget *port_lv, *port_lv_sw, *port_frame; + GtkWidget *mixer_card_cmb_evbox, *mixer_card_cmb, *mixer_vbox, *mixer_frame; + GtkWidget *hseparator, *hbuttonbox, *button_ok, *button_cancel; + GtkListStore *port_liststore, *mixer_card_liststore; + GtkTreeIter iter; + GtkTreeSelection *port_lv_sel; + GtkCellRenderer *port_lv_toggle_rndr, *port_lv_text_rndr, *mixer_card_cmb_text_rndr; + GtkTreeViewColumn *port_lv_toggle_col, *port_lv_portnum_col; + GtkTreeViewColumn *port_lv_clientname_col, *port_lv_portname_col; + gchar **portstring_from_cfg = NULL; + + if ( amidiplug_gui_prefs.config_win ) + return; + + if ( strlen( amidiplug_cfg.seq_writable_ports ) > 0 ) + portstring_from_cfg = g_strsplit( amidiplug_cfg.seq_writable_ports , "," , 0 ); + + amidiplug_gui_prefs.config_win = gtk_window_new( GTK_WINDOW_TOPLEVEL ); + gtk_window_set_type_hint( GTK_WINDOW(amidiplug_gui_prefs.config_win), GDK_WINDOW_TYPE_HINT_DIALOG ); + gtk_window_set_title( GTK_WINDOW(amidiplug_gui_prefs.config_win), "AMIDI-Plug - configuration" ); + gtk_container_set_border_width( GTK_CONTAINER(amidiplug_gui_prefs.config_win), 10 ); + g_signal_connect( G_OBJECT(amidiplug_gui_prefs.config_win) , + "destroy" , G_CALLBACK(i_configure_ev_destroy) , NULL ); + + configwin_vbox = gtk_vbox_new( FALSE , 0 ); + gtk_container_add( GTK_CONTAINER(amidiplug_gui_prefs.config_win) , configwin_vbox ); + + port_liststore = gtk_list_store_new( LISTPORT_N_COLUMNS, G_TYPE_BOOLEAN, G_TYPE_STRING , + G_TYPE_STRING , G_TYPE_STRING , G_TYPE_POINTER ); + + /* append ALSA MIDI ports */ + while ( wports != NULL ) + { + gint i = 0; + gboolean toggled = FALSE; + data_bucket_t * portinfo = (data_bucket_t *)wports->data; + GString * portstring = g_string_new(""); + G_STRING_PRINTF( portstring , "%i:%i" , + portinfo->bint[0] , portinfo->bint[1] ); + gtk_list_store_append( port_liststore , &iter ); + + /* in the existing configuration there may be previously selected ports */ + if ( portstring_from_cfg ) + { + /* check if current row contains a port selected by user */ + for ( i = 0 ; portstring_from_cfg[i] != NULL ; i++ ) + { + /* if it's one of the selected ports, toggle its checkbox */ + if ( !strcmp( portstring->str, portstring_from_cfg[i] ) ) + toggled = TRUE; + } + } + + gtk_list_store_set( port_liststore , &iter , + LISTPORT_TOGGLE_COLUMN , toggled , + LISTPORT_PORTNUM_COLUMN , portstring->str , + LISTPORT_CLIENTNAME_COLUMN , portinfo->bcharp[0] , + LISTPORT_PORTNAME_COLUMN , portinfo->bcharp[1] , + LISTPORT_POINTER_COLUMN , portinfo , -1 ); + + g_string_free( portstring , TRUE ); + /* on with next */ + wports = wports->next; + } + + /* this string array is not needed anymore */ + g_strfreev( portstring_from_cfg ); + + port_lv = gtk_tree_view_new_with_model( GTK_TREE_MODEL(port_liststore) ); + amidiplug_gui_prefs.port_treeview = port_lv; + g_object_unref( port_liststore ); + port_lv_toggle_rndr = gtk_cell_renderer_toggle_new(); + gtk_cell_renderer_toggle_set_radio( GTK_CELL_RENDERER_TOGGLE(port_lv_toggle_rndr) , FALSE ); + gtk_cell_renderer_toggle_set_active( GTK_CELL_RENDERER_TOGGLE(port_lv_toggle_rndr) , TRUE ); + g_signal_connect( port_lv_toggle_rndr , "toggled" , + G_CALLBACK(i_configure_ev_changetoggle) , port_liststore ); + port_lv_text_rndr = gtk_cell_renderer_text_new(); + port_lv_toggle_col = gtk_tree_view_column_new_with_attributes( "", port_lv_toggle_rndr, + "active", LISTPORT_TOGGLE_COLUMN, NULL ); + port_lv_portnum_col = gtk_tree_view_column_new_with_attributes( "Port", port_lv_text_rndr, + "text", LISTPORT_PORTNUM_COLUMN, NULL ); + port_lv_clientname_col = gtk_tree_view_column_new_with_attributes( "Client name", port_lv_text_rndr, + "text", LISTPORT_CLIENTNAME_COLUMN, NULL ); + port_lv_portname_col = gtk_tree_view_column_new_with_attributes( "Port name", port_lv_text_rndr, + "text", LISTPORT_PORTNAME_COLUMN, NULL ); + gtk_tree_view_append_column( GTK_TREE_VIEW(port_lv), port_lv_toggle_col ); + gtk_tree_view_append_column( GTK_TREE_VIEW(port_lv), port_lv_portnum_col ); + gtk_tree_view_append_column( GTK_TREE_VIEW(port_lv), port_lv_clientname_col ); + gtk_tree_view_append_column( GTK_TREE_VIEW(port_lv), port_lv_portname_col ); + + port_lv_sel = gtk_tree_view_get_selection( GTK_TREE_VIEW(port_lv) ); + gtk_tree_selection_set_mode( GTK_TREE_SELECTION(port_lv_sel) , GTK_SELECTION_SINGLE ); + + port_lv_sw = gtk_scrolled_window_new( NULL , NULL ); + gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(port_lv_sw), + GTK_POLICY_NEVER, GTK_POLICY_NEVER ); + port_frame = gtk_frame_new( "ALSA output ports" ); + + gtk_container_add( GTK_CONTAINER(port_lv_sw) , port_lv ); + gtk_container_set_border_width( GTK_CONTAINER(port_lv_sw) , 5 ); + gtk_container_add( GTK_CONTAINER(port_frame) , port_lv_sw ); + gtk_box_pack_start( GTK_BOX(configwin_vbox) , port_frame , TRUE , TRUE , 0 ); + + /**********************/ + /*** MIXER SETTINGS ***/ + mixer_card_liststore = gtk_list_store_new( LISTMIXER_N_COLUMNS , G_TYPE_STRING , G_TYPE_INT , + G_TYPE_INT , G_TYPE_STRING ); + mixer_card_cmb = gtk_combo_box_new_with_model( GTK_TREE_MODEL(mixer_card_liststore) ); + amidiplug_gui_prefs.mixercard_combo = mixer_card_cmb; + /* fill models with sound cards and relative mixer controls */ + while ( scards != NULL ) + { + data_bucket_t * cardinfo = (data_bucket_t *)scards->data; + GString * desc_cardmix_string = g_string_new( "" ); + GSList * mixctl_list = cardinfo->bpointer[0]; + while ( mixctl_list != NULL ) + { + data_bucket_t * mixctlinfo = (data_bucket_t *)mixctl_list->data; + G_STRING_PRINTF( desc_cardmix_string , "%s - ctl: %s (ID %i)" , cardinfo->bcharp[0] , + mixctlinfo->bcharp[0] , mixctlinfo->bint[0] ); + gtk_list_store_append( mixer_card_liststore , &iter ); + gtk_list_store_set( mixer_card_liststore , &iter , + LISTMIXER_DESC_COLUMN , desc_cardmix_string->str , + LISTMIXER_CARDID_COLUMN , cardinfo->bint[0] , + LISTMIXER_MIXCTLID_COLUMN , mixctlinfo->bint[0] , + LISTMIXER_MIXCTLNAME_COLUMN , mixctlinfo->bcharp[0] , -1 ); + /* check if this corresponds to the value previously selected by user */ + if ( ( cardinfo->bint[0] == amidiplug_cfg.mixer_card_id ) && + ( !strcasecmp( mixctlinfo->bcharp[0] , amidiplug_cfg.mixer_control_name ) ) && + ( mixctlinfo->bint[0] == amidiplug_cfg.mixer_control_id ) ) + gtk_combo_box_set_active_iter( GTK_COMBO_BOX(mixer_card_cmb) , &iter ); + mixctl_list = mixctl_list->next; + } + g_string_free( desc_cardmix_string , TRUE ); + /* on with next */ + scards = scards->next; + } + /* free the instance of liststore, we already have one in the combo box */ + g_object_unref( mixer_card_liststore ); + /* create renderer to display text in the mixer combo box */ + mixer_card_cmb_text_rndr = gtk_cell_renderer_text_new(); + gtk_cell_layout_pack_start( GTK_CELL_LAYOUT(mixer_card_cmb) , mixer_card_cmb_text_rndr , TRUE ); + gtk_cell_layout_add_attribute( GTK_CELL_LAYOUT(mixer_card_cmb) , mixer_card_cmb_text_rndr , "text" , 0 ); + + /* the event box is needed to display a tooltip for the mixer combo box */ + mixer_card_cmb_evbox = gtk_event_box_new(); + gtk_container_add( GTK_CONTAINER(mixer_card_cmb_evbox) , mixer_card_cmb ); + mixer_vbox = gtk_vbox_new( FALSE , 0 ); + gtk_container_set_border_width( GTK_CONTAINER(mixer_vbox) , 5 ); + gtk_box_pack_start( GTK_BOX(mixer_vbox) , mixer_card_cmb_evbox , TRUE , TRUE , 0 ); + + mixer_frame = gtk_frame_new( "Mixer settings" ); + gtk_container_add( GTK_CONTAINER(mixer_frame) , mixer_vbox ); + gtk_box_pack_start( GTK_BOX(configwin_vbox) , mixer_frame , TRUE , TRUE , 0 ); + + /* horizontal separator and buttons */ + hseparator = gtk_hseparator_new(); + gtk_box_pack_start( GTK_BOX(configwin_vbox) , hseparator , FALSE , FALSE , 4 ); + hbuttonbox = gtk_hbutton_box_new(); + gtk_button_box_set_layout( GTK_BUTTON_BOX(hbuttonbox) , GTK_BUTTONBOX_END ); + button_cancel = gtk_button_new_from_stock( GTK_STOCK_CANCEL ); + g_signal_connect( G_OBJECT(button_cancel) , "clicked" , G_CALLBACK(i_configure_ev_bcancel) , NULL ); + gtk_container_add( GTK_CONTAINER(hbuttonbox) , button_cancel ); + button_ok = gtk_button_new_from_stock( GTK_STOCK_OK ); + g_signal_connect( G_OBJECT(button_ok) , "clicked" , G_CALLBACK(i_configure_ev_bok) , NULL ); + gtk_container_add( GTK_CONTAINER(hbuttonbox) , button_ok ); + gtk_box_pack_start( GTK_BOX(configwin_vbox) , hbuttonbox , FALSE , FALSE , 0 ); + + /* tooltips */ + amidiplug_gui_prefs.config_tips = gtk_tooltips_new(); + gtk_tooltips_set_tip( GTK_TOOLTIPS(amidiplug_gui_prefs.config_tips) , port_lv , + "* Select ALSA output ports *\n" + "MIDI events will be sent to the ports selected here. At least one " + "port must be selected in order to play MIDI with AMIDI-Plug. Unless " + "you know what you're doing, you'll probably want to use the " + "wavetable synthesizer ports." , "" ); + gtk_tooltips_set_tip( GTK_TOOLTIPS(amidiplug_gui_prefs.config_tips) , mixer_card_cmb_evbox , + "* Select ALSA mixer control *\n" + "AMIDI-Plug outputs directly through ALSA, it doesn't use effect " + "and ouput plugins from the player. While playing with AMIDI-Plug, " + "the player volume will manipulate the control you select here. " + "Unless you know what you're doing, you'll probably want to select " + "the Synth control here." , "" ); + + gtk_widget_show_all( amidiplug_gui_prefs.config_win ); +} + + +void i_configure_upd_portlist( void ) +{ + GtkTreeModel * liststore; + GString *wp = g_string_new( "" ); + /* get the model of the port list control */ + liststore = gtk_tree_view_get_model( GTK_TREE_VIEW(amidiplug_gui_prefs.port_treeview) ); + /* after the following foreach, wp contains a comma-separated list of selected ports */ + gtk_tree_model_foreach( liststore , i_configure_ev_checktoggle , wp ); + /* free previous */ + g_free( amidiplug_cfg.seq_writable_ports ); + /* update point amidiplug_cfg.seq_writable_ports + so it points to the new list of ports */ + amidiplug_cfg.seq_writable_ports = g_strdup( wp->str ); + /* not needed anymore */ + g_string_free( wp , TRUE ); + return; +} + + +void i_configure_upd_mixercardlist( void ) +{ + GtkTreeModel * liststore; + GtkTreeIter iter; + /* get the model of the card-mixer list control */ + liststore = gtk_combo_box_get_model( GTK_COMBO_BOX(amidiplug_gui_prefs.mixercard_combo) ); + /* get the selected item */ + if ( gtk_combo_box_get_active_iter( GTK_COMBO_BOX(amidiplug_gui_prefs.mixercard_combo) , &iter ) ) + { + /* free previous */ + g_free( amidiplug_cfg.mixer_control_name ); + /* update amidiplug_cfg.mixer_card_id and amidiplug_cfg.mixer_control_name */ + gtk_tree_model_get( GTK_TREE_MODEL(liststore) , &iter , + LISTMIXER_CARDID_COLUMN , &amidiplug_cfg.mixer_card_id , + LISTMIXER_MIXCTLID_COLUMN , &amidiplug_cfg.mixer_control_id , + LISTMIXER_MIXCTLNAME_COLUMN , &amidiplug_cfg.mixer_control_name , -1 ); + } + return; +} + + +gboolean i_configure_ev_checktoggle( GtkTreeModel * model , GtkTreePath * path , + GtkTreeIter * iter , gpointer wpp ) +{ + gboolean toggled = FALSE; + gchar * portstring; + GString * wps = wpp; + gtk_tree_model_get ( model , iter , + LISTPORT_TOGGLE_COLUMN , &toggled , + LISTPORT_PORTNUM_COLUMN , &portstring , -1 ); + /* check if the row points to an enabled port */ + if ( toggled ) + { + /* if this is not the first port added to wp, use comma as separator */ + if ( wps->str[0] != '\0' ) g_string_append_c( wps , ',' ); + g_string_append( wps , portstring ); + } + g_free( portstring ); + return FALSE; +} + + +void i_configure_ev_changetoggle( GtkCellRendererToggle * rdtoggle , + gchar * path_str , gpointer data ) +{ + GtkTreeModel *model = (GtkTreeModel *)data; + GtkTreeIter iter; + GtkTreePath *path = gtk_tree_path_new_from_string( path_str ); + gboolean toggled; + + gtk_tree_model_get_iter( model , &iter , path ); + gtk_tree_model_get( model , &iter , LISTPORT_TOGGLE_COLUMN , &toggled , -1); + + toggled ^= 1; + gtk_list_store_set( GTK_LIST_STORE(model), &iter , LISTPORT_TOGGLE_COLUMN , toggled , -1); + + gtk_tree_path_free (path); +} + + +void i_configure_ev_destroy( void ) +{ + g_object_unref( amidiplug_gui_prefs.config_tips ); + amidiplug_gui_prefs.config_tips = NULL; + amidiplug_gui_prefs.config_win = NULL; +} + + +void i_configure_ev_bcancel( void ) +{ + gtk_widget_destroy(amidiplug_gui_prefs.config_win); +} + + +void i_configure_ev_bok( void ) +{ + /* update amidiplug_cfg.seq_writable_ports + using the selected values from the port list */ + i_configure_upd_portlist(); + + /* update amidiplug_cfg.mixer_card_id and amidiplug_cfg.mixer_control_name + using the selected values from the card-mixer combo list */ + i_configure_upd_mixercardlist(); + + /* save settings */ + i_configure_cfg_save(); + + gtk_widget_destroy(amidiplug_gui_prefs.config_win); +} + + +gchar * i_configure_read_seq_ports_default( gchar * alsaversion ) +{ + FILE * fp = NULL; + gchar ** alsaversion_toks = NULL; + /* first try, get seq ports from proc on card0 */ + fp = fopen( "/proc/asound/card0/wavetableD1" , "rb" ); + if ( fp ) + { + gchar buffer[100]; + while ( !feof( fp ) ) + { + fgets( buffer , 100 , fp ); + if (( strlen( buffer ) > 11 ) && ( !strncasecmp( buffer , "addresses: " , 11 ) )) + { + /* change spaces between ports (65:0 65:1 65:2 ...) + into commas (65:0,65:1,65:2,...) */ + g_strdelimit( &buffer[11] , " " , ',' ); + /* remove lf and cr from the end of the string */ + g_strdelimit( &buffer[11] , "\r\n" , '\0' ); + /* ready to go */ + DEBUGMSG( "init, default values for seq ports detected: %s\n" , &buffer[11] ); + fclose( fp ); + return g_strdup( &buffer[11] ); + } + } + fclose( fp ); + } + + /* second try, go with different "possible" defaults depending on ALSA version; + this is just a fallback, not expected to work all of the times; expecially + considering that the lib version is checked, not the driver one (even if + the version number is most likely the same) */ + alsaversion_toks = g_strsplit( alsaversion , "." , 4 ); + if ( strtol( alsaversion_toks[0] , NULL , 10 ) < 2 ) + { + if ( strtol( alsaversion_toks[1] , NULL , 10 ) < 1 ) + { + if ( strtol( alsaversion_toks[2] , NULL , 10 ) < 11 ) + { + /* alsa version <= 1.0.10 */ + g_strfreev( alsaversion_toks ); + DEBUGMSG( "init, default seq port value tentatively set to 65:0 (ALSA %s)\n" , alsaversion ); + return g_strdup( "65:0" ); + } + } + } + /* alsa version > 1.0.10 */ + g_strfreev( alsaversion_toks ); + DEBUGMSG( "init, default seq port value tentatively set to 17:0 (ALSA %s)\n" , alsaversion ); + return g_strdup( "17:0" ); +} + + +void i_configure_cfg_read( gchar * alsaversion ) +{ + ConfigFile *cfgfile; + cfgfile = xmms_cfg_open_default_file(); + + if (!cfgfile) + { + /* use defaults */ + amidiplug_cfg.seq_writable_ports = i_configure_read_seq_ports_default( alsaversion ); + amidiplug_cfg.mixer_card_id = 0; + amidiplug_cfg.mixer_control_name = g_strdup( "Synth" ); + amidiplug_cfg.mixer_control_id = 0; + } + else + { + if ( !xmms_cfg_read_string( cfgfile , "amidi-plug" , "writable_ports" , &amidiplug_cfg.seq_writable_ports ) ) + amidiplug_cfg.seq_writable_ports = i_configure_read_seq_ports_default( alsaversion ); /* default value */ + + if ( !xmms_cfg_read_int( cfgfile , "amidi-plug" , "mixer_card_id" , &amidiplug_cfg.mixer_card_id ) ) + amidiplug_cfg.mixer_card_id = 0; /* default value */ + + if ( !xmms_cfg_read_string( cfgfile , "amidi-plug" , "mixer_control_name" , &amidiplug_cfg.mixer_control_name ) ) + amidiplug_cfg.mixer_control_name = g_strdup( "Synth" ); /* default value */ + + if ( !xmms_cfg_read_int( cfgfile , "amidi-plug" , "mixer_control_id" , &amidiplug_cfg.mixer_control_id ) ) + amidiplug_cfg.mixer_control_id = 0; /* default value */ + + xmms_cfg_free(cfgfile); + } +} + + +void i_configure_cfg_save( void ) +{ + ConfigFile *cfgfile; + cfgfile = xmms_cfg_open_default_file(); + + if (!cfgfile) + cfgfile = xmms_cfg_new(); + + xmms_cfg_write_string( cfgfile , "amidi-plug" , "writable_ports" , amidiplug_cfg.seq_writable_ports ); + xmms_cfg_write_int( cfgfile , "amidi-plug" , "mixer_card_id" , amidiplug_cfg.mixer_card_id ); + xmms_cfg_write_string( cfgfile , "amidi-plug" , "mixer_control_name" , amidiplug_cfg.mixer_control_name ); + xmms_cfg_write_int( cfgfile , "amidi-plug" , "mixer_control_id" , amidiplug_cfg.mixer_control_id ); + + xmms_cfg_write_default_file(cfgfile); + xmms_cfg_free(cfgfile); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/amidi-plug/i_configure.h Thu Jan 26 18:43:59 2006 -0800 @@ -0,0 +1,78 @@ +/* +* +* Author: Giacomo Lozito <james@develia.org>, (C) 2005-2006 +* +* 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 +* +*/ + +#ifndef _I_CONFIGURE_H +#define _I_CONFIGURE_H 1 + +#include "i_common.h" +#include <gtk/gtk.h> +#include <audacious/configfile.h> + + +enum +{ + LISTPORT_TOGGLE_COLUMN, + LISTPORT_PORTNUM_COLUMN, + LISTPORT_CLIENTNAME_COLUMN, + LISTPORT_PORTNAME_COLUMN, + LISTPORT_POINTER_COLUMN, + LISTPORT_N_COLUMNS +}; + +enum +{ + LISTMIXER_DESC_COLUMN, + LISTMIXER_CARDID_COLUMN, + LISTMIXER_MIXCTLID_COLUMN, + LISTMIXER_MIXCTLNAME_COLUMN, + LISTMIXER_N_COLUMNS +}; + +typedef struct +{ + gchar * seq_writable_ports; + gint mixer_card_id; + gchar * mixer_control_name; + gint mixer_control_id; +} +amidiplug_cfg_t; + +extern amidiplug_cfg_t amidiplug_cfg; + +typedef struct +{ + GtkWidget * config_win; + GtkWidget * port_treeview; + GtkWidget * mixercard_combo; + GtkTooltips * config_tips; +} +amidiplug_gui_prefs_t; + +static amidiplug_gui_prefs_t amidiplug_gui_prefs = { NULL , NULL , NULL , NULL }; + +void i_configure_gui( GSList * , GSList * ); +void i_configure_ev_destroy( void ); +void i_configure_ev_bcancel( void ); +void i_configure_ev_bok( void ); +void i_configure_cfg_save( void ); +void i_configure_cfg_read( gchar * ); + + +#endif /* !_I_CONFIGURE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/amidi-plug/i_fileinfo.c Thu Jan 26 18:43:59 2006 -0800 @@ -0,0 +1,254 @@ +/* +* +* Author: Giacomo Lozito <james@develia.org>, (C) 2005-2006 +* +* 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 +* +*/ + + +#include "i_fileinfo.h" +/* this is needed to retrieve information */ +#include "i_midi.h" +/* icon from gnome-mime-audio-midi.png of the GNOME ICON SET */ +#include "amidi-plug.midiicon.xpm" + +static amidiplug_gui_fileinfo_t amidiplug_gui_fileinfo = { NULL }; + + +gint i_fileinfo_midiparse( gchar * filename , midifile_t * mf ) +{ + i_midi_init( mf ); + DEBUGMSG( "FILEINFO requested, opening file: %s\n" , filename ); + mf->file_pointer = fopen( filename , "rb" ); + if (!mf->file_pointer) + { + g_warning( "Cannot open %s\n" , filename ); + return 0; + } + mf->file_name = filename; + + switch( i_midi_file_read_id( mf ) ) + { + case MAKE_ID('R', 'I', 'F', 'F'): + { + DEBUGMSG( "FILEINFO requested, RIFF chunk found, processing...\n" ); + /* read riff chunk */ + if ( !i_midi_file_parse_riff( mf ) ) + WARNANDBREAK( "%s: invalid file format (riff parser)\n" , filename ); + + /* if that was read correctly, go ahead and read smf data */ + } + + case MAKE_ID('M', 'T', 'h', 'd'): + { + DEBUGMSG( "FILEINFO requested, MThd chunk found, processing...\n" ); + /* we don't care about port count here, pass 1 */ + if ( !i_midi_file_parse_smf( mf , 1 ) ) + WARNANDBREAK( "%s: invalid file format (smf parser)\n" , filename ); + + if ( mf->time_division < 1 ) + WARNANDBREAK( "%s: invalid time division (%i)\n" , filename , mf->time_division ); + + /* fill mf->ppq and mf->tempo using time_division */ + if ( !i_midi_setget_tempo( mf ) ) + WARNANDBREAK( "%s: invalid values while setting ppq and tempo\n" , filename ); + + /* fill mf->length, keeping in count tempo-changes */ + i_midi_setget_length( mf ); + + /* ok, mf has been filled with information; successfully return */ + fclose( mf->file_pointer ); + return 1; + } + + default: + { + g_warning( "%s is not a Standard MIDI File\n" , filename ); + break; + } + } + + /* something failed */ + fclose( mf->file_pointer ); + return 0; +} + + +void i_fileinfo_ev_destroy( void ) +{ + amidiplug_gui_fileinfo.fileinfo_win = NULL; +} + + +void i_fileinfo_ev_close( void ) +{ + gtk_widget_destroy( amidiplug_gui_fileinfo.fileinfo_win ); +} + + +void i_fileinfo_table_add_entry( gchar * field_text , gchar * value_text , + GtkWidget * table , guint line , PangoAttrList * attrlist ) +{ + GtkWidget *field, *value; + field = gtk_label_new( field_text ); + gtk_label_set_attributes( GTK_LABEL(field) , attrlist ); + gtk_misc_set_alignment( GTK_MISC(field) , 0 , 0 ); + gtk_label_set_justify( GTK_LABEL(field) , GTK_JUSTIFY_LEFT ); + gtk_table_attach( GTK_TABLE(table) , field , 0 , 1 , line , (line + 1) , + GTK_FILL , GTK_FILL , 5 , 2 ); + value = gtk_label_new( value_text ); + gtk_misc_set_alignment( GTK_MISC(value) , 0 , 0 ); + gtk_label_set_justify( GTK_LABEL(value) , GTK_JUSTIFY_LEFT ); + gtk_table_attach( GTK_TABLE(table) , value , 1 , 2 , line , (line + 1) , + GTK_FILL , GTK_FILL , 5 , 2 ); + return; +} + + +void i_fileinfo_gui( gchar * filename ) +{ + GtkWidget *fileinfowin_vbox; + GtkWidget *title_hbox , *title_icon_image , *title_name_f_label , *title_name_v_entry; + GtkWidget *info_frame , *info_table; + GtkWidget *footer_hbbox, *footer_bclose; + GdkPixbuf *title_icon_pixbuf; + PangoAttrList *pangoattrlist; + PangoAttribute *pangoattr; + GString *value_gstring; + gchar *title , *filename_utf8; + gint bpm = 0, wavg_bpm = 0; + midifile_t mf; + + if ( amidiplug_gui_fileinfo.fileinfo_win ) + return; + + /****************** midifile parser ******************/ + if ( !i_fileinfo_midiparse( filename , &mf ) ) + return; + /* midifile is filled with information at this point, + bpm information is needed too */ + i_midi_get_bpm( &mf , &bpm , &wavg_bpm ); + /*****************************************************/ + + amidiplug_gui_fileinfo.fileinfo_win = gtk_window_new( GTK_WINDOW_TOPLEVEL ); + gtk_window_set_type_hint( GTK_WINDOW(amidiplug_gui_fileinfo.fileinfo_win), GDK_WINDOW_TYPE_HINT_DIALOG ); + gtk_window_set_resizable( GTK_WINDOW(amidiplug_gui_fileinfo.fileinfo_win) , FALSE ); + gtk_window_set_position( GTK_WINDOW(amidiplug_gui_fileinfo.fileinfo_win) , GTK_WIN_POS_CENTER ); + g_signal_connect( G_OBJECT(amidiplug_gui_fileinfo.fileinfo_win) , + "destroy" , G_CALLBACK(i_fileinfo_ev_destroy) , NULL ); + gtk_container_set_border_width( GTK_CONTAINER(amidiplug_gui_fileinfo.fileinfo_win), 10 ); + + fileinfowin_vbox = gtk_vbox_new( FALSE , 10 ); + gtk_container_add( GTK_CONTAINER(amidiplug_gui_fileinfo.fileinfo_win) , fileinfowin_vbox ); + + /* pango attributes */ + pangoattrlist = pango_attr_list_new(); + pangoattr = pango_attr_weight_new( PANGO_WEIGHT_BOLD ); + pangoattr->start_index = 0; + pangoattr->end_index = G_MAXINT; + pango_attr_list_insert( pangoattrlist , pangoattr ); + + /****************** + *** TITLE LINE ***/ + title_hbox = gtk_hbox_new( FALSE , 5 ); + gtk_box_pack_start( GTK_BOX(fileinfowin_vbox) , title_hbox , FALSE , FALSE , 0 ); + + title_icon_pixbuf = gdk_pixbuf_new_from_xpm_data( (const gchar **)amidiplug_xpm_midiicon ); + title_icon_image = gtk_image_new_from_pixbuf( title_icon_pixbuf ); + g_object_unref( title_icon_pixbuf ); + gtk_misc_set_alignment( GTK_MISC(title_icon_image) , 0 , 0 ); + gtk_box_pack_start( GTK_BOX(title_hbox) , title_icon_image , FALSE , FALSE , 0 ); + + title_name_f_label = gtk_label_new( _("Name:") ); + gtk_label_set_attributes( GTK_LABEL(title_name_f_label) , pangoattrlist ); + gtk_box_pack_start( GTK_BOX(title_hbox) , title_name_f_label , FALSE , FALSE , 0 ); + + title_name_v_entry = gtk_entry_new(); + gtk_editable_set_editable( GTK_EDITABLE(title_name_v_entry) , FALSE ); + gtk_widget_set_size_request( GTK_WIDGET(title_name_v_entry) , 200 , -1 ); + gtk_box_pack_start(GTK_BOX(title_hbox) , title_name_v_entry , TRUE , TRUE , 0 ); + + /********************* + *** MIDI INFO BOX ***/ + info_frame = gtk_frame_new( _(" MIDI Info ") ); + gtk_box_pack_start( GTK_BOX(fileinfowin_vbox) , info_frame , TRUE , TRUE , 0 ); + info_table = gtk_table_new( 6 , 2 , FALSE ); + gtk_container_set_border_width( GTK_CONTAINER(info_table) , 5 ); + gtk_container_add( GTK_CONTAINER(info_frame) , info_table ); + value_gstring = g_string_new( "" ); + + /* midi format */ + G_STRING_PRINTF( value_gstring , "type %i" , mf.format ); + i_fileinfo_table_add_entry( _("Format:") , value_gstring->str , info_table , 0 , pangoattrlist ); + /* midi length */ + G_STRING_PRINTF( value_gstring , "%i" , (gint)(mf.length / 1000) ); + i_fileinfo_table_add_entry( _("Length (msec):") , value_gstring->str , info_table , 1 , pangoattrlist ); + /* midi num of tracks */ + G_STRING_PRINTF( value_gstring , "%i" , mf.num_tracks ); + i_fileinfo_table_add_entry( _("Num of Tracks:") , value_gstring->str , info_table , 2 , pangoattrlist ); + /* midi bpm */ + if ( bpm > 0 ) + G_STRING_PRINTF( value_gstring , "%i" , bpm ); /* fixed bpm */ + else + G_STRING_PRINTF( value_gstring , _("variable") ); /* variable bpm */ + i_fileinfo_table_add_entry( _("BPM:") , value_gstring->str , info_table , 3 , pangoattrlist ); + /* midi weighted average bpm */ + if ( bpm > 0 ) + G_STRING_PRINTF( value_gstring , "/" ); /* fixed bpm, don't care about wavg_bpm */ + else + G_STRING_PRINTF( value_gstring , "%i" , wavg_bpm ); /* variable bpm, display wavg_bpm */ + i_fileinfo_table_add_entry( _("BPM (wavg):") , value_gstring->str , info_table , 4 , pangoattrlist ); + /* midi time division */ + G_STRING_PRINTF( value_gstring , "%i" , mf.time_division ); + i_fileinfo_table_add_entry( _("Time Div:") , value_gstring->str , info_table , 5 , pangoattrlist ); + + g_string_free( value_gstring , TRUE ); + + /************** + *** FOOTER ***/ + footer_hbbox = gtk_hbutton_box_new(); + gtk_button_box_set_layout( GTK_BUTTON_BOX(footer_hbbox) , GTK_BUTTONBOX_END ); + footer_bclose = gtk_button_new_from_stock( GTK_STOCK_CLOSE ); + g_signal_connect( G_OBJECT(footer_bclose) , "clicked" , G_CALLBACK(i_fileinfo_ev_close) , NULL ); + gtk_container_add( GTK_CONTAINER(footer_hbbox) , footer_bclose ); + gtk_box_pack_start( GTK_BOX(fileinfowin_vbox) , footer_hbbox , FALSE , FALSE , 0 ); + + + /* utf8-ize filename and set window title */ + filename_utf8 = g_strdup(g_filename_to_utf8( filename , -1 , NULL , NULL , NULL )); + if ( !filename_utf8 ) + { + /* utf8 fallback */ + gchar *chr , *convert_str = g_strdup( filename ); + for ( chr = convert_str ; *chr ; chr++ ) + { + if ( *chr & 0x80 ) + *chr = '?'; + } + filename_utf8 = g_strconcat( convert_str , _(" (invalid UTF-8)") , NULL ); + g_free(convert_str); + } + title = g_strdup_printf( "%s - " PLAYER_NAME , g_basename(filename_utf8)); + gtk_window_set_title( GTK_WINDOW(amidiplug_gui_fileinfo.fileinfo_win) , title); + g_free(title); + /* set the text for the filename header too */ + gtk_entry_set_text( GTK_ENTRY(title_name_v_entry) , filename_utf8 ); + gtk_editable_set_position( GTK_EDITABLE(title_name_v_entry) , -1 ); + g_free(filename_utf8); + + gtk_widget_grab_focus( GTK_WIDGET(footer_bclose) ); + gtk_widget_show_all( amidiplug_gui_fileinfo.fileinfo_win ); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/amidi-plug/i_fileinfo.h Thu Jan 26 18:43:59 2006 -0800 @@ -0,0 +1,38 @@ +/* +* +* Author: Giacomo Lozito <james@develia.org>, (C) 2005-2006 +* +* 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 +* +*/ + +#ifndef _I_FILEINFO_H +#define _I_FILEINFO_H 1 + +#include "i_common.h" +#include <gtk/gtk.h> +#include <audacious/util.h> + + +typedef struct +{ + GtkWidget * fileinfo_win; +} +amidiplug_gui_fileinfo_t; + +void i_fileinfo_gui( gchar * ); + + +#endif /* !_I_FILEINFO_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/amidi-plug/i_midi.c Thu Jan 26 18:43:59 2006 -0800 @@ -0,0 +1,671 @@ +/* +* +* Author: Giacomo Lozito <james@develia.org>, (C) 2005-2006 +* +* MIDI (SMF) parser based on aplaymidi.c from ALSA-utils +* aplaymidi.c is Copyright (c) 2004 Clemens Ladisch <clemens@ladisch.de> +* +* 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 +* +*/ + + +#include "i_midi.h" + +#define ERRMSG_MIDITRACK() { g_warning( "%s: invalid MIDI data (offset %#x)" , mf->file_name , mf->file_offset ); return 0; } + + +/* skip a certain number of bytes */ +void i_midi_file_skip_bytes( midifile_t * mf , gint bytes ) +{ + while (bytes > 0) + { + i_midi_file_read_byte(mf); + --bytes; + } +} + + +/* reads a single byte */ +gint i_midi_file_read_byte( midifile_t * mf ) +{ + ++mf->file_offset; + return getc(mf->file_pointer); +} + + +/* reads a little-endian 32-bit integer */ +gint i_midi_file_read_32_le( midifile_t * mf ) +{ + gint value; + value = i_midi_file_read_byte(mf); + value |= i_midi_file_read_byte(mf) << 8; + value |= i_midi_file_read_byte(mf) << 16; + value |= i_midi_file_read_byte(mf) << 24; + return !feof(mf->file_pointer) ? value : -1; +} + + +/* reads a 4-character identifier */ +gint i_midi_file_read_id( midifile_t * mf ) +{ + return i_midi_file_read_32_le(mf); +} + + +/* reads a fixed-size big-endian number */ +gint i_midi_file_read_int( midifile_t * mf , gint bytes ) +{ + gint c, value = 0; + + do { + c = i_midi_file_read_byte(mf); + if (c == EOF) return -1; + value = (value << 8) | c; + } while (--bytes); + + return value; +} + + +/* reads a variable-length number */ +gint i_midi_file_read_var( midifile_t * mf ) +{ + gint value, c; + + c = i_midi_file_read_byte(mf); + value = c & 0x7f; + if (c & 0x80) { + c = i_midi_file_read_byte(mf); + value = (value << 7) | (c & 0x7f); + if (c & 0x80) { + c = i_midi_file_read_byte(mf); + value = (value << 7) | (c & 0x7f); + if (c & 0x80) { + c = i_midi_file_read_byte(mf); + value = (value << 7) | c; + if (c & 0x80) + return -1; + } + } + } + return !feof(mf->file_pointer) ? value : -1; +} + + +/* allocates a new event */ +midievent_t * i_midi_file_new_event(midifile_track_t * track, gint sysex_length) +{ + midievent_t * event; + + event = malloc(sizeof(midievent_t) + sysex_length); + /* check_mem(event); */ + + event->next = NULL; + + /* append at the end of the track's linked list */ + if (track->current_event) + track->current_event->next = event; + else + track->first_event = event; + track->current_event = event; + + return event; +} + + +/* reads one complete track from the file */ +gint i_midi_file_read_track( midifile_t * mf , midifile_track_t * track , + gint track_end , gint port_count ) +{ + gint tick = 0; + guchar last_cmd = 0; + guchar port = 0; + + /* the current file position is after the track ID and length */ + while ( mf->file_offset < track_end ) + { + guchar cmd; + midievent_t *event; + gint delta_ticks, len, c; + + delta_ticks = i_midi_file_read_var(mf); + if ( delta_ticks < 0 ) + break; + tick += delta_ticks; + + c = i_midi_file_read_byte(mf); + if (c < 0) + break; + + if (c & 0x80) { + /* have command */ + cmd = c; + if (cmd < 0xf0) + last_cmd = cmd; + } else { + /* running status */ + ungetc(c, mf->file_pointer); + mf->file_offset--; + cmd = last_cmd; + if (!cmd) + ERRMSG_MIDITRACK(); + } + + switch (cmd >> 4) + { + /* maps SMF events to ALSA sequencer events */ + static guchar cmd_type[] = { + [0x8] = SND_SEQ_EVENT_NOTEOFF, + [0x9] = SND_SEQ_EVENT_NOTEON, + [0xa] = SND_SEQ_EVENT_KEYPRESS, + [0xb] = SND_SEQ_EVENT_CONTROLLER, + [0xc] = SND_SEQ_EVENT_PGMCHANGE, + [0xd] = SND_SEQ_EVENT_CHANPRESS, + [0xe] = SND_SEQ_EVENT_PITCHBEND + }; + + case 0x8: /* channel msg with 2 parameter bytes */ + case 0x9: + case 0xa: + case 0xb: + case 0xe: + { + event = i_midi_file_new_event(track, 0); + event->type = cmd_type[cmd >> 4]; + event->port = port; + event->tick = tick; + event->data.d[0] = cmd & 0x0f; + event->data.d[1] = i_midi_file_read_byte(mf) & 0x7f; + event->data.d[2] = i_midi_file_read_byte(mf) & 0x7f; + } + break; + + case 0xc: /* channel msg with 1 parameter byte */ + case 0xd: + { + event = i_midi_file_new_event(track, 0); + event->type = cmd_type[cmd >> 4]; + event->port = port; + event->tick = tick; + event->data.d[0] = cmd & 0x0f; + event->data.d[1] = i_midi_file_read_byte(mf) & 0x7f; + } + break; + + case 0xf: + { + switch (cmd) + { + case 0xf0: /* sysex */ + case 0xf7: /* continued sysex, or escaped commands */ + { + len = i_midi_file_read_var(mf); + if (len < 0) + ERRMSG_MIDITRACK(); + if (cmd == 0xf0) + ++len; + event = i_midi_file_new_event(track, len); + event->type = SND_SEQ_EVENT_SYSEX; + event->port = port; + event->tick = tick; + event->data.length = len; + if (cmd == 0xf0) { + event->sysex[0] = 0xf0; + c = 1; + } else { + c = 0; + } + for (; c < len; ++c) + event->sysex[c] = i_midi_file_read_byte(mf); + } + break; + + case 0xff: /* meta event */ + { + c = i_midi_file_read_byte(mf); + len = i_midi_file_read_var(mf); + if (len < 0) + ERRMSG_MIDITRACK(); + + switch (c) + { + case 0x21: /* port number */ + { + if (len < 1) + ERRMSG_MIDITRACK(); + port = i_midi_file_read_byte(mf) % port_count; + i_midi_file_skip_bytes(mf,(len - 1)); + } + break; + + case 0x2f: /* end of track */ + { + track->end_tick = tick; + i_midi_file_skip_bytes(mf,(track_end - mf->file_offset)); + return 1; + } + + case 0x51: /* tempo */ + { + if (len < 3) + ERRMSG_MIDITRACK(); + if (mf->smpte_timing) { + /* SMPTE timing doesn't change */ + i_midi_file_skip_bytes(mf,len); + } else { + event = i_midi_file_new_event(track, 0); + event->type = SND_SEQ_EVENT_TEMPO; + event->port = port; + event->tick = tick; + event->data.tempo = i_midi_file_read_byte(mf) << 16; + event->data.tempo |= i_midi_file_read_byte(mf) << 8; + event->data.tempo |= i_midi_file_read_byte(mf); + i_midi_file_skip_bytes(mf,(len - 3)); + } + } + break; + + default: /* ignore all other meta events */ + { + i_midi_file_skip_bytes(mf,len); + } + break; + } + } + break; + + default: /* invalid Fx command */ + ERRMSG_MIDITRACK(); + } + } + break; + + default: /* cannot happen */ + ERRMSG_MIDITRACK(); + } + } + ERRMSG_MIDITRACK(); +} + + +/* read a MIDI file in Standard MIDI Format */ +/* return values: 0 = error , 1 = ok */ +gint i_midi_file_parse_smf( midifile_t * mf , gint port_count ) +{ + gint header_len, i; + + /* the curren position is immediately after the "MThd" id */ + header_len = i_midi_file_read_int(mf,4); + if ( header_len < 6 ) + { + g_warning( "%s: invalid file format\n" , mf->file_name ); + return 0; + } + + mf->format = i_midi_file_read_int(mf,2); + if (( mf->format != 0 ) && ( mf->format != 1 )) + { + g_warning( "%s: type %d format is not supported\n" , mf->file_name , mf->format); + return 0; + } + + mf->num_tracks = i_midi_file_read_int(mf,2); + if (( mf->num_tracks < 1 ) || ( mf->num_tracks > 1000 )) + { + g_warning( "%s: invalid number of tracks (%d)\n" , mf->file_name , mf->num_tracks ); + mf->num_tracks = 0; + return 0; + } + + mf->tracks = calloc( mf->num_tracks , sizeof(midifile_track_t) ); + if ( !mf->tracks ) + { + g_warning( "out of memory\n" ); + mf->num_tracks = 0; + return 0; + } + + mf->time_division = i_midi_file_read_int(mf,2); + if ( mf->time_division < 0 ) + { + g_warning( "%s: invalid file format\n" , mf->file_name ); + return 0; + } + + mf->smpte_timing = !!(mf->time_division & 0x8000); + + /* read tracks */ + for ( i = 0 ; i < mf->num_tracks ; ++i ) + { + gint len; + + /* search for MTrk chunk */ + for (;;) + { + gint id = i_midi_file_read_id(mf); + len = i_midi_file_read_int(mf,4); + if ( feof(mf->file_pointer) ) + { + g_warning( "%s: unexpected end of file\n" , mf->file_name ); + return 0; + } + if (( len < 0 ) || ( len >= 0x10000000)) + { + g_warning( "%s: invalid chunk length %d\n" , mf->file_name , len ); + return 0; + } + if ( id == MAKE_ID('M', 'T', 'r', 'k') ) + break; + i_midi_file_skip_bytes(mf,len); + } + + if ( !i_midi_file_read_track( mf , &mf->tracks[i] , mf->file_offset + len , port_count ) ) + return 0; + } + + /* calculate the max_tick for the entire file */ + mf->max_tick = 0; + for ( i = 0 ; i < mf->num_tracks ; ++i ) + { + if ( mf->tracks[i].end_tick > mf->max_tick ) + mf->max_tick = mf->tracks[i].end_tick; + } + + /* ok, success */ + return 1; +} + + +/* read a MIDI file enclosed in RIFF format */ +/* return values: 0 = error , 1 = ok */ +gint i_midi_file_parse_riff( midifile_t * mf ) +{ + /* skip file length (4 bytes) */ + i_midi_file_skip_bytes(mf,4); + + /* check file type ("RMID" = RIFF MIDI) */ + if ( i_midi_file_read_id(mf) != MAKE_ID('R', 'M', 'I', 'D') ) + return 0; + + /* search for "data" chunk */ + for (;;) + { + gint id = i_midi_file_read_id(mf); + gint len = i_midi_file_read_32_le(mf); + + if ( feof(mf->file_pointer) ) + return 0; + + if ( id == MAKE_ID('d', 'a', 't', 'a') ) + break; + + if (len < 0) + return 0; + + i_midi_file_skip_bytes(mf,((len + 1) & ~1)); + } + + /* the "data" chunk must contain data in SMF format */ + if ( i_midi_file_read_id(mf) != MAKE_ID('M', 'T', 'h', 'd') ) + return 0; + + /* ok, success */ + return 1; +} + + +/* midifile init */ +void i_midi_init( midifile_t * mf ) +{ + mf->file_pointer = NULL; + mf->file_name = NULL; + mf->file_offset = 0; + mf->num_tracks = 0; + mf->tracks = NULL; + mf->max_tick = 0; + mf->smpte_timing = 0; + mf->format = 0; + mf->time_division = 0; + mf->ppq = 0; + mf->current_tempo = 0; + mf->playing_tick = 0; + mf->avg_microsec_per_tick = 0; + mf->length = 0; + mf->skip_offset = 0; + return; +} + + +void i_midi_free( midifile_t * mf ) +{ + if ( mf->tracks ) + { + gint i; + /* free event list for each track */ + for ( i = 0 ; i < mf->num_tracks ; ++i ) + { + midievent_t * event = mf->tracks[i].first_event; + midievent_t * event_tmp = NULL; + while( event ) + { + event_tmp = event; + event = event->next; + free( event_tmp ); + } + } + /* free track array */ + free( mf->tracks ); + mf->tracks = NULL; + } +} + + +/* queue set tempo */ +gint i_midi_setget_tempo( midifile_t * mf ) +{ + gint smpte_timing , i = 0; + gint time_division = mf->time_division; + + /* interpret and set tempo */ + smpte_timing = !!(time_division & 0x8000); + if (!smpte_timing) + { + /* time_division is ticks per quarter */ + mf->current_tempo = 500000; + mf->ppq = time_division; + } + else + { + /* upper byte is negative frames per second */ + i = 0x80 - ((time_division >> 8) & 0x7f); + /* lower byte is ticks per frame */ + time_division &= 0xff; + /* now pretend that we have quarter-note based timing */ + switch (i) + { + case 24: + mf->current_tempo = 500000; + mf->ppq = 12 * time_division; + break; + case 25: + mf->current_tempo = 400000; + mf->ppq = 10 * time_division; + break; + case 29: /* 30 drop-frame */ + mf->current_tempo = 100000000; + mf->ppq = 2997 * time_division; + break; + case 30: + mf->current_tempo = 500000; + mf->ppq = 15 * time_division; + break; + default: + g_warning("Invalid number of SMPTE frames per second (%d)\n", i); + return 0; + } + } + DEBUGMSG( "MIDI tempo set -> time division: %i\n" , midifile.time_division ); + DEBUGMSG( "MIDI tempo set -> tempo: %i\n" , midifile.current_tempo ); + DEBUGMSG( "MIDI tempo set -> ppq: %i\n" , midifile.ppq ); + return 1; +} + + +/* this will set the midi length in microseconds + COMMENT: this will also reset current position in each track! */ +void i_midi_setget_length( midifile_t * mf ) +{ + gint length_microsec = 0, last_tick = 0, i = 0; + /* get the first microsec_per_tick ratio */ + gint microsec_per_tick = (gint)(mf->current_tempo / mf->ppq); + + /* initialize current position in each track */ + for (i = 0; i < mf->num_tracks; ++i) + mf->tracks[i].current_event = mf->tracks[i].first_event; + + /* search for tempo events in each track; in fact, since the program + currently supports type 0 and type 1 MIDI files, we should find + tempo events only in one track */ + DEBUGMSG( "LENGTH calc: starting calc loop\n" ); + for (;;) + { + midievent_t * event = NULL; + midifile_track_t * event_track = NULL; + gint i, min_tick = mf->max_tick + 1; + + /* search next event */ + for ( i = 0 ; i < mf->num_tracks ; ++i ) + { + midifile_track_t * track = &mf->tracks[i]; + midievent_t * e2 = track->current_event; + if (e2 && e2->tick < min_tick) + { + min_tick = e2->tick; + event = e2; + event_track = track; + } + } + + if (!event) + { + /* calculate the remaining length */ + length_microsec += ( microsec_per_tick * ( mf->max_tick - last_tick ) ); + break; /* end of song reached */ + } + + /* advance pointer to next event */ + event_track->current_event = event->next; + + /* check if this is a tempo event */ + if ( event->type == SND_SEQ_EVENT_TEMPO ) + { + DEBUGMSG( "LENGTH calc: tempo event (%i) encountered during calc on tick %i\n" , + event->data.tempo , event->tick ); + /* increment length_microsec with the amount of microsec before tempo change */ + length_microsec += ( microsec_per_tick * ( event->tick - last_tick ) ); + /* now update last_tick and the microsec_per_tick ratio */ + last_tick = event->tick; + microsec_per_tick = (gint)(event->data.tempo / mf->ppq); + } + } + + /* IMPORTANT + this couple of important values is set by i_midi_set_length */ + mf->length = length_microsec; + mf->avg_microsec_per_tick = (gint)(length_microsec / mf->max_tick); + + return; +} + + +/* this will get the weighted average bpm of the midi file; + if the file has a variable bpm, 'bpm' is set to -1; + COMMENT: this will also reset current position in each track! */ +void i_midi_get_bpm( midifile_t * mf , gint * bpm , gint * wavg_bpm ) +{ + gint i = 0 , last_tick = 0; + guint weighted_avg_tempo = 0; + gboolean is_monotempo = TRUE; + gint last_tempo = mf->current_tempo; + + /* initialize current position in each track */ + for ( i = 0 ; i < mf->num_tracks ; ++i ) + mf->tracks[i].current_event = mf->tracks[i].first_event; + + /* search for tempo events in each track; in fact, since the program + currently supports type 0 and type 1 MIDI files, we should find + tempo events only in one track */ + DEBUGMSG( "BPM calc: starting calc loop\n" ); + for (;;) + { + midievent_t * event = NULL; + midifile_track_t * event_track = NULL; + gint i, min_tick = mf->max_tick + 1; + + /* search next event */ + for ( i = 0 ; i < mf->num_tracks ; ++i ) + { + midifile_track_t * track = &mf->tracks[i]; + midievent_t * e2 = track->current_event; + if (e2 && e2->tick < min_tick) + { + min_tick = e2->tick; + event = e2; + event_track = track; + } + } + + if (!event) + { + /* calculate the remaining length */ + weighted_avg_tempo += (guint)( last_tempo * ((gfloat)( mf->max_tick - last_tick ) / (gfloat)mf->max_tick ) ); + break; /* end of song reached */ + } + + /* advance pointer to next event */ + event_track->current_event = event->next; + + /* check if this is a tempo event */ + if ( event->type == SND_SEQ_EVENT_TEMPO ) + { + /* check if this is a tempo change (real change, tempo should be + different) in the midi file (and it shouldn't be at tick 0); */ + if (( is_monotempo ) && ( event->tick > 0 ) && ( event->data.tempo != last_tempo )) + is_monotempo = FALSE; + + DEBUGMSG( "BPM calc: tempo event (%i) encountered during calc on tick %i\n" , + event->data.tempo , event->tick ); + /* add the previous tempo change multiplied for its weight (the tick interval for the tempo ) */ + weighted_avg_tempo += (guint)( last_tempo * ((gfloat)( event->tick - last_tick ) / (gfloat)mf->max_tick ) ); + /* now update last_tick and the microsec_per_tick ratio */ + last_tick = event->tick; + last_tempo = event->data.tempo; + } + } + + DEBUGMSG( "BPM calc: weighted average tempo: %i\n" , weighted_avg_tempo ); + + *wavg_bpm = (gint)( 60000000 / weighted_avg_tempo ); + + DEBUGMSG( "BPM calc: weighted average bpm: %i\n" , *wavg_bpm ); + + if ( is_monotempo ) + *bpm = *wavg_bpm; /* the song has fixed bpm */ + else + *bpm = -1; /* the song has variable bpm */ + + return; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/amidi-plug/i_midi.h Thu Jan 26 18:43:59 2006 -0800 @@ -0,0 +1,107 @@ +/* +* +* Author: Giacomo Lozito <james@develia.org>, (C) 2005-2006 +* +* 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 +* +*/ + +#ifndef _I_MIDI_H +#define _I_MIDI_H 1 + +#include "i_common.h" +#include <alsa/asoundlib.h> + +#define MAKE_ID(c1, c2, c3, c4) ((c1) | ((c2) << 8) | ((c3) << 16) | ((c4) << 24)) + +/* MIDI event we care of */ +#define MIDI_EVENT_NOTEOFF 1 +#define MIDI_EVENT_NOTEON 2 +#define MIDI_EVENT_KEYPRESS 3 +#define MIDI_EVENT_CONTROLLER 4 +#define MIDI_EVENT_PGMCHANGE 5 +#define MIDI_EVENT_CHANPRESS 6 +#define MIDI_EVENT_PITCHBEND 7 +#define MIDI_EVENT_SYSEX 8 +#define MIDI_EVENT_TEMPO 9 + + +struct midievent_stru { + struct midievent_stru * next; /* linked list */ + guchar type; /* SND_SEQ_EVENT_xxx */ + guchar port; /* port index */ + guint tick; + union { + guchar d[3]; /* channel and data bytes */ + gint tempo; + guint length; /* length of sysex data */ + } data; + guchar sysex[0]; +}; + +typedef struct midievent_stru midievent_t; + +typedef struct +{ + midievent_t * first_event; /* list of all events in this track */ + gint end_tick; /* length of this track */ + midievent_t * current_event; /* used while loading and playing */ +} +midifile_track_t; + +typedef struct +{ + FILE * file_pointer; + gchar * file_name; + gint file_offset; + + gint num_tracks; + midifile_track_t *tracks; + + gushort format; + guint max_tick; + gint smpte_timing; + + gint time_division; + gint ppq; + gint current_tempo; + + gint playing_tick; + gint avg_microsec_per_tick; + gint length; + + gint skip_offset; +} +midifile_t; + +extern midifile_t midifile; + +midievent_t * i_midi_file_new_event( midifile_track_t * , gint ); +void i_midi_file_skip_bytes( midifile_t * , gint ); +gint i_midi_file_read_byte( midifile_t * ); +gint i_midi_file_read_32_le( midifile_t * ); +gint i_midi_file_read_id( midifile_t * ); +gint i_midi_file_read_int( midifile_t * , gint ); +gint i_midi_file_read_var( midifile_t * ); +gint i_midi_file_read_track( midifile_t * , midifile_track_t * , gint , gint ); +gint i_midi_file_parse_riff( midifile_t * ); +gint i_midi_file_parse_smf( midifile_t * , gint ); +void i_midi_init( midifile_t * ); +void i_midi_free( midifile_t * ); +gint i_midi_setget_tempo( midifile_t * ); +void i_midi_setget_length( midifile_t * ); +void i_midi_get_bpm( midifile_t * , gint * , gint * ); + +#endif /* !_I_MIDI_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/amidi-plug/i_seq.c Thu Jan 26 18:43:59 2006 -0800 @@ -0,0 +1,425 @@ +/* +* +* Author: Giacomo Lozito <james@develia.org>, (C) 2005-2006 +* +* 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 +* +*/ + + +#include "i_seq.h" + + +/* activate sequencer client */ +gint i_seq_on( gshort with_wparse , gchar * wports_str ) +{ + if ( !i_seq_open() ) + return 0; + + if ( !i_seq_port_create() ) + { + i_seq_close(); + return 0; + } + + if ( !i_seq_queue_create() ) + { + i_seq_close(); + return 0; + } + + if (( with_wparse > 0 ) && ( wports_str )) + i_seq_port_wparse( wports_str ); + + if ( !i_seq_port_connect() ) + { + i_seq_queue_free(); + i_seq_close(); + return 0; + } + + /* success */ + return 1; +} + + +/* shutdown sequencer client */ +gint i_seq_off( void ) +{ + if ( sc.seq ) + { + i_seq_port_disconnect(); + i_seq_queue_free(); + i_seq_close(); + sc.seq = NULL; + /* return 1 here */ + return 1; + } + /* return 2 if it was already freed */ + return 2; +} + + +/* create sequencer client */ +gint i_seq_open( void ) +{ + gint err; + err = snd_seq_open(&sc.seq, "default", SND_SEQ_OPEN_DUPLEX, 0); + if (err < 0) + return 0; + snd_seq_set_client_name(sc.seq, "amidi-plug"); + return 1; +} + + +/* free sequencer client */ +gint i_seq_close( void ) +{ + if ( snd_seq_close( sc.seq ) < 0 ) + return 0; /* fail */ + else + return 1; /* success */ +} + + +/* create queue */ +gint i_seq_queue_create( void ) +{ + sc.queue = snd_seq_alloc_named_queue( sc.seq , "AMIDI-Plug" ); + if ( sc.queue < 0 ) + return 0; /* fail */ + else + return 1; /* success */ +} + + +/* free queue */ +gint i_seq_queue_free( void ) +{ + if ( snd_seq_free_queue( sc.seq , sc.queue ) < 0 ) + return 0; /* fail */ + else + return 1; /* success */ +} + + +/* queue set tempo */ +gint i_seq_queue_set_tempo( gint tempo , gint ppq ) +{ + /* interpret and set tempo */ + snd_seq_queue_tempo_alloca( &sc.queue_tempo ); + snd_seq_queue_tempo_set_tempo( sc.queue_tempo , tempo ); + snd_seq_queue_tempo_set_ppq( sc.queue_tempo , ppq ); + + if ( snd_seq_set_queue_tempo( sc.seq , sc.queue , sc.queue_tempo ) < 0 ) + { + g_warning( "Cannot set queue tempo (%u/%i)\n", + snd_seq_queue_tempo_get_tempo(sc.queue_tempo), + snd_seq_queue_tempo_get_ppq(sc.queue_tempo) ); + return 0; + } + return 1; +} + + +/* create sequencer port */ +gint i_seq_port_create( void ) +{ + sc.client_port = snd_seq_create_simple_port( sc.seq , "AMIDI-Plug" , 0 , + SND_SEQ_PORT_TYPE_MIDI_GENERIC | + SND_SEQ_PORT_TYPE_APPLICATION ); + if ( sc.client_port < 0 ) + return 0; /* fail */ + else + return 1; /* success */ +} + + +/* port connection */ +gint i_seq_port_connect( void ) +{ + gint i = 0 , err = 0; + for ( i = 0 ; i < sc.dest_port_num ; i++ ) + { + if ( snd_seq_connect_to( sc.seq , sc.client_port , + sc.dest_port[i].client , + sc.dest_port[i].port ) < 0 ) + ++err; + } + /* if these values are equal, it means + that all port connections failed */ + if ( err == i ) + return 0; /* fail */ + else + return 1; /* success */ +} + + +/* port disconnection */ +gint i_seq_port_disconnect( void ) +{ + gint i = 0 , err = 0; + for ( i = 0 ; i < sc.dest_port_num ; i++ ) + { + if ( snd_seq_disconnect_to( sc.seq , sc.client_port , + sc.dest_port[i].client , + sc.dest_port[i].port ) < 0 ) + ++err; + } + /* if these values are equal, it means + that all port disconnections failed */ + if ( err == i ) + return 0; /* fail */ + else + return 1; /* success */ +} + + +/* parse writable ports */ +gint i_seq_port_wparse( gchar * wportlist ) +{ + gint i = 0 , err = 0; + gchar **portstr = g_strsplit( wportlist , "," , 0 ); + + sc.dest_port_num = 0; + + /* fill sc.dest_port_num with the writable port number */ + while ( portstr[sc.dest_port_num] != NULL ) + ++sc.dest_port_num; + + /* check if there is already an allocated array and free it */ + if ( sc.dest_port ) + free( sc.dest_port ); + + if ( sc.dest_port_num > 0 ) + /* allocate the array of writable ports */ + sc.dest_port = calloc( sc.dest_port_num , sizeof(snd_seq_addr_t) ); + + for ( i = 0 ; i < sc.dest_port_num ; i++ ) + { + if ( snd_seq_parse_address( sc.seq , &sc.dest_port[i] , portstr[i] ) < 0 ) + ++err; + } + + g_strfreev( portstr ); + + /* if these values are equal, it means + that all port translations failed */ + if ( err == i ) + return 0; /* fail */ + else + return 1; /* success */ +} + + +/* get a list of writable ALSA MIDI ports + use the data_bucket_t here... + bint[0] = client id , bint[1] = port id + bcharp[0] = client name , bcharp[1] = port name + bpointer[0] = (not used) , bpointer[1] = (not used) */ +GSList * i_seq_port_get_list( void ) +{ + snd_seq_t * pseq; + snd_seq_open( &pseq , "default" , SND_SEQ_OPEN_DUPLEX , 0 ); + + GSList * wports = NULL; + snd_seq_client_info_t *cinfo; + snd_seq_port_info_t *pinfo; + + snd_seq_client_info_alloca( &cinfo ); + snd_seq_port_info_alloca( &pinfo ); + + snd_seq_client_info_set_client( cinfo , -1 ); + while ( snd_seq_query_next_client( pseq , cinfo ) >= 0 ) + { + gint client = snd_seq_client_info_get_client( cinfo ); + snd_seq_port_info_set_client( pinfo , client ); + snd_seq_port_info_set_port( pinfo , -1 ); + while (snd_seq_query_next_port( pseq , pinfo ) >= 0 ) + { + if ((snd_seq_port_info_get_capability(pinfo) + & (SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE)) + == (SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE)) + { + data_bucket_t * portinfo = (data_bucket_t*)g_malloc(sizeof(data_bucket_t)); + portinfo->bint[0] = snd_seq_port_info_get_client( pinfo ); + portinfo->bint[1] = snd_seq_port_info_get_port( pinfo ); + portinfo->bcharp[0] = g_strdup(snd_seq_client_info_get_name(cinfo)); + portinfo->bcharp[1] = g_strdup(snd_seq_port_info_get_name(pinfo)); + wports = g_slist_append( wports , portinfo ); + } + } + } + /* snd_seq_port_info_free( pinfo ); + snd_seq_client_info_free( cinfo ); */ + snd_seq_close( pseq ); + return wports; +} + + +void i_seq_port_free_list( GSList * wports ) +{ + GSList * start = wports; + while ( wports != NULL ) + { + data_bucket_t * portinfo = wports->data; + g_free( (gpointer)portinfo->bcharp[0] ); + g_free( (gpointer)portinfo->bcharp[1] ); + g_free( portinfo ); + wports = wports->next; + } + g_slist_free( start ); + return; +} + + +/* get a list of available sound cards and relative mixer controls; + use the data_bucket_t here... + bint[0] = card id , bint[1] = (not used) + bcharp[0] = card name , bcharp[1] = (not used) + bpointer[0] = list (GSList) of mixer controls on the card , bpointer[1] = (not used) */ +GSList * i_seq_card_get_list( void ) +{ + gint soundcard_id = -1; + GSList * scards = NULL; + + snd_card_next( &soundcard_id ); + while ( soundcard_id > -1 ) + { + /* card container */ + data_bucket_t * cardinfo = (data_bucket_t*)g_malloc(sizeof(data_bucket_t)); + cardinfo->bint[0] = soundcard_id; + /* snd_card_get_name calls strdup on its own */ + snd_card_get_name( soundcard_id , &cardinfo->bcharp[0] ); + /* for each sound card, get a list of available mixer controls */ + cardinfo->bpointer[0] = i_seq_mixctl_get_list( soundcard_id ); + + scards = g_slist_append( scards , cardinfo ); + snd_card_next( &soundcard_id ); + } + return scards; +} + + +void i_seq_card_free_list( GSList * scards ) +{ + GSList * start = scards; + while ( scards != NULL ) + { + data_bucket_t * cardinfo = scards->data; + g_free( (gpointer)cardinfo->bcharp[0] ); + g_free( cardinfo ); + scards = scards->next; + } + g_slist_free( start ); + return; +} + + +/* get a list of available mixer controls for a given sound card; + use the data_bucket_t here... + bint[0] = control id , bint[1] = (not used) + bcharp[0] = control name , bcharp[1] = (not used) + bpointer[0] = (not used) , bpointer[1] = (not used) */ +GSList * i_seq_mixctl_get_list( gint soundcard_id ) +{ + GSList * mixctls = NULL; + snd_mixer_t * mixer_h; + snd_mixer_selem_id_t * mixer_selem_id; + snd_mixer_elem_t * mixer_elem; + gchar card[10]; + + snprintf( card , 8 , "hw:%i" , soundcard_id ); + card[9] = '\0'; + + snd_mixer_selem_id_alloca( &mixer_selem_id ); + snd_mixer_open( &mixer_h , 0 ); + snd_mixer_attach( mixer_h , card ); + snd_mixer_selem_register( mixer_h , NULL , NULL ); + snd_mixer_load( mixer_h ); + for ( mixer_elem = snd_mixer_first_elem( mixer_h ) ; mixer_elem ; + mixer_elem = snd_mixer_elem_next( mixer_elem ) ) + { + data_bucket_t * mixctlinfo = (data_bucket_t*)g_malloc(sizeof(data_bucket_t)); + snd_mixer_selem_get_id( mixer_elem , mixer_selem_id ); + mixctlinfo->bint[0] = snd_mixer_selem_id_get_index(mixer_selem_id); + mixctlinfo->bcharp[0] = g_strdup(snd_mixer_selem_id_get_name(mixer_selem_id)); + mixctls = g_slist_append( mixctls , mixctlinfo ); + } + snd_mixer_close( mixer_h ); + return mixctls; +} + + +void i_seq_mixctl_free_list( GSList * mixctls ) +{ + GSList * start = mixctls; + while ( mixctls != NULL ) + { + data_bucket_t * mixctlinfo = mixctls->data; + g_free( (gpointer)mixctlinfo->bcharp[0] ); + g_free( mixctlinfo ); + mixctls = mixctls->next; + } + g_slist_free( start ); + return; +} + + +gint i_seq_mixer_set_volume( gint left_volume , gint right_volume , + gchar * mixer_card , gchar * mixer_control_name , gint mixer_control_id ) +{ + snd_mixer_t * mixer_h; + snd_mixer_selem_id_t * mixer_selem_id; + snd_mixer_elem_t * mixer_elem; + + snd_mixer_selem_id_alloca( &mixer_selem_id ); + snd_mixer_selem_id_set_index( mixer_selem_id , mixer_control_id ); + snd_mixer_selem_id_set_name( mixer_selem_id , mixer_control_name ); + + snd_mixer_open( &mixer_h , 0 ); + snd_mixer_attach( mixer_h , mixer_card ); + snd_mixer_selem_register( mixer_h , NULL , NULL); + snd_mixer_load( mixer_h ); + + mixer_elem = snd_mixer_find_selem( mixer_h , mixer_selem_id ); + + if ( ( mixer_elem ) && ( snd_mixer_selem_has_playback_volume( mixer_elem ) ) ) + { + glong pv_min , pv_max , pv_range; + + snd_mixer_selem_get_playback_volume_range( mixer_elem , &pv_min , &pv_max ); + pv_range = pv_max - pv_min; + if ( pv_range > 0 ) + { + if ( snd_mixer_selem_has_playback_channel( mixer_elem , SND_MIXER_SCHN_FRONT_LEFT ) ) + { + DEBUGMSG( "SET VOLUME requested, setting left channel to %i%%\n" , left_volume ); + snd_mixer_selem_set_playback_volume( mixer_elem , SND_MIXER_SCHN_FRONT_LEFT , + (gint)(((gdouble)pv_range * ((gdouble)left_volume*.01)) + pv_min) ); + } + if ( snd_mixer_selem_has_playback_channel( mixer_elem , SND_MIXER_SCHN_FRONT_RIGHT ) ) + { + DEBUGMSG( "SET VOLUME requested, setting right channel to %i%%\n" , right_volume ); + snd_mixer_selem_set_playback_volume( mixer_elem , SND_MIXER_SCHN_FRONT_RIGHT , + (gint)(((gdouble)pv_range * ((gdouble)right_volume*.01)) + pv_min) ); + } + } + } + + snd_mixer_close( mixer_h ); + /* for now, always return 1 here */ + return 1; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/amidi-plug/i_seq.h Thu Jan 26 18:43:59 2006 -0800 @@ -0,0 +1,61 @@ +/* +* +* Author: Giacomo Lozito <james@develia.org>, (C) 2005-2006 +* +* 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 +* +*/ + +#ifndef _I_SEQ_H +#define _I_SEQ_H 1 + +#include "i_common.h" +#include <alsa/asoundlib.h> + +typedef struct +{ + snd_seq_t * seq; + gint client_port; + gint queue; + + snd_seq_addr_t * dest_port; + gint dest_port_num; + + snd_seq_queue_tempo_t * queue_tempo; +} +sequencer_client_t; + +extern sequencer_client_t sc; + +gint i_seq_on( gshort , gchar * ); +gint i_seq_off( void ); +gint i_seq_open( void ); +gint i_seq_close( void ); +gint i_seq_port_create( void ); +gint i_seq_port_connect( void ); +gint i_seq_port_disconnect( void ); +gint i_seq_queue_create( void ); +gint i_seq_queue_free( void ); +gint i_seq_queue_set_tempo( gint , gint ); +gint i_seq_mixer_set_volume( gint , gint , gchar * , gchar * , gint ); +gint i_seq_port_wparse( gchar * ); +GSList * i_seq_port_get_list( void ); +GSList * i_seq_card_get_list( void ); +GSList * i_seq_mixctl_get_list( gint ); +void i_seq_port_free_list( GSList * ); +void i_seq_card_free_list( GSList * ); +void i_seq_mixctl_free_list( GSList * ); + +#endif /* !_I_SEQ_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/amidi-plug/i_utils.c Thu Jan 26 18:43:59 2006 -0800 @@ -0,0 +1,137 @@ +/* +* +* Author: Giacomo Lozito <james@develia.org>, (C) 2005-2006 +* +* 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 +* +*/ + + +#include "i_utils.h" +#include "amidi-plug.logo.xpm" + +static amidiplug_gui_about_t amidiplug_gui_about = { NULL }; + +void i_about_ev_destroy( void ); +void i_about_ev_bok( void ); + + +/* count the number of occurrencies of a specific character 'c' + in the string 'string' (it must be a null-terminated string) */ +gint i_util_str_count( gchar * string , gchar c ) +{ + gint i = 0 , count = 0; + while ( string[i] != '\0' ) + { + if ( string[i] == c ) + ++count; + ++i; + } + return count; +} + + +void i_about_gui( void ) +{ + GtkWidget *logoandinfo_vbox , *aboutwin_vbox; + GtkWidget *logo_image , *logo_frame; + GtkWidget *info_frame , *info_scrolledwin , *info_textview; + GtkWidget *hseparator , *hbuttonbox , *button_ok; + GtkTextBuffer *info_textbuffer; + GdkPixbuf *logo_pixbuf; + + if ( amidiplug_gui_about.about_win ) + return; + + amidiplug_gui_about.about_win = gtk_window_new( GTK_WINDOW_TOPLEVEL ); + gtk_window_set_type_hint( GTK_WINDOW(amidiplug_gui_about.about_win), GDK_WINDOW_TYPE_HINT_DIALOG ); + gtk_window_set_title( GTK_WINDOW(amidiplug_gui_about.about_win), "AMIDI-Plug - about" ); + gtk_window_set_resizable( GTK_WINDOW(amidiplug_gui_about.about_win) , FALSE ); + gtk_container_set_border_width( GTK_CONTAINER(amidiplug_gui_about.about_win), 10 ); + g_signal_connect( G_OBJECT(amidiplug_gui_about.about_win) , + "destroy" , G_CALLBACK(i_about_ev_destroy) , NULL ); + + aboutwin_vbox = gtk_vbox_new( FALSE , 0 ); + + logoandinfo_vbox = gtk_vbox_new( TRUE , 2 ); + gtk_container_add( GTK_CONTAINER(amidiplug_gui_about.about_win) , aboutwin_vbox ); + + logo_pixbuf = gdk_pixbuf_new_from_xpm_data( (const gchar **)amidiplug_xpm_logo ); + logo_image = gtk_image_new_from_pixbuf( logo_pixbuf ); + g_object_unref( logo_pixbuf ); + + logo_frame = gtk_frame_new( NULL ); + gtk_container_add( GTK_CONTAINER(logo_frame) , logo_image ); + gtk_box_pack_start( GTK_BOX(logoandinfo_vbox) , logo_frame , TRUE , TRUE , 0 ); + + info_textview = gtk_text_view_new(); + info_textbuffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(info_textview) ); + gtk_text_view_set_editable( GTK_TEXT_VIEW(info_textview) , FALSE ); + gtk_text_view_set_cursor_visible( GTK_TEXT_VIEW(info_textview) , FALSE ); + gtk_text_view_set_justification( GTK_TEXT_VIEW(info_textview) , GTK_JUSTIFY_LEFT ); + gtk_text_view_set_left_margin( GTK_TEXT_VIEW(info_textview) , 10 ); + + gtk_text_buffer_set_text( info_textbuffer , + "\nAMIDI-Plug " AMIDIPLUG_VERSION + "\nplay MIDI music through the ALSA sequencer\n" + "http://www.develia.org/projects.php?p=amidiplug\n\n" + "written by Giacomo Lozito\n" + "< james@develia.org >\n\n\n" + "special thanks to...\n\n" + "Clemens Ladisch and Jaroslav Kysela\n" + "for their cool programs aplaymidi and amixer; those\n" + "were really useful, along with alsa-lib docs, in order\n" + "to learn more about the ALSA API\n\n" + "Alfredo Spadafina\n" + "for the nice midi keyboard logo\n\n" + "Tony Vroon\n" + "for the good help with alpha testing\n\n" + , -1 ); + + info_scrolledwin = gtk_scrolled_window_new( NULL , NULL ); + gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(info_scrolledwin) , + GTK_POLICY_NEVER , GTK_POLICY_ALWAYS ); + gtk_container_add( GTK_CONTAINER(info_scrolledwin) , info_textview ); + info_frame = gtk_frame_new( NULL ); + gtk_container_add( GTK_CONTAINER(info_frame) , info_scrolledwin ); + + gtk_box_pack_start( GTK_BOX(logoandinfo_vbox) , info_frame , TRUE , TRUE , 0 ); + + gtk_box_pack_start( GTK_BOX(aboutwin_vbox) , logoandinfo_vbox , TRUE , TRUE , 0 ); + + /* horizontal separator and buttons */ + hseparator = gtk_hseparator_new(); + gtk_box_pack_start( GTK_BOX(aboutwin_vbox) , hseparator , FALSE , FALSE , 4 ); + hbuttonbox = gtk_hbutton_box_new(); + gtk_button_box_set_layout( GTK_BUTTON_BOX(hbuttonbox) , GTK_BUTTONBOX_END ); + button_ok = gtk_button_new_from_stock( GTK_STOCK_OK ); + g_signal_connect( G_OBJECT(button_ok) , "clicked" , G_CALLBACK(i_about_ev_bok) , NULL ); + gtk_container_add( GTK_CONTAINER(hbuttonbox) , button_ok ); + gtk_box_pack_start( GTK_BOX(aboutwin_vbox) , hbuttonbox , FALSE , FALSE , 0 ); + + gtk_widget_show_all( amidiplug_gui_about.about_win ); +} + + +void i_about_ev_destroy( void ) +{ + amidiplug_gui_about.about_win = NULL; +} + + +void i_about_ev_bok( void ) +{ + gtk_widget_destroy(amidiplug_gui_about.about_win); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/amidi-plug/i_utils.h Thu Jan 26 18:43:59 2006 -0800 @@ -0,0 +1,38 @@ +/* +* +* Author: Giacomo Lozito <james@develia.org>, (C) 2005-2006 +* +* 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 +* +*/ + +#ifndef _I_UTILS_H +#define _I_UTILS_H 1 + +#include "i_common.h" +#include <gtk/gtk.h> + + +typedef struct +{ + GtkWidget * about_win; +} +amidiplug_gui_about_t; + +void i_about_gui( void ); +gint i_util_str_count( gchar * , gchar ); + + +#endif /* !_I_UTILS_H */