1 /* Copyright (c) 1997-1999 Miller Puckette and others.
2 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
3 * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
6 * hacked the code to add advanced multidevice-support
7 * 1311:forum::für::umläute:2001
10 char pd_version
[] = "Pd version 0.37.4\n";
11 char pd_compiletime
[] = __TIME__
;
12 char pd_compiledate
[] = __DATE__
;
17 #include <sys/types.h>
35 int sys_argparse(int argc
, char **argv
);
36 void sys_findprogdir(char *progname
);
37 int sys_startgui(const char *guipath
);
39 int m_scheduler(void);
40 void sys_addhelppath(char *p
);
41 void alsa_adddev(char *name
);
50 static t_symbol
*sys_guidir
;
51 static t_namelist
*sys_externlist
;
52 static t_namelist
*sys_openlist
;
53 static t_namelist
*sys_messagelist
;
54 static int sys_version
;
55 int sys_oldtclversion
; /* hack to warn g_rtext.c about old text sel */
63 int sys_midiindevlist
[MAXMIDIINDEV
] = {1};
64 int sys_midioutdevlist
[MAXMIDIOUTDEV
] = {1};
66 static int sys_main_srate
= DEFAULTSRATE
;
67 static int sys_main_advance
= DEFAULTADVANCE
;
71 /* here the "-1" counts signify that the corresponding vector hasn't been
72 specified in command line arguments; sys_open_audio will detect this
73 and fill things in. */
74 int sys_nsoundin
= -1;
75 int sys_nsoundout
= -1;
76 int sys_soundindevlist
[MAXAUDIOINDEV
];
77 int sys_soundoutdevlist
[MAXAUDIOOUTDEV
];
81 int sys_chinlist
[MAXAUDIOINDEV
];
82 int sys_choutlist
[MAXAUDIOOUTDEV
];
86 typedef struct _fontinfo
96 /* these give the nominal point size and maximum height of the characters
99 static t_fontinfo sys_fontlist
[] = {
100 {8, 5, 9, 0, 0, 0}, {10, 7, 13, 0, 0, 0}, {12, 9, 16, 0, 0, 0},
101 {16, 10, 20, 0, 0, 0}, {24, 15, 25, 0, 0, 0}, {36, 25, 45, 0, 0, 0}};
102 #define NFONT (sizeof(sys_fontlist)/sizeof(*sys_fontlist))
104 /* here are the actual font size structs on msp's systems:
109 font 16 10 20 16 10 18
110 font 24 15 25 16 10 18
111 font 36 25 42 36 22 41
117 font 16 10 20 16 10 19
118 font 24 15 25 24 15 24
119 font 36 25 42 36 22 41
122 static t_fontinfo
*sys_findfont(int fontsize
)
126 for (i
= 0, fi
= sys_fontlist
; i
< (NFONT
-1); i
++, fi
++)
127 if (fontsize
< fi
[1].fi_fontsize
) return (fi
);
128 return (sys_fontlist
+ (NFONT
-1));
131 int sys_nearestfontsize(int fontsize
)
133 return (sys_findfont(fontsize
)->fi_fontsize
);
136 int sys_hostfontsize(int fontsize
)
138 return (sys_findfont(fontsize
)->fi_hostfontsize
);
141 int sys_fontwidth(int fontsize
)
143 return (sys_findfont(fontsize
)->fi_width
);
146 int sys_fontheight(int fontsize
)
148 return (sys_findfont(fontsize
)->fi_height
);
153 #define DEFAULTFONT 12
155 #define DEFAULTFONT 10
158 static void openit(const char *dirname
, const char *filename
)
160 char dirbuf
[MAXPDSTRING
], *nameptr
;
161 int fd
= open_via_path(dirname
, filename
, "", dirbuf
, &nameptr
,
166 glob_evalfile(0, gensym(nameptr
), gensym(dirbuf
));
169 error("%s: can't open", filename
);
174 /* this is called from the gui process. The first argument is the cwd, and
175 succeeding args give the widths and heights of known fonts. We wait until
176 these are known to open files and send messages specified on the command line.
177 We ask the GUI to specify the "cwd" in case we don't have a local OS to get it
178 from; for instance we could be some kind of RT embedded system. However, to
179 really make this make sense we would have to implement
180 open(), read(), etc, calls to be served somehow from the GUI too. */
182 void glob_initfromgui(void *dummy
, t_symbol
*s
, int argc
, t_atom
*argv
)
184 char *cwd
= atom_getsymbolarg(0, argc
, argv
)->s_name
;
187 if (argc
!= 2 + 3 * NHOSTFONT
) bug("glob_initfromgui");
188 for (i
= 0; i
< NFONT
; i
++)
190 int wantheight
= sys_fontlist
[i
].fi_maxheight
;
191 for (j
= 0; j
< NHOSTFONT
-1; j
++)
193 if (atom_getintarg(3 * (j
+ 1) + 3, argc
, argv
) > wantheight
)
196 /* j is now the "real" font index for the desired font index i. */
197 sys_fontlist
[i
].fi_hostfontsize
= atom_getintarg(3 * j
+ 1, argc
, argv
);
198 sys_fontlist
[i
].fi_width
= atom_getintarg(3 * j
+ 2, argc
, argv
);
199 sys_fontlist
[i
].fi_height
= atom_getintarg(3 * j
+ 3, argc
, argv
);
202 for (i
= 0; i
< 6; i
++)
203 fprintf(stderr
, "font %d %d %d %d %d\n",
204 sys_fontlist
[i
].fi_fontsize
,
205 sys_fontlist
[i
].fi_maxheight
,
206 sys_fontlist
[i
].fi_hostfontsize
,
207 sys_fontlist
[i
].fi_width
,
208 sys_fontlist
[i
].fi_height
);
210 /* load dynamic libraries specified with "-lib" args */
211 for (nl
= sys_externlist
; nl
; nl
= nl
->nl_next
)
212 if (!sys_load_lib(cwd
, nl
->nl_string
))
213 post("%s: can't load library", nl
->nl_string
);
214 namelist_free(sys_externlist
);
216 /* open patches specifies with "-open" args */
217 for (nl
= sys_openlist
; nl
; nl
= nl
->nl_next
)
218 openit(cwd
, nl
->nl_string
);
219 namelist_free(sys_openlist
);
221 /* send messages specified with "-send" args */
222 for (nl
= sys_messagelist
; nl
; nl
= nl
->nl_next
)
224 t_binbuf
*b
= binbuf_new();
225 binbuf_text(b
, nl
->nl_string
, strlen(nl
->nl_string
));
226 binbuf_eval(b
, 0, 0, 0);
229 namelist_free(sys_messagelist
);
231 sys_oldtclversion
= atom_getfloatarg(1 + 3 * NHOSTFONT
, argc
, argv
);
234 static void sys_afterargparse(void);
236 /* this is called from main() in s_entry.c */
237 int sys_main(int argc
, char **argv
)
240 fprintf(stderr
, "Pd: COMPILED FOR DEBUGGING\n");
243 sys_findprogdir(argv
[0]); /* set sys_progname, guipath */
245 sys_rcfile(); /* parse the startup file */
247 if (sys_argparse(argc
, argv
)) /* parse cmd line */
249 sys_afterargparse(); /* post-argparse settings */
250 if (sys_verbose
|| sys_version
) fprintf(stderr
, "%scompiled %s %s\n",
251 pd_version
, pd_compiletime
, pd_compiledate
);
252 if (sys_version
) /* if we were just asked our version, exit here. */
254 if (sys_startgui(sys_guidir
->s_name
)) /* start the gui */
256 /* open audio and MIDI */
257 sys_open_midi(sys_nmidiin
, sys_midiindevlist
,
258 sys_nmidiout
, sys_midioutdevlist
);
259 sys_open_audio(sys_nsoundin
, sys_soundindevlist
, sys_nchin
, sys_chinlist
,
260 sys_nsoundout
, sys_soundoutdevlist
, sys_nchout
, sys_choutlist
,
261 sys_main_srate
, sys_main_advance
, 1);
262 /* run scheduler until it quits */
264 return (m_scheduler_pda());
265 return (m_scheduler());
268 static char *(usagemessage
[]) = {
269 "usage: pd [-flags] [file]...\n",
270 "\naudio configuration flags:\n",
271 "-r <n> -- specify sample rate\n",
272 "-audioindev ... -- audio in devices; e.g., \"1,3\" for first and third\n",
273 "-audiooutdev ... -- audio out devices (same)\n",
274 "-audiodev ... -- specify input and output together\n",
275 "-inchannels ... -- audio input channels (by device, like \"2\" or \"16,8\")\n",
276 "-outchannels ... -- number of audio out channels (same)\n",
277 "-channels ... -- specify both input and output channels\n",
278 "-audiobuf <n> -- specify size of audio buffer in msec\n",
279 "-blocksize <n> -- specify audio I/O block size in sample frames\n",
280 "-sleepgrain <n> -- specify number of milliseconds to sleep when idle\n",
281 "-nodac -- suppress audio output\n",
282 "-noadc -- suppress audio input\n",
283 "-noaudio -- suppress audio input and output (-nosound is synonym) \n",
284 "-listdev -- list audio and MIDI devices\n",
287 "-oss -- use OSS audio API\n",
288 "-32bit ----- allow 32 bit OSS audio (for RME Hammerfall)\n",
292 "-alsa -- use ALSA audio API\n",
293 "-alsaadd <name> -- add an ALSA device name to list\n",
294 "-alsadev <n> ----- obsolete: use -audiodev\n",
298 "-jack -- use JACK audio API\n",
301 #ifdef USEAPI_PORTAUDIO
303 "-asio -- use ASIO audio driver (via Portaudio)\n",
304 "-pa -- synonym for -asio\n",
306 "-pa -- use Portaudio API\n",
311 "-mmio -- use MMIO audio API (default for Windows)\n",
313 " (default audio API for this platform: ", API_DEFSTRING
, ")\n\n",
315 "\nMIDI configuration flags:\n",
316 "-midiindev ... -- midi in device list; e.g., \"1,3\" for first and third\n",
317 "-midioutdev ... -- midi out device list, same format\n",
318 "-mididev ... -- specify -midioutdev and -midiindev together\n",
319 "-nomidiin -- suppress MIDI input\n",
320 "-nomidiout -- suppress MIDI output\n",
321 "-nomidi -- suppress MIDI input and output\n",
324 "-path <path> -- add to file search path\n",
325 "-helppath <path> -- add to help file search path\n",
326 "-open <file> -- open file(s) on startup\n",
327 "-lib <file> -- load object library(s)\n",
328 "-font <n> -- specify default font size in points\n",
329 "-verbose -- extra printout on startup and when searching for files\n",
330 "-version -- don't run Pd; just print out which version it is \n",
331 "-d <n> -- specify debug level\n",
332 "-noloadbang -- suppress all loadbangs\n",
333 "-nogui -- suppress starting the GUI\n",
334 "-stdin -- scan stdin for keypresses\n",
335 "-guicmd \"cmd...\" -- substitute another GUI program (e.g., rsh)\n",
336 "-send \"msg...\" -- send a message at startup (after patches are loaded)\n",
338 "-rt or -realtime -- use real-time priority\n",
339 "-nrt -- don't use real-time priority\n",
343 static void sys_parsedevlist(int *np
, int *vecp
, int max
, char *str
)
352 vecp
[n
] = strtol(str
, &endp
, 10);
364 static int sys_getmultidevchannels(int n
, int *devlist
)
369 while(n
--)sum
+=*devlist
++;
374 /* this routine tries to figure out where to find the auxilliary files
375 Pd will need to run. This is either done by looking at the command line
376 invokation for Pd, or if that fails, by consulting the variable
377 INSTALL_PREFIX. In MSW, we don't try to use INSTALL_PREFIX. */
378 void sys_findprogdir(char *progname
)
380 char sbuf
[MAXPDSTRING
], sbuf2
[MAXPDSTRING
], *sp
;
386 /* find out by what string Pd was invoked; put answer in "sbuf". */
388 GetModuleFileName(NULL
, sbuf2
, sizeof(sbuf2
));
389 sbuf2
[MAXPDSTRING
-1] = 0;
390 sys_unbashfilename(sbuf2
, sbuf
);
393 strncpy(sbuf
, progname
, MAXPDSTRING
);
394 sbuf
[MAXPDSTRING
-1] = 0;
396 lastslash
= strrchr(sbuf
, '/');
399 /* bash last slash to zero so that sbuf is directory pd was in,
402 /* go back to the parent from there, e.g., ~/pd */
403 lastslash
= strrchr(sbuf
, '/');
406 strncpy(sbuf2
, sbuf
, lastslash
-sbuf
);
407 sbuf2
[lastslash
-sbuf
] = 0;
409 else strcpy(sbuf2
, "..");
413 /* no slashes found. Try INSTALL_PREFIX. */
414 #ifdef INSTALL_PREFIX
415 strcpy(sbuf2
, INSTALL_PREFIX
);
420 /* now we believe sbuf2 holds the parent directory of the directory
421 pd was found in. We now want to infer the "lib" directory and the
422 "gui" directory. In "simple" UNIX installations, the layout is
426 and in "complicated" UNIX installations, it's:
428 .../lib/pd/bin/pd-gui
430 To decide which, we stat .../lib/pd; if that exists, we assume it's
431 the complicated layout. In MSW, it's the "simple" layout, but
432 the gui program is straight wish80:
438 strncpy(sbuf
, sbuf2
, MAXPDSTRING
-30);
439 sbuf
[MAXPDSTRING
-30] = 0;
440 strcat(sbuf
, "/lib/pd");
441 if (stat(sbuf
, &statbuf
) >= 0)
443 /* complicated layout: lib dir is the one we just stat-ed above */
444 sys_libdir
= gensym(sbuf
);
445 /* gui lives in .../lib/pd/bin */
446 strncpy(sbuf
, sbuf2
, MAXPDSTRING
-30);
447 sbuf
[MAXPDSTRING
-30] = 0;
448 strcat(sbuf
, "/lib/pd/bin");
449 sys_guidir
= gensym(sbuf
);
453 /* simple layout: lib dir is the parent */
454 sys_libdir
= gensym(sbuf2
);
455 /* gui lives in .../bin */
456 strncpy(sbuf
, sbuf2
, MAXPDSTRING
-30);
457 sbuf
[MAXPDSTRING
-30] = 0;
458 strcat(sbuf
, "/bin");
459 sys_guidir
= gensym(sbuf
);
463 sys_libdir
= gensym(sbuf2
);
464 sys_guidir
= &s_
; /* in MSW the guipath just depends on the libdir */
469 static int sys_mmio
= 1;
471 static int sys_mmio
= 0;
474 int sys_argparse(int argc
, char **argv
)
476 char sbuf
[MAXPDSTRING
];
479 while ((argc
> 0) && **argv
== '-')
481 if (!strcmp(*argv
, "-r") && argc
> 1 &&
482 sscanf(argv
[1], "%d", &sys_main_srate
) >= 1)
487 else if (!strcmp(*argv
, "-inchannels"))
489 sys_parsedevlist(&sys_nchin
,
490 sys_chinlist
, MAXAUDIOINDEV
, argv
[1]);
495 argc
-= 2; argv
+= 2;
497 else if (!strcmp(*argv
, "-outchannels"))
499 sys_parsedevlist(&sys_nchout
, sys_choutlist
,
500 MAXAUDIOOUTDEV
, argv
[1]);
505 argc
-= 2; argv
+= 2;
507 else if (!strcmp(*argv
, "-channels"))
509 sys_parsedevlist(&sys_nchin
, sys_chinlist
,MAXAUDIOINDEV
,
511 sys_parsedevlist(&sys_nchout
, sys_choutlist
,MAXAUDIOOUTDEV
,
517 argc
-= 2; argv
+= 2;
519 else if (!strcmp(*argv
, "-soundbuf") || !strcmp(*argv
, "-audiobuf"))
521 sys_main_advance
= atoi(argv
[1]);
522 argc
-= 2; argv
+= 2;
524 else if (!strcmp(*argv
, "-blocksize"))
526 sys_setblocksize(atoi(argv
[1]));
527 argc
-= 2; argv
+= 2;
529 else if (!strcmp(*argv
, "-sleepgrain"))
531 sys_sleepgrain
= 1000 * atoi(argv
[1]);
532 argc
-= 2; argv
+= 2;
534 else if (!strcmp(*argv
, "-nodac"))
540 else if (!strcmp(*argv
, "-noadc"))
546 else if (!strcmp(*argv
, "-nosound") || !strcmp(*argv
, "-noaudio"))
548 sys_nsoundin
=sys_nsoundout
= 0;
549 sys_nchin
= sys_nchout
= 0;
553 else if (!strcmp(*argv
, "-oss"))
555 sys_set_audio_api(API_OSS
);
558 else if (!strcmp(*argv
, "-32bit"))
560 sys_set_audio_api(API_OSS
);
566 else if (!strcmp(*argv
, "-alsa"))
568 sys_set_audio_api(API_ALSA
);
571 else if (!strcmp(*argv
, "-alsaadd"))
574 alsa_adddev(argv
[1]);
578 /* obsolete flag for setting ALSA device number or name */
579 else if (!strcmp(*argv
, "-alsadev"))
582 if (argv
[1][0] >= '1' && argv
[1][0] <= '9')
583 devno
= 1 + 2 * (atoi(argv
[1]) - 1);
584 else if (!strncmp(argv
[1], "hw:", 3))
585 devno
= 1 + 2 * atoi(argv
[1]+3);
586 else if (!strncmp(argv
[1], "plughw:", 7))
587 devno
= 2 + 2 * atoi(argv
[1]+7);
589 sys_nsoundin
= sys_nsoundout
= 1;
590 sys_soundindevlist
[0] = sys_soundoutdevlist
[0] = devno
;
591 sys_set_audio_api(API_ALSA
);
596 else if (!strcmp(*argv
, "-jack"))
598 sys_set_audio_api(API_JACK
);
602 #ifdef USEAPI_PORTAUDIO
603 else if (!strcmp(*argv
, "-pa") || !strcmp(*argv
, "-portaudio")
605 || !strcmp(*argv
, "-asio")
609 sys_set_audio_api(API_PORTAUDIO
);
615 else if (!strcmp(*argv
, "-mmio"))
617 sys_set_audio_api(API_MMIO
);
622 else if (!strcmp(*argv
, "-nomidiin"))
627 else if (!strcmp(*argv
, "-nomidiout"))
632 else if (!strcmp(*argv
, "-nomidi"))
634 sys_nmidiin
= sys_nmidiout
= 0;
637 else if (!strcmp(*argv
, "-midiindev"))
639 sys_parsedevlist(&sys_nmidiin
, sys_midiindevlist
, MAXMIDIINDEV
,
643 argc
-= 2; argv
+= 2;
645 else if (!strcmp(*argv
, "-midioutdev"))
647 sys_parsedevlist(&sys_nmidiout
, sys_midioutdevlist
, MAXMIDIOUTDEV
,
651 argc
-= 2; argv
+= 2;
653 else if (!strcmp(*argv
, "-mididev"))
655 sys_parsedevlist(&sys_nmidiin
, sys_midiindevlist
, MAXMIDIINDEV
,
657 sys_parsedevlist(&sys_nmidiout
, sys_midioutdevlist
, MAXMIDIOUTDEV
,
661 argc
-= 2; argv
+= 2;
663 else if (!strcmp(*argv
, "-path"))
665 sys_addpath(argv
[1]);
666 argc
-= 2; argv
+= 2;
668 else if (!strcmp(*argv
, "-helppath"))
670 sys_addhelppath(argv
[1]);
671 argc
-= 2; argv
+= 2;
673 else if (!strcmp(*argv
, "-open") && argc
> 1)
675 sys_openlist
= namelist_append(sys_openlist
, argv
[1]);
676 argc
-= 2; argv
+= 2;
678 else if (!strcmp(*argv
, "-lib") && argc
> 1)
680 sys_externlist
= namelist_append(sys_externlist
, argv
[1]);
681 argc
-= 2; argv
+= 2;
683 else if (!strcmp(*argv
, "-font") && argc
> 1)
685 sys_defaultfont
= sys_nearestfontsize(atoi(argv
[1]));
689 else if (!strcmp(*argv
, "-verbose"))
694 else if (!strcmp(*argv
, "-version"))
699 else if (!strcmp(*argv
, "-d") && argc
> 1 &&
700 sscanf(argv
[1], "%d", &sys_debuglevel
) >= 1)
705 else if (!strcmp(*argv
, "-noloadbang"))
710 else if (!strcmp(*argv
, "-nogui"))
715 else if (!strcmp(*argv
, "-stdin"))
720 else if (!strcmp(*argv
, "-guicmd") && argc
> 1)
722 sys_guicmd
= argv
[1];
723 argc
-= 2; argv
+= 2;
725 else if (!strcmp(*argv
, "-send") && argc
> 1)
727 sys_messagelist
= namelist_append(sys_messagelist
, argv
[1]);
728 argc
-= 2; argv
+= 2;
730 else if (!strcmp(*argv
, "-listdev"))
736 else if (!strcmp(*argv
, "-rt") || !strcmp(*argv
, "-realtime"))
741 else if (!strcmp(*argv
, "-nrt"))
747 else if (!strcmp(*argv
, "-soundindev") ||
748 !strcmp(*argv
, "-audioindev"))
750 sys_parsedevlist(&sys_nsoundin
, sys_soundindevlist
,
751 MAXAUDIOINDEV
, argv
[1]);
754 argc
-= 2; argv
+= 2;
756 else if (!strcmp(*argv
, "-soundoutdev") ||
757 !strcmp(*argv
, "-audiooutdev"))
759 sys_parsedevlist(&sys_nsoundout
, sys_soundoutdevlist
,
760 MAXAUDIOOUTDEV
, argv
[1]);
763 argc
-= 2; argv
+= 2;
765 else if (!strcmp(*argv
, "-sounddev") || !strcmp(*argv
, "-audiodev"))
767 sys_parsedevlist(&sys_nsoundin
, sys_soundindevlist
,
768 MAXAUDIOINDEV
, argv
[1]);
769 sys_parsedevlist(&sys_nsoundout
, sys_soundoutdevlist
,
770 MAXAUDIOOUTDEV
, argv
[1]);
773 argc
-= 2; argv
+= 2;
779 for (i
= 0; i
< sizeof(usagemessage
)/sizeof(*usagemessage
); i
++)
780 fprintf(stderr
, "%s", usagemessage
[i
]);
784 if (!sys_defaultfont
)
785 sys_defaultfont
= DEFAULTFONT
;
786 for (; argc
> 0; argc
--, argv
++)
787 sys_openlist
= namelist_append(sys_openlist
, *argv
);
793 int sys_getblksize(void)
795 return (DEFDACBLKSIZE
);
798 /* stuff to do, once, after calling sys_argparse() -- which may itself
799 be called twice because of the .pdrc hack. */
800 static void sys_afterargparse(void)
802 char sbuf
[MAXPDSTRING
];
804 /* add "extra" library to path */
805 strncpy(sbuf
, sys_libdir
->s_name
, MAXPDSTRING
-30);
806 sbuf
[MAXPDSTRING
-30] = 0;
807 strcat(sbuf
, "/extra");
809 strncpy(sbuf
, sys_libdir
->s_name
, MAXPDSTRING
-30);
810 sbuf
[MAXPDSTRING
-30] = 0;
811 strcat(sbuf
, "/intern");
813 /* add "doc/5.reference" library to helppath */
814 strncpy(sbuf
, sys_libdir
->s_name
, MAXPDSTRING
-30);
815 sbuf
[MAXPDSTRING
-30] = 0;
816 strcat(sbuf
, "/doc/5.reference");
817 sys_addhelppath(sbuf
);
818 /* correct to make audio and MIDI device lists zero based. On
819 MMIO, however, "1" really means the second device (the first one
820 is "mapper" which is was not included when the command args were
821 set up, so we leave it that way for compatibility. */
824 for (i
= 0; i
< sys_nsoundin
; i
++)
825 sys_soundindevlist
[i
]--;
826 for (i
= 0; i
< sys_nsoundout
; i
++)
827 sys_soundoutdevlist
[i
]--;
829 for (i
= 0; i
< sys_nmidiin
; i
++)
830 sys_midiindevlist
[i
]--;
831 for (i
= 0; i
< sys_nmidiout
; i
++)
832 sys_midioutdevlist
[i
]--;
835 static void sys_addreferencepath(void)
837 char sbuf
[MAXPDSTRING
];