diff options
Diffstat (limited to 'playlist')
-rw-r--r-- | playlist/CHANGES.LOG | 12 | ||||
-rw-r--r-- | playlist/INSTALL | 15 | ||||
-rw-r--r-- | playlist/README | 20 | ||||
-rw-r--r-- | playlist/help-playlist.pd | 37 | ||||
-rw-r--r-- | playlist/playlist.c | 748 | ||||
-rw-r--r-- | playlist/playlist.tk | 89 | ||||
-rw-r--r-- | playlist/xmms.pd | 144 |
7 files changed, 1065 insertions, 0 deletions
diff --git a/playlist/CHANGES.LOG b/playlist/CHANGES.LOG new file mode 100644 index 0000000..1b8b586 --- /dev/null +++ b/playlist/CHANGES.LOG @@ -0,0 +1,12 @@ +0.6 + added properties menu +0.5 + handle location messages with wrong argument +0.4 + added location message + fix memory allocation problems +0.3 + fixed crash when list is empty +0.2 + fixed extension saving ( all ---> ll ) +0.1 + first implementation diff --git a/playlist/INSTALL b/playlist/INSTALL new file mode 100644 index 0000000..972bba0 --- /dev/null +++ b/playlist/INSTALL @@ -0,0 +1,15 @@ +untar in /my/pd/dir/externs + +cd /my/pd/dir/externs/playlist + +make clean + +make + +make install + +open help-playlist.pd + +Thanx for getting here. +Yves/ +comments and bugs @ ydegoyon@free.fr diff --git a/playlist/README b/playlist/README new file mode 100644 index 0000000..dff1892 --- /dev/null +++ b/playlist/README @@ -0,0 +1,20 @@ +Version 0.01
+copyleft 2001 by Yves Degoyon
+tarballs and updates available @ http://ydegoyon.free.fr
+
+playlist : choose a file in 1 click with space, numeric, ... characters
+you can also send a seek message to select a file automatically.
+
+To install playlist, follow the steps from INSTALL
+
+This software is published under GPL terms.
+
+This is software with ABSOLUTELY NO WARRANTY.
+Use it at your OWN RISK. It's possible to damage e.g. hardware or your hearing
+due to a bug or for other reasons.
+We do not warrant that the program is free of infringement of any third-party
+patents.
+
+*****************************************************************************
+
+
diff --git a/playlist/help-playlist.pd b/playlist/help-playlist.pd new file mode 100644 index 0000000..f399ac3 --- /dev/null +++ b/playlist/help-playlist.pd @@ -0,0 +1,37 @@ +#N canvas 94 79 817 563 10; +#X text 28 57 Constructor : playlist <extension> <width> <height>; +#X text 88 95 playlist all 200 200; +#X text 88 107 playlist mp3 200 200; +#X text 30 78 Examples :; +#X text 80 454 Comments and bugs @ ydegoyon@free.fr; +#X symbolatom 292 399 50 0 0; +#X text 543 284 Note : you can scroll the list by dragging; +#X text 541 295 the mouse in the yellow area; +#X text 543 306 You can select and scroll in the blue area; +#X obj 292 181 playlist all 200 200; +#X msg 298 108 seek \$1; +#X text 403 90 You can seek a file in the list; +#X text 402 101 It will skip the first two items ( '.' and '..'); +#X text 402 113 and behave like a round list; +#X text 28 14 Playlist lets you switch files in one click; +#X text 27 25 It's handling most non-alpha characters gracefully; +#X floatatom 352 109 5 0 0; +#X symbolatom 333 426 50 0 0; +#X symbolatom 379 453 50 0 0; +#X msg 151 163 location ..; +#X msg 150 140 location /tmp; +#X text 60 211 You can change change location; +#X text 60 221 with a message.; +#X text 60 233 Thus \, you can initialize the object; +#X text 59 242 in a particular folder.; +#X msg 151 185 location patches; +#X obj 87 140 loadbang; +#X connect 9 0 5 0; +#X connect 9 1 17 0; +#X connect 9 2 18 0; +#X connect 10 0 9 0; +#X connect 16 0 10 0; +#X connect 19 0 9 0; +#X connect 20 0 9 0; +#X connect 25 0 9 0; +#X connect 26 0 20 0; diff --git a/playlist/playlist.c b/playlist/playlist.c new file mode 100644 index 0000000..557646f --- /dev/null +++ b/playlist/playlist.c @@ -0,0 +1,748 @@ +/*------------------------ playlist~ ------------------------------------------ */ +/* */ +/* playlist~ : lets you choose a file with 1 click */ +/* or by sending a 'seek #' message */ +/* constructor : playlist <extension> <width> <height> */ +/* */ +/* Copyleft Yves Degoyon ( ydegoyon@free.fr ) */ +/* */ +/* 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. */ +/* */ +/* See file LICENSE for further informations on licensing terms. */ +/* */ +/* 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. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* "If a man's made of blood and iron" */ +/* "Doctor, doctor, what's in my chest ????" */ +/* Gang Of Four -- Guns Before Butter */ +/* ---------------------------------------------------------------------------- */ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <math.h> +#include <ctype.h> +#include <regex.h> +#include "m_imp.h" +#include "g_canvas.h" +#include "t_tk.h" + +#ifdef NT +#include <io.h> +#else +#include <unistd.h> +#include <sys/types.h> +#include <dirent.h> +#endif + +t_widgetbehavior playlist_widgetbehavior; +static t_class *playlist_class; + +static int guidebug=0; + +static char *playlist_version = "playlist: 1 click file chooser : version 0.6, written by Yves Degoyon (ydegoyon@free.fr)"; + +#define CHAR_WIDTH 6 // average character width with font Helvetica 8 +#define MAX_DIR_LENGTH 2048 // maximum length for a directory name + +#define MIN(a,b) (a>b?b:a) + +#define SYS_VGUI2(a,b) if (guidebug) \ + post(a,b);\ + sys_vgui(a,b) + +#define SYS_VGUI3(a,b,c) if (guidebug) \ + post(a,b,c);\ + sys_vgui(a,b,c) + +#define SYS_VGUI4(a,b,c,d) if (guidebug) \ + post(a,b,c,d);\ + sys_vgui(a,b,c,d) + +#define SYS_VGUI5(a,b,c,d,e) if (guidebug) \ + post(a,b,c,d,e);\ + sys_vgui(a,b,c,d,e) + +#define SYS_VGUI6(a,b,c,d,e,f) if (guidebug) \ + post(a,b,c,d,e,f);\ + sys_vgui(a,b,c,d,e,f) + +#define SYS_VGUI7(a,b,c,d,e,f,g) if (guidebug) \ + post(a,b,c,d,e,f,g);\ + sys_vgui(a,b,c,d,e,f,g) + +#define SYS_VGUI8(a,b,c,d,e,f,g,h) if (guidebug) \ + post(a,b,c,d,e,f,g,h);\ + sys_vgui(a,b,c,d,e,f,g,h) + +#define SYS_VGUI9(a,b,c,d,e,f,g,h,i) if (guidebug) \ + post(a,b,c,d,e,f,g,h,i );\ + sys_vgui(a,b,c,d,e,f,g,h,i) + + +typedef struct _playlist +{ + t_object x_obj; + t_glist *x_glist; + t_outlet *x_fullpath; + t_outlet *x_file; + t_outlet *x_dir; + char *x_extension; /* extension to selected files */ + t_int x_height; /* height of the playlist */ + t_int x_width; /* width of the playlist */ + t_int x_itemselected; /* index of the selected item */ + t_int x_selected; /* stores selected state */ + char **x_dentries; /* directory entries */ + t_int x_nentries; /* number of entries in the current dir */ + t_int x_pnentries; /* previous size of entries list */ + t_int x_firstseen; /* first displayed entry */ + t_int x_lastseen; /* last displayed entry */ + t_int x_cdy; /* cumulated y drag */ + char *x_curdir; /* current directory informations */ +} t_playlist; + + +static void playlist_update_dir(t_playlist *x, t_glist *glist) +{ + t_canvas *canvas=glist_getcanvas(glist); + t_int i; + char wrappedname[ MAX_DIR_LENGTH ]; + + // set title + SYS_VGUI3(".x%x.c delete %xTITLE\n", glist_getcanvas(glist), x); + SYS_VGUI7(".x%x.c create text %d %d -width %d -text \"%s\" \ + -anchor w -font {Helvetica 8 bold} -tags %xTITLE\n", + canvas, + x->x_obj.te_xpix+5, + x->x_obj.te_ypix-10, + x->x_width, + x->x_curdir, + x ); + + // delete previous entries + for ( i=x->x_firstseen; i<=x->x_lastseen; i++ ) + { + SYS_VGUI4(".x%x.c delete %xENTRY%d\n", glist_getcanvas(glist), x, i); + } + + // display the content of current directory + { + t_int nentries, i; + struct dirent** dentries; /* all directory entries */ + + // post( "playlist : scandir : %s", x->x_curdir ); + if ( ( nentries = scandir(x->x_curdir, &dentries, NULL, alphasort ) ) == -1 ) + { + post( "playlist : could not scan current directory ( where the hell are you ??? )" ); + perror( "scandir" ); + return; + } + + x->x_firstseen = 0; + if ( x->x_dentries ) + { + for ( i=0; i<x->x_nentries; i++ ) + { + // post( "playlist : freeing entry %d size=%d : %s", i, strlen( x->x_dentries[i] ) + 1, x->x_dentries[i] ); + freebytes( x->x_dentries[i], strlen( x->x_dentries[i] ) + 1 ); + } + } + if ( x->x_pnentries != -1 ) + { + freebytes( x->x_dentries, x->x_pnentries*sizeof(char**) ); + } + + x->x_nentries = 0; + // post( "playlist : allocating dentries %d", nentries ); + x->x_dentries = (char **) getbytes( nentries*sizeof(char**) ) ; + x->x_pnentries = nentries; + for ( i=0; i<nentries; i++ ) + { + size_t nmatches = 0; + regmatch_t matchinfos[1]; + DIR* tmpdir; + + // ckeck if that entry should be displayed + if ( ( ( ( tmpdir = opendir( dentries[i]->d_name ) ) != NULL ) ) || + ( strstr( dentries[i]->d_name, x->x_extension ) ) || + ( !strcmp( x->x_extension, "all" ) ) + ) + { + // close temporarily opened dir + if ( tmpdir ) + { + if ( closedir( tmpdir ) < 0 ) + { + post( "playlist : could not close directory %s", dentries[i]->d_name ); + } + } + + // post( "playlist : allocating entry %d %d : %s", x->x_nentries, strlen( dentries[i]->d_name ) + 1, dentries[i]->d_name ); + x->x_dentries[x->x_nentries] = ( char * ) getbytes( strlen( dentries[i]->d_name ) + 1 ); + strcpy( x->x_dentries[x->x_nentries], dentries[i]->d_name ); + + // display the entry if displayable + if ( x->x_nentries*10+5 < x->x_height ) + { + x->x_lastseen = x->x_nentries; + strncpy( wrappedname, x->x_dentries[x->x_nentries], MIN(x->x_width/CHAR_WIDTH, MAX_DIR_LENGTH) ); + wrappedname[ x->x_width/CHAR_WIDTH ] = '\0'; + SYS_VGUI8(".x%x.c create text %d %d -fill #000000 -activefill #FF0000 -width %d -text \"%s\" \ + -anchor w -font {Helvetica 8 bold} -tags %xENTRY%d\n", + canvas, + x->x_obj.te_xpix+5, + x->x_obj.te_ypix+5+(x->x_nentries-x->x_firstseen)*10, + x->x_width, + wrappedname, + x, x->x_nentries ); + } + x->x_nentries++; + } + + } + + } +} + +void playlist_output_current(t_playlist* x) +{ + // output the selected dir+file + if ( x->x_dentries && x->x_itemselected < x->x_nentries && x->x_itemselected >= 0 ) + { + char* tmpstring = (char*) getbytes( strlen( x->x_curdir ) + strlen( x->x_dentries[x->x_itemselected]) + 2 ); + + sprintf( tmpstring, "%s/%s", x->x_curdir, x->x_dentries[x->x_itemselected] ); + outlet_symbol( x->x_dir, gensym( x->x_curdir ) ); + outlet_symbol( x->x_file, gensym( x->x_dentries[x->x_itemselected] ) ); + outlet_symbol( x->x_fullpath, gensym( tmpstring ) ); + } +} + +void playlist_draw_new(t_playlist *x, t_glist *glist) +{ + t_canvas *canvas=glist_getcanvas(glist); + + SYS_VGUI7(".x%x.c create rectangle %d %d %d %d -fill #457782 -tags %xPLAYLIST\n", + canvas, x->x_obj.te_xpix, x->x_obj.te_ypix, + x->x_obj.te_xpix + x->x_width, x->x_obj.te_ypix + x->x_height, + x); + SYS_VGUI7(".x%x.c create rectangle %d %d %d %d -fill yellow -tags %xSCROLLLIST\n", + canvas, x->x_obj.te_xpix+4*x->x_width/5, x->x_obj.te_ypix, + x->x_obj.te_xpix + x->x_width, x->x_obj.te_ypix + x->x_height, + x); + + playlist_update_dir( x, glist ); + +} + +void playlist_draw_move(t_playlist *x, t_glist *glist) +{ + t_canvas *canvas=glist_getcanvas(glist); + t_int i; + + SYS_VGUI7(".x%x.c coords %xPLAYLIST %d %d %d %d\n", + canvas, x, + x->x_obj.te_xpix, x->x_obj.te_ypix, + x->x_obj.te_xpix+x->x_width, + x->x_obj.te_ypix+x->x_height); + SYS_VGUI7(".x%x.c coords %xSCROLLLIST %d %d %d %d\n", + canvas, x, + x->x_obj.te_xpix+4*x->x_width/5, x->x_obj.te_ypix, + x->x_obj.te_xpix+x->x_width, + x->x_obj.te_ypix+x->x_height); + SYS_VGUI5(".x%x.c coords %xTITLE %d %d\n", + canvas, x, + x->x_obj.te_xpix+5, x->x_obj.te_ypix-10 ); + for ( i=x->x_firstseen; i<=x->x_lastseen; i++ ) + { + SYS_VGUI6(".x%x.c coords %xENTRY%d %d %d\n", + canvas, x, i, + x->x_obj.te_xpix+5, + x->x_obj.te_ypix+5+(i-x->x_firstseen)*10); + } + + canvas_fixlinesfor( canvas, (t_text*)x ); +} + +void playlist_draw_erase(t_playlist* x, t_glist* glist) +{ + t_canvas *canvas=glist_getcanvas(glist); + int i; + + SYS_VGUI3(".x%x.c delete %xPLAYLIST\n", canvas, x); + SYS_VGUI3(".x%x.c delete %xSCROLLLIST\n", canvas, x); + SYS_VGUI3(".x%x.c delete %xTITLE\n", canvas, x); + for ( i=x->x_firstseen; i<=x->x_lastseen; i++ ) + { + SYS_VGUI4(".x%x.c delete %xENTRY%d\n", glist_getcanvas(glist), x, i); + } +} + +void playlist_draw_select(t_playlist* x, t_glist* glist) +{ + t_canvas *canvas=glist_getcanvas(glist); + + // post( "playlist : select" ); + if(x->x_selected) + { + /* sets the item in blue */ + SYS_VGUI3(".x%x.c itemconfigure %xPLAYLIST -outline #0000FF\n", canvas, x); + } + else + { + SYS_VGUI3(".x%x.c itemconfigure %xPLAYLIST -outline #000000\n", canvas, x); + } +} + +/* ------------------------ playlist widgetbehaviour----------------------------- */ + + +void playlist_getrect(t_gobj *z, t_glist *owner, + int *xp1, int *yp1, int *xp2, int *yp2) +{ + t_playlist* x = (t_playlist*)z; + + *xp1 = x->x_obj.te_xpix; + *yp1 = x->x_obj.te_ypix; + *xp2 = x->x_obj.te_xpix+x->x_width; + *yp2 = x->x_obj.te_ypix+x->x_height; +} + +void playlist_save(t_gobj *z, t_binbuf *b) +{ + t_playlist *x = (t_playlist *)z; + + // post( "saving playlist : %s", x->x_extension ); + binbuf_addv(b, "ssiissii", gensym("#X"),gensym("obj"), + (t_int)x->x_obj.te_xpix, (t_int)x->x_obj.te_ypix, + gensym("playlist"), gensym(x->x_extension), x->x_width, x->x_height ); + binbuf_addv(b, ";"); +} + +void playlist_select(t_gobj *z, t_glist *glist, int selected) +{ + t_playlist *x = (t_playlist *)z; + + x->x_selected = selected; + + playlist_draw_select( x, glist ); +} + +void playlist_vis(t_gobj *z, t_glist *glist, int vis) +{ + t_playlist *x = (t_playlist *)z; + t_rtext *y; + + if (vis) + { + playlist_draw_new( x, glist ); + } + else + { + playlist_draw_erase( x, glist ); + } +} + +void playlist_delete(t_gobj *z, t_glist *glist) +{ + canvas_deletelinesfor( glist_getcanvas(glist), (t_text *)z); +} + +void playlist_displace(t_gobj *z, t_glist *glist, int dx, int dy) +{ + t_playlist *x = (t_playlist *)z; + int xold = x->x_obj.te_xpix; + int yold = x->x_obj.te_ypix; + + // post( "playlist_displace dx=%d dy=%d", dx, dy ); + + x->x_obj.te_xpix += dx; + x->x_obj.te_ypix += dy; + if(xold != x->x_obj.te_xpix || yold != x->x_obj.te_ypix) + { + playlist_draw_move(x, glist); + } +} + +void playlist_motion(t_playlist *x, t_floatarg dx, t_floatarg dy) +{ + int i; + + x->x_cdy+=dy; + + // check if we need to scroll + if ( ( x->x_lastseen < x->x_nentries ) ) + { + // eventually, move down + if ( ( x->x_cdy >= 3 ) && + ( x->x_firstseen < x->x_nentries - ( x->x_height/10 ) ) ) + { + x->x_cdy = 0; + if ( x->x_firstseen + 1 < x->x_nentries ) + { + for ( i=x->x_firstseen; i<=x->x_lastseen; i++ ) + { + SYS_VGUI4(".x%x.c delete %xENTRY%d\n", x->x_glist, x, i); + } + x->x_firstseen++; + for ( i=x->x_firstseen; i< x->x_nentries; i++ ) + { + char *wrappedname = (char *) getbytes( x->x_width ); + + if ( (i-x->x_firstseen)*10+5 < x->x_height ) + { + x->x_lastseen = i; + strncpy( wrappedname, x->x_dentries[i], x->x_width/CHAR_WIDTH ); + wrappedname[ x->x_width/CHAR_WIDTH ] = '\0'; + SYS_VGUI8(".x%x.c create text %d %d -fill #000000 -activefill #FF0000 -width %d -text \"%s\" \ + -anchor w -font {Helvetica 8 bold} -tags %xENTRY%d\n", + glist_getcanvas(x->x_glist), + x->x_obj.te_xpix+5, + x->x_obj.te_ypix+5+(i-x->x_firstseen)*10, + x->x_width, + wrappedname, + x, i ); + } + else break; + } + SYS_VGUI4(".x%x.c itemconfigure %xENTRY%d -fill #FF0000\n", x->x_glist, x, x->x_itemselected); + // post( "playlist : moved down first=%d last=%d", x->x_firstseen, x->x_lastseen ); + } + } + // eventually, move up + if ( ( x->x_cdy <= -3 ) && + ( x->x_lastseen >= ( x->x_height/10 ) ) ) + { + x->x_cdy = 0; + if ( x->x_firstseen - 1 >= 0 ) + { + for ( i=x->x_firstseen; i<=x->x_lastseen; i++ ) + { + SYS_VGUI4(".x%x.c delete %xENTRY%d\n", x->x_glist, x, i); + } + x->x_firstseen--; + for ( i=x->x_firstseen; i< x->x_nentries; i++ ) + { + char *wrappedname = (char *) getbytes( x->x_width ); + + if ( (i-x->x_firstseen)*10+5 < x->x_height ) + { + x->x_lastseen = i; + strncpy( wrappedname, x->x_dentries[i], x->x_width/CHAR_WIDTH ); + wrappedname[ x->x_width/CHAR_WIDTH ] = '\0'; + SYS_VGUI8(".x%x.c create text %d %d -fill #000000 -activefill #FF0000 -width %d -text \"%s\" \ + -anchor w -font {Helvetica 8 bold} -tags %xENTRY%d\n", + glist_getcanvas(x->x_glist), + x->x_obj.te_xpix+5, + x->x_obj.te_ypix+5+(i-x->x_firstseen)*10, + x->x_width, + wrappedname, + x, i ); + } + else break; + } + SYS_VGUI4(".x%x.c itemconfigure %xENTRY%d -fill #FF0000\n", x->x_glist, x, x->x_itemselected); + // post( "playlist : moved up first=%d last=%d", x->x_firstseen, x->x_lastseen ); + } + } + } // scroll test +} + + +int playlist_click(t_gobj *z, struct _glist *glist, + int xpix, int ypix, int shift, int alt, int dbl, int doit) +{ + t_playlist* x = (t_playlist *)z; + + if (doit) + { + // leave a margin for scrolling without selection + if ( (xpix-x->x_obj.te_xpix) < 4*x->x_width/5 ) + { + // deselect previously selected item + SYS_VGUI4(".x%x.c itemconfigure %xENTRY%d -fill #000000\n", x->x_glist, x, x->x_itemselected); + x->x_itemselected = x->x_firstseen + (ypix-x->x_obj.te_ypix)/10; + SYS_VGUI4(".x%x.c itemconfigure %xENTRY%d -fill #FF0000\n", x->x_glist, x, x->x_itemselected); + // post( "playlist : selected item : %d", x->x_itemselected ); + if ( x->x_dentries && ( x->x_itemselected < x->x_nentries ) ) + { + char *tmpstring = (char *) getbytes( strlen( x->x_curdir ) + strlen( x->x_dentries[x->x_itemselected] ) + 2 ); + sprintf( tmpstring, "%s/%s", x->x_curdir, x->x_dentries[x->x_itemselected] ); + // post( "playlist : chdir : %s", tmpstring ); + if ( chdir( tmpstring ) < 0 ) + { + playlist_output_current(x); + } + else + { + if ( !strcmp( x->x_dentries[ x->x_itemselected ], ".." ) ) + { + char *iamthelastslash; + + iamthelastslash = strrchr( x->x_curdir, '/' ); + *iamthelastslash = '\0'; + + if ( !strcmp( x->x_curdir, "" ) ) + { + strcpy( x->x_curdir, "/" ); + } + } + else + if ( !strcmp( x->x_dentries[ x->x_itemselected ], "." ) ) + { + // nothing + } + else + { + if ( strlen( x->x_curdir ) + strlen( x->x_dentries[x->x_itemselected] ) + 2 > MAX_DIR_LENGTH ) + { + post( "playlist : maximum dir length reached : cannot change directory" ); + return -1; + } + if ( strcmp( x->x_curdir, "/" ) ) + { + sprintf( x->x_curdir, "%s/%s", x->x_curdir, x->x_dentries[x->x_itemselected] ); + } + else + { + sprintf( x->x_curdir, "/%s", x->x_dentries[x->x_itemselected] ); + } + } + + playlist_update_dir( x, glist ); + } + } + } + glist_grab(glist, &x->x_obj.te_g, (t_glistmotionfn)playlist_motion, + 0, xpix, ypix); + } + return (1); +} + +static void playlist_properties(t_gobj *z, t_glist *owner) +{ + char buf[800]; + t_playlist *x=(t_playlist *)z; + + sprintf(buf, "pdtk_playlist_dialog %%s %s %d %d\n", + x->x_extension, x->x_width, x->x_height); + // post("playlist_properties : %s", buf ); + gfxstub_new(&x->x_obj.ob_pd, x, buf); +} + +static void playlist_dialog(t_playlist *x, t_symbol *s, int argc, t_atom *argv) +{ + if ( !x ) { + post( "playlist : error :tried to set properties on an unexisting object" ); + } + if ( argc != 3 ) + { + post( "playlist : error in the number of arguments ( %d instead of 3 )", argc ); + return; + } + if ( argv[0].a_type != A_SYMBOL || argv[1].a_type != A_FLOAT || + argv[2].a_type != A_FLOAT ) { + post( "playlist : wrong arguments" ); + return; + } + x->x_extension = argv[0].a_w.w_symbol->s_name; + x->x_width = (int)argv[1].a_w.w_float; + x->x_height = (int)argv[2].a_w.w_float; + + playlist_draw_erase(x, x->x_glist); + playlist_draw_new(x, x->x_glist); +} + + +t_playlist *playlist_new(t_symbol *extension, t_floatarg fwidth, t_floatarg fheight ) +{ + int i; + t_playlist *x; + char *tmpcurdir; + + if ( !strcmp( extension->s_name, "" ) ) + { + error( "playlist : no extension specified" ); + error( "playlist : usage : playlist <extension> <width> <height>" ); + return NULL; + } + + if ( fwidth <= 0 ) + { + error( "playlist : wrong width (%d)", fwidth ); + error( "playlist : usage : playlist <extension> <width> <height>" ); + return NULL; + } + + if ( fheight <= 0 ) + { + error( "playlist : wrong height (%d)", fheight ); + error( "playlist : usage : playlist <extension> <width> <height>" ); + return NULL; + } + + x = (t_playlist *)pd_new(playlist_class); + + x->x_width = fwidth; + x->x_height = fheight; + x->x_extension = ( char * ) getbytes( strlen( extension->s_name ) + 2 ); + sprintf( x->x_extension, "%s", extension->s_name ); + + x->x_fullpath = outlet_new(&x->x_obj, &s_symbol ); + x->x_file = outlet_new(&x->x_obj, &s_symbol ); + x->x_dir = outlet_new(&x->x_obj, &s_symbol ); + + x->x_glist = (t_glist *) canvas_getcurrent(); + x->x_nentries = 0; + x->x_pnentries = 0; + x->x_dentries = NULL; + + // get current directory full path + x->x_curdir = ( char * ) getbytes( MAX_DIR_LENGTH ); + if ( ( tmpcurdir = getenv( "PWD" ) ) == NULL ) + { + post( "playlist : could not get current directory ( where the hell are you ??? )" ); + return NULL; + } + strncpy( x->x_curdir, tmpcurdir, strlen( tmpcurdir ) ); + x->x_curdir[ strlen( tmpcurdir ) ] = '\0'; + + x->x_selected = 0; + x->x_itemselected = -1; + + // post( "playlist : built extension=%s width=%d height=%d", x->x_extension, x->x_width, x->x_height ); + + return (x); +} + +void playlist_free(t_playlist *x) +{ + // post( "playlist : playlist_free" ); + if ( x->x_extension ) + { + freebytes( x->x_extension, strlen( x->x_extension ) ); + } + if ( x->x_curdir ) + { + freebytes( x->x_curdir, MAX_DIR_LENGTH ); + } +} + +void playlist_seek(t_playlist *x, t_floatarg fseeked) +{ + int iout=0; + + if ( fseeked < 0 ) + { + post( "playlist : wrong searched file : %f", fseeked ); + return; + } + + if ( x->x_nentries > 2 ) + { + // do not select . or .. + iout = (int)fseeked % (x->x_nentries-2) + 2; + } + else + { + return; + } + SYS_VGUI4(".x%x.c itemconfigure %xENTRY%d -fill #000000\n", x->x_glist, x, x->x_itemselected); + x->x_itemselected = iout; + SYS_VGUI4(".x%x.c itemconfigure %xENTRY%d -fill #FF0000\n", x->x_glist, x, x->x_itemselected); + playlist_output_current(x); +} + +void playlist_location(t_playlist *x, t_symbol *flocation) +{ + int iout=0; + char olddir[ MAX_DIR_LENGTH ]; /* remember old location */ + + strcpy( olddir, x->x_curdir ); + + if ( !strcmp( flocation->s_name, ".." ) ) + { + char *iamthelastslash; + + iamthelastslash = strrchr( x->x_curdir, '/' ); + *iamthelastslash = '\0'; + + if ( !strcmp( x->x_curdir, "" ) ) + { + strcpy( x->x_curdir, "/" ); + } + } + else + if ( !strncmp( flocation->s_name, "/", 1 ) ) + { + // absolute path required + if ( strlen( flocation->s_name ) >= MAX_DIR_LENGTH ) + { + error( "playlist : maximum dir length reached : cannot change directory" ); + return; + } + strncpy( x->x_curdir, flocation->s_name, MAX_DIR_LENGTH ); + } + else + { + // relative path + if ( strlen( x->x_curdir ) + strlen( flocation->s_name ) + 2 > MAX_DIR_LENGTH ) + { + post( "playlist : maximum dir length reached : cannot change directory" ); + return; + } + if ( strcmp( x->x_curdir, "/" ) ) + { + sprintf( x->x_curdir, "%s/%s", x->x_curdir, flocation->s_name ); + } + else + { + sprintf( x->x_curdir, "/%s", flocation->s_name ); + } + } + + if ( chdir( x->x_curdir ) < 0 ) + { + error( "playlist : requested location >%s< is not a directory", x->x_curdir ); + strcpy( x->x_curdir, olddir ); + return; + } + + playlist_update_dir( x, x->x_glist ); +} + +void playlist_setup(void) +{ + post( playlist_version ); +#include "playlist.tk2c" + playlist_class = class_new(gensym("playlist"), (t_newmethod)playlist_new, + (t_method)playlist_free, sizeof(t_playlist), + CLASS_DEFAULT, A_SYMBOL, A_FLOAT, A_FLOAT, 0); + class_addmethod(playlist_class, (t_method)playlist_seek, gensym("seek"), A_FLOAT, 0 ); + class_addmethod(playlist_class, (t_method)playlist_location, gensym("location"), A_SYMBOL, 0 ); + class_addmethod(playlist_class, (t_method)playlist_dialog, gensym("dialog"), A_GIMME, 0 ); + + playlist_widgetbehavior.w_getrectfn = playlist_getrect; + playlist_widgetbehavior.w_displacefn = playlist_displace; + playlist_widgetbehavior.w_selectfn = playlist_select; + playlist_widgetbehavior.w_activatefn = NULL; + playlist_widgetbehavior.w_deletefn = playlist_delete; + playlist_widgetbehavior.w_visfn = playlist_vis; + playlist_widgetbehavior.w_clickfn = playlist_click; + playlist_widgetbehavior.w_propertiesfn = playlist_properties; + playlist_widgetbehavior.w_savefn = playlist_save; + class_setwidget(playlist_class, &playlist_widgetbehavior); + class_sethelpsymbol(playlist_class, gensym("help-playlist.pd")); +} diff --git a/playlist/playlist.tk b/playlist/playlist.tk new file mode 100644 index 0000000..025c312 --- /dev/null +++ b/playlist/playlist.tk @@ -0,0 +1,89 @@ +############ playlist procedures -- ydegoyon@free.fr ######### + +proc playlist_apply {id} { +# strip "." from the TK id to make a variable name suffix + set vid [string trimleft $id .] +# for each variable, make a local variable to hold its name... + set var_graph_extension [concat graph_extension_$vid] + global $var_graph_extension + set var_graph_width [concat graph_width_$vid] + global $var_graph_width + set var_graph_height [concat graph_height$vid] + global $var_graph_height + + set cmd [concat $id dialog \ + [eval concat $$var_graph_extension] \ + [eval concat $$var_graph_width] \ + [eval concat $$var_graph_height] \ + \;] + #puts stderr $cmd + pd $cmd +} + +proc playlist_cancel {id} { + set cmd [concat $id cancel \;] + #puts stderr $cmd + pd $cmd +} + +proc playlist_ok {id} { + playlist_apply $id + playlist_cancel $id +} + +proc pdtk_playlist_dialog {id extension width height} { + set vid [string trimleft $id .] + set var_graph_extension [concat graph_extension_$vid] + global $var_graph_extension + set var_graph_width [concat graph_width_$vid] + global $var_graph_width + set var_graph_height [concat graph_height$vid] + global $var_graph_height + + set $var_graph_extension $extension + set $var_graph_width $width + set $var_graph_height $height + + toplevel $id + wm title $id {playlist} + wm protocol $id WM_DELETE_WINDOW [concat playlist_cancel $id] + + label $id.label -text {PLAYLIST PROPERTIES} + pack $id.label -side top + + frame $id.buttonframe + pack $id.buttonframe -side bottom -fill x -pady 2m + button $id.buttonframe.cancel -text {Cancel}\ + -command "playlist_cancel $id" + button $id.buttonframe.apply -text {Apply}\ + -command "playlist_apply $id" + button $id.buttonframe.ok -text {OK}\ + -command "playlist_ok $id" + pack $id.buttonframe.cancel -side left -expand 1 + pack $id.buttonframe.apply -side left -expand 1 + pack $id.buttonframe.ok -side left -expand 1 + + frame $id.1rangef + pack $id.1rangef -side top + label $id.1rangef.lextension -text "Files Extension :" + entry $id.1rangef.extension -textvariable $var_graph_extension -width 7 + pack $id.1rangef.lextension $id.1rangef.extension -side left + + frame $id.2rangef + pack $id.2rangef -side top + label $id.2rangef.lwidth -text "Width :" + entry $id.2rangef.width -textvariable $var_graph_width -width 7 + pack $id.2rangef.lwidth $id.2rangef.width -side left + + frame $id.3rangef + pack $id.3rangef -side top + label $id.3rangef.lheight -text "Height :" + entry $id.3rangef.height -textvariable $var_graph_height -width 7 + pack $id.3rangef.lheight $id.3rangef.height -side left + + bind $id.1rangef.extension <KeyPress-Return> [concat playlist_ok $id] + bind $id.2rangef.width <KeyPress-Return> [concat playlist_ok $id] + bind $id.3rangef.height <KeyPress-Return> [concat playlist_ok $id] +} + +############ playlist procedures END -- ydegoyon@free.fr ######### diff --git a/playlist/xmms.pd b/playlist/xmms.pd new file mode 100644 index 0000000..b9282cd --- /dev/null +++ b/playlist/xmms.pd @@ -0,0 +1,144 @@ +#N canvas 146 29 755 574 10; +#X obj 411 144 mp3fileout~; +#X floatatom 411 165 5 0 0; +#X floatatom 456 165 5 0 0; +#X msg 409 113 open \$1; +#X msg 466 113 start; +#X msg 511 114 stop; +#X text 534 154 Number of frames emitted; +#X text 396 184 Connection state; +#X symbolatom 127 286 80 0 0; +#X floatatom 520 63 5 0 0; +#X obj 20 57 playlist mp3 300 200; +#X msg 651 37 bang; +#X text 23 17 Step 1 : point to your MP3s directory; +#X obj 357 513 dac~; +#X symbolatom 131 438 10 0 0; +#X text 127 452 Incomer's address; +#X obj 349 470 *~ 1; +#X floatatom 461 513 5 0 0; +#X obj 427 513 / 100; +#X obj 390 470 *~ 1; +#X text 501 515 Volume; +#X msg 336 38 connect localhost 5672; +#X obj 95 341 mp3streamin~ 5672 1; +#X text 295 15 Step 2 : connect to the streamer; +#X text 65 285 Playing :; +#X msg 463 64 seek \$1; +#X text 566 11 Step 3 :start random play; +#X obj 657 410 loadbang; +#X msg 656 434 \; pd dsp 1; +#X msg 379 220 seek \$1; +#X obj 437 219 hsl 128 15 0 1e+07 0 0 empty empty empty 20 8 0 8 -262144 +-1 -1 0 0; +#X msg 547 114 disconnect; +#X obj 573 37 random 1000; +#X msg 620 73 seed \$1; +#X floatatom 673 73 5 0 0; +#X msg 634 220 bang; +#X text 575 264 Step 3 bis :start seq play; +#X obj 592 220 countn; +#X obj 578 242 - 1; +#X floatatom 531 243 5 0 0; +#X obj 551 187 spigot; +#X obj 599 186 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 0 +1; +#X msg 624 186 1; +#X obj 618 95 spigot; +#X obj 666 94 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 1 1 +; +#X msg 691 94 1; +#X obj 362 441 ekwalizer --------------------------; +#X msg 544 315 100; +#X obj 385 343 vsl 15 80 0 100 0 0 empty empty empty 20 8 0 8 -262144 +-1 -1 7900 1; +#X obj 408 343 vsl 15 80 0 100 0 0 empty empty empty 20 8 0 8 -262144 +-1 -1 7900 1; +#X obj 432 343 vsl 15 80 0 100 0 0 empty empty empty 20 8 0 8 -262144 +-1 -1 7900 1; +#X obj 454 343 vsl 15 80 0 100 0 0 empty empty empty 20 8 0 8 -262144 +-1 -1 7900 1; +#X obj 477 343 vsl 15 80 0 100 0 0 empty empty empty 20 8 0 8 -262144 +-1 -1 0 1; +#X obj 498 343 vsl 15 80 0 100 0 0 empty empty empty 20 8 0 8 -262144 +-1 -1 0 1; +#X obj 516 343 vsl 15 80 0 100 0 0 empty empty empty 20 8 0 8 -262144 +-1 -1 0 1; +#X obj 534 343 vsl 15 80 0 100 0 0 empty empty empty 20 8 0 8 -262144 +-1 -1 0 1; +#X obj 552 343 vsl 15 80 0 100 0 0 empty empty empty 20 8 0 8 -262144 +-1 -1 0 1; +#X obj 573 343 vsl 15 80 0 100 0 0 empty empty empty 20 8 0 8 -262144 +-1 -1 0 1; +#X obj 579 315 loadbang; +#X obj 494 539 loadbang; +#X msg 463 539 50; +#X obj 259 486 compressor~; +#X floatatom 279 434 5 0 0; +#X obj 241 509 env~; +#X obj 266 463 / 100; +#X connect 0 0 1 0; +#X connect 0 1 2 0; +#X connect 0 2 40 0; +#X connect 0 2 43 0; +#X connect 3 0 0 0; +#X connect 4 0 0 0; +#X connect 5 0 0 0; +#X connect 10 0 8 0; +#X connect 10 0 3 0; +#X connect 11 0 32 0; +#X connect 11 0 45 0; +#X connect 16 0 61 0; +#X connect 17 0 18 0; +#X connect 18 0 16 1; +#X connect 18 0 19 1; +#X connect 19 0 61 0; +#X connect 21 0 0 0; +#X connect 21 0 4 0; +#X connect 22 0 46 0; +#X connect 22 1 46 0; +#X connect 22 2 14 0; +#X connect 25 0 10 0; +#X connect 27 0 28 0; +#X connect 29 0 0 0; +#X connect 30 0 29 0; +#X connect 31 0 0 0; +#X connect 32 0 9 0; +#X connect 32 0 25 0; +#X connect 33 0 32 0; +#X connect 34 0 33 0; +#X connect 35 0 37 0; +#X connect 35 0 42 0; +#X connect 37 0 38 0; +#X connect 38 0 25 0; +#X connect 38 0 39 0; +#X connect 40 0 37 0; +#X connect 41 0 40 1; +#X connect 42 0 41 0; +#X connect 43 0 32 0; +#X connect 44 0 43 1; +#X connect 45 0 44 0; +#X connect 46 0 19 0; +#X connect 46 0 16 0; +#X connect 47 0 48 0; +#X connect 47 0 49 0; +#X connect 47 0 50 0; +#X connect 47 0 51 0; +#X connect 48 0 46 1; +#X connect 49 0 46 2; +#X connect 50 0 46 3; +#X connect 51 0 46 4; +#X connect 52 0 46 5; +#X connect 53 0 46 6; +#X connect 54 0 46 7; +#X connect 55 0 46 8; +#X connect 56 0 46 9; +#X connect 57 0 46 10; +#X connect 58 0 47 0; +#X connect 59 0 60 0; +#X connect 60 0 17 0; +#X connect 61 0 13 0; +#X connect 61 0 13 1; +#X connect 61 0 63 0; +#X connect 62 0 64 0; +#X connect 64 0 61 1; |