1 /* Sound Player
2 
3    Copyright (C) 1997 by Woo-jae Jung */
4 
5 // It's an example of using MPEG Sound library
6 
7 // Anyone can use MPEG Sound library under GPL
8 
9 #ifdef HAVE_CONFIG_H
10 #include "config.h"
11 #endif
12 
13 #include <string.h>
14 #include <unistd.h>
15 #include <stdlib.h>
16 
17 #include <sys/types.h>
18 #include <sys/wait.h>
19 #include <iostream>
20 using namespace std;
21 
22 #ifdef HAVE_LIBID3
23 #include <id3/tag.h>
24 #include <id3/misc_support.h>
25 #endif /* HAVE_LIBID3 */
26 
27 #include <iomanip>
28 
29 #include "mpegsound.h"
30 
31 #include "splay.h"
32 
33 static char *help=
34 "\t-2 : playing with half frequency.\n"
35 "\t-e : exit when playing is done. (only XSPLAY)\n"
36 "\t-f : display frame and time info (played and remaining).\n"
37 "\t-m : force to mono.\n"
38 "\t-r : repeat forever.\n"
39 "\t-s : shuffle play.\n"
40 "\t-v : verbose, Very verbose, Very very verbose.\n"
41 "\t-M : playing MPEG-Audio file as standard input.\n"
42 "\t-V : display version.\n"
43 "\n"
44 "\t-k num : start playing at frame num.\n"
45 "\t-d dev  : Set dev as device or file.\n"
46 "\t-l list : list file.\n"
47 "\t-t buf  : Set number of buffer. (default : 50)\n"
48 "\n"
49 "For detail, see man pages.\n";
50 
51 /***********************/
52 /* Command line player */
53 /***********************/
54 inline void error(int n)
55 {
56   fprintf(stderr,"%s: %s\n",splay_progname,splay_Sounderrors[n-1]);
57   return;
58 }
59 
60 #ifdef PTHREADEDMPEG
61 static void playingthread(Mpegfileplayer *player)
62 {
63   if(player->geterrorcode()>0)error(player->geterrorcode());
64   else
65   {
66     player->setforcetomono(splay_forcetomonoflag);
67     player->playingwiththread(splay_verbose-1,splay_frameinfo,
68 			      splay_threadnum, splay_startframe);
69     if(player->geterrorcode()>0)error(player->geterrorcode());
70   }
71 }
72 #endif
73 
74 static void playing(Fileplayer *player)
75 {
76   if(player->geterrorcode()>0)error(player->geterrorcode());
77   else
78   {
79     player->setforcetomono(splay_forcetomonoflag);
80     player->playing(splay_verbose-1,splay_frameinfo,splay_startframe);
81     if(player->geterrorcode()>0)error(player->geterrorcode());
Panel(QWidget * parent,const char * name)82   }
83 }
84 
85 //Wrapper to convert null-string to the empty string
86 inline const char * nn(const char* str)
87 {
88   return str?str:"";
89 }
90 
91 #ifdef HAVE_LIBID3
92 
93 //List of ID3 genre names, copied from xmms.org
94 const char *ID3_gen_list[255] =
95   {
96     //0-24
97     "Blues", "Classic Rock", "Country", "Dance", "Disco",
98     "Funk", "Grunge", "Hip-Hop", "Jazz", "Metal",
99     "New Age", "Oldies", "Other", "Pop", "R&B",
100     "Rap", "Reggae", "Rock", "Techno", "Industrial",
101     "Alternative", "Ska", "Death Metal", "Pranks", "Soundtrack",
102     //25-49
103     "Euro-Techno", "Ambient", "Trip-Hop", "Vocal", "Jazz+Funk",
104     "Fusion", "Trance", "Classical", "Instrumental", "Acid",
105     "House", "Game", "Sound Clip", "Gospel", "Noise",
106     "Alt", "Bass", "Soul", "Punk", "Space",
107     "Meditative", "Instrumental Pop", "Instrumental Rock", "Ethnic", "Gothic",
108     //50-74
109     "Darkwave", "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance",
110     "Dream", "Southern Rock", "Comedy", "Cult", "Gangsta Rap",
111     "Top 40", "Christian Rap", "Pop/Funk", "Jungle", "Native American",
112     "Cabaret", "New Wave", "Psychedelic", "Rave", "Showtunes",
113     "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz",
114     //75-99
115     "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock",
116     "Folk", "Folk/Rock", "National Folk", "Swing", "Fast-Fusion",
117     "Bebob", "Latin", "Revival", "Celtic", "Bluegrass",
118     "Avantgarde", "Gothic Rock", "Progressive Rock", "Psychedelic Rock", "Symphonic Rock",
119     "Slow Rock", "Big Band", "Chorus", "Easy Listening", "Acoustic",
120     //100-124
121     "Humour", "Speech", "Chanson", "Opera", "Chamber Music",
122     "Sonata", "Symphony", "Booty Bass", "Primus", "Porn Groove",
123     "Satire", "Slow Jam", "Club", "Tango", "Samba",
124     "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle",
125     "Duet", "Punk Rock", "Drum Solo", "A Cappella", "Euro-House",
126     //125-149
127     "Dance Hall", "Goa", "Drum & Bass", "Club-House", "Hardcore",
128     "Terror", "Indie", "BritPop", "Negerpunk", "Polsk Punk",
129     "Beat", "Christian Gangsta Rap", "Heavy Metal", "Black Metal", "Crossover",
130     "Contemporary Christian", "Christian Rock", "Merengue", "Salsa", "Thrash Metal",
131     "Anime", "JPop", "Synthpop"
132 };
133 
134 ostream& operator<<(ostream& s, const ID3_Tag* tag )
135 {
136   /* this gets all frames, but the info is rather difficult to get,
137      just assume all is ID3FN_TEXT here and hope we get the most...
138   */
139   /*
140   size_t max = tag->NumFrames();
141   // s << "frames: " << max << endl;
142   for ( size_t n=0; n<max ; n++){
143     if ( ID3_Frame* frame = (*tag)[n] ){
144       s << "@@@" << frame->GetDescription() << " " <<
145 	ID3_GetString(frame,ID3FN_TEXT) << endl;
146     }
147   }
148   */
149 
150 
151   // Print just what we want...
152   s.setf(ios::left);  // The filled fields get the text to the left
153   s <<
154     "Title : " << nn(ID3_GetTitle(tag)) << endl;
155   s <<
156     "Artist: " << setw(30) << nn(ID3_GetArtist(tag)) <<
157     "Album: " << nn(ID3_GetAlbum(tag)) <<
158     endl ;
159 
160   s <<
161     "Genre : " << setw(18) << nn(ID3_gen_list[ID3_GetGenreNum(tag)]) <<
162     "Track: " << setw(5) << ID3_GetTrackNum(tag) <<
163     "Year: " <<  setw(6) << nn(ID3_GetYear(tag));
164 //   if ( ID3_GetComment(tag) ){
165 //     s << endl << "Comment:" << nn(ID3_GetComment(tag)) <<
166 //       nn(ID3_GetLyricist(tag)) << nn(ID3_GetLyrics(tag));
167 //   }
168 
169   return s;
170 }
171 #endif /* HAVE_LIBID3 */
172 
173 static void play(char *filename)
174 {
175   if( splay_verbose-- )
176     cout << filename << ":" << endl;
177   if( splay_verbose>0 )
178     {
179       //    cerr << getpid() << endl;
180 #ifdef HAVE_LIBID3
181       try {
182 	const ID3_Tag*  mytag = new ID3_Tag(filename);
183 	if ( mytag->HasV1Tag() || mytag->HasV2Tag()  )
184 	  cout << mytag << endl;
185 	delete mytag;
186 
187       }
188       catch(ID3_Error &err){
189 	cout << err.GetErrorFile() << " (" << err.GetErrorLine() << "): "
190 	     << err.GetErrorType() << ": " << err.GetErrorDesc() << endl;
191       }
192 #endif /* HAVE_LIBID3 */
193     }
194 
195   Mpegfileplayer *player;
196 
197   player=new Mpegfileplayer;
198   if(!player->openfile(filename,splay_devicename))
199     {
200       error(player->geterrorcode());
201       delete player;
202       return;
203     }
204   player->setdownfrequency(splay_downfrequency);
205 #ifdef PTHREADEDMPEG
206   playingthread(player);
207 #else
208   playing(player);
209 #endif
210   delete player;
211 }
212 
213 #include <signal.h>
214 
215 void mtest(int)
216 {
217   //  cerr << "mtest got nr " << i << endl;
218 }
219 
220 void mstop(int)
221 {
222   //  cerr << "mstop got nr " << i << endl;
223   exit(1);
224 }
225 
226 
227 int main(int argc,char *argv[])
228 {
229   int c;
230 
231   splay_progname=argv[0];
232 
233   while((c=getopt(argc,argv,
234 		  "VM2mfrsvd:k:l:"
235 #ifdef PTHREADEDMPEG
236 		  "t:"
237 #endif
238 		  ))>=0)
239   {
240     switch(c)
241     {
242       case 'V':printf("%s %s"
243 #ifdef PTHREADEDMPEG
244 		      " with pthread"
245 #endif
246 		      "\n",PACKAGE,VERSION);
247                return 0;
248       case 'M':
refreshlabel(Label * l)249 	{
250 	  Mpegfileplayer player;
251 
252 	  player.openfile(NULL,splay_devicename);
253 	  playing(&player);
254 	  return 0;
255 	}
256 
257     case '2':splay_downfrequency  =   1;break;
Setframeslider(int frame,int maxframe)258     case 'f':splay_frameinfo      =true;break;
259     case 'm':splay_forcetomonoflag=true;break;
260     case 'r':splay_repeatflag     =true;break;
261     case 's':splay_shuffleflag    =true;break;
262     case 'v':splay_verbose++;           break;
263 
initializelabel(void)264     case 'd':splay_devicename=optarg;   break;
265     case 'k':splay_startframe=atoi(optarg);   break;
266     case 'l':if(splay_verbose)
267 		fprintf(stderr,"List file : %s\n",optarg);
268 	       readlist(optarg);
269 	       break;
270 #ifdef PTHREADEDMPEG
271       case 't':
272 	{
273 	  int a;
274 
timerEvent(QTimerEvent *)275 	  sscanf(optarg,"%d",&a);
276 	  splay_threadnum=a;
277 	}
278 	break;
279 #endif
280       default:fprintf(stderr,"Bad argument.\n");
281     }
282   }
283 
284   if(argc<=optind && splay_listsize==0)
285   {
286     printf("%s %s"
287 #ifdef PTHREADEDMPEG
288 	   " with pthread"
289 #endif
290 	   "\n"
291 	   "Usage : splay [-2mrsvMVW] [-d device] [-l listfile] "
292 #ifdef PTHREADEDMPEG
293 	   "[-t number] "
294 #endif
295 	   "files ...\n"
296 	   "\n"
297 	   "%s"
298 	   ,PACKAGE,VERSION,help);
299     return 0;
300   }
301 
302   if(splay_listsize==0)    // Make list by arguments
303     arglist(argc,argv,optind);
304 
305   do
306   {
307     if(splay_shuffleflag)shufflelist();
308 
309     for(int i=0;i<splay_listsize;i++){
310       signal(SIGINT,&mtest);
311       if ( fork() ) {
312 	//	pid_t pid=getpid();
313 	//	cout << "parent process " << pid << endl;
314 	int a;
315 	wait(&a);
316 	signal(SIGINT,&mstop);
317 	//	cerr << "stoppable "<<endl;
318 	usleep (500*1000);
319 	//	cerr << "not stoppable "<<endl;
320 	signal(SIGINT,&mtest);
321       }
322       else{
323 	//	cout << "child process " << getpid() << endl;
324 	signal(SIGINT,&mstop);
325 	play(splay_list[i]);
326 	exit(0);
load()327       }
328     }
329 
330   }while(splay_repeatflag);
331 
332   return 0;
333 }
loadlist()334