From ba84e2aabb0663846804ea158539359939257539 Mon Sep 17 00:00:00 2001 From: "Kjetil S. Matheussen" Date: Sun, 25 Jan 2004 15:24:47 +0000 Subject: send and receive sound to and from jack ports, k_jack~ v0.0.2 svn path=/trunk/externals/k_jack~/; revision=1292 --- README | 18 +++ help-k_jack~.pd | 33 +++++ k_jack~.c | 424 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ makefile | 85 ++++++++++++ 4 files changed, 560 insertions(+) create mode 100644 README create mode 100644 help-k_jack~.pd create mode 100644 k_jack~.c create mode 100644 makefile diff --git a/README b/README new file mode 100644 index 0000000..5c74df9 --- /dev/null +++ b/README @@ -0,0 +1,18 @@ + + +k_jack~ - General signal in/out external for pure data. Kjetil S. Matheussen. +V0.0.2 + + +This external makes objects with signal inlets and outlets to jack ports. See +the help patch. + +It works by calling functions and using variables in pd/src/s_audio.c that probably +was not ment to be used for this purpose. But it works. And thats whats important. + + +Kjetil S. Matheussen +k.s.matheussen@notam02.no + + + diff --git a/help-k_jack~.pd b/help-k_jack~.pd new file mode 100644 index 0000000..f8aa28d --- /dev/null +++ b/help-k_jack~.pd @@ -0,0 +1,33 @@ +#N canvas 245 237 811 481 10; +#X obj 20 67 osc~ 500; +#X obj 96 113 k_jack~ freqtweak; +#X obj 97 65 osc~ 600; +#X obj 11 22 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 0 10 +-262144 -1 -1 0 256; +#X obj 97 23 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 0 10 +-262144 -1 -1 0 256; +#X text 597 425 k_jack~ General jack in/out; +#X text 593 443 -Kjetil S. Matheussen \, 2004; +#X text 230 114 <- Make sure freqtweak is running first!; +#X text 292 64 <- Argument is a regexp string; +#X obj 171 64 k_jack~ alsa_pcm; +#X text 227 181 <- Its no harm having two similar k_jack objects; +#X obj 105 181 k_jack~ alsa_pcm; +#X obj 11 269 k_jack~ alsa_pcm:capture; +#X obj 11 246 k_jack~ alsa_pcm:playback; +#X text 201 246 <- Only playback.; +#X text 200 267 <- Only capture.; +#X obj 10 355 k_jack~ * . . . . . . . . . . . . . . . . . . .; +#X text 359 357 <- "*" means all jack ports available. (The "."-s are +there just for spacing.); +#X obj 12 297 k_jack~ _1; +#X text 95 298 <- All ports containing "_1"; +#X connect 0 0 1 0; +#X connect 1 0 11 0; +#X connect 1 1 11 1; +#X connect 2 0 1 1; +#X connect 3 0 0 0; +#X connect 4 0 2 0; +#X connect 9 0 1 0; +#X connect 9 1 1 1; +#X coords 0 0 1 1 200 140 1; diff --git a/k_jack~.c b/k_jack~.c new file mode 100644 index 0000000..0fd9d22 --- /dev/null +++ b/k_jack~.c @@ -0,0 +1,424 @@ +/* --------------------------- k_jack~ ----------------------------------- */ +/* ;; Kjetil S. Matheussen, 2004. */ +/* */ +/* 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 +#include + +#include +#include +#include +#include + +#include + + +// Currently, the jack implementation in PD only supports 2 pd instances. +// However, it doesn't hurt to use 100, so we use 100 to be prepared for +// the future. + +#define MAX_PD_JACKCLIENTS 100 + + +static char *version = +"k_jack~ v0.0.2, written by Kjetil S. Matheussen, k.s.matheussen@notam02.no"; + + + + + +/***********************************************************/ +/********************* Jack part ***************************/ +/***********************************************************/ + +struct JackPort{ + struct JackPort *next; + char *name; + bool is_input; + int num; +}; + +static struct JackPort *jackports=NULL; + +/* Name(+":") of the client we belong to. ("pure_data_0:", "pure_data_1:", ...) */ +static char *clientname=NULL; + + + +static void set_pd_channels(int inc_ins,int inc_outs){ + int num_recs=sys_get_inchannels(); + int num_plays=sys_get_outchannels(); + + int t1[1]={0}; + int t2[1]={0}; + int t3[1]={num_recs+inc_ins}; + int t4[1]={num_plays+inc_outs}; + sys_close_audio(); + sys_open_audio(1,t1, + 1,t3, + 1,t2, + 1,t4, + sys_getsr(),sys_schedadvance/1000,1); +} + + + +static bool find_clientname(jack_client_t *client){ + bool ret=false; + + if(clientname!=NULL){ + ret=true; + }else{ + int lokke; + int num_clients=0; + int num_ports[MAX_PD_JACKCLIENTS]={0}; + char temp[500]; + const char **ports; + + for(lokke=0;lokkename,portname)) break; + jp=jp->next; + } + if(jp==NULL){ + char temp[500]; + char temp2[500]; + jp=calloc(1,sizeof(struct JackPort)); + jp->name=strdup(portname); + jp->is_input=is_input; + jp->num=add_pd_channel(is_input); + jp->next=jackports; + jackports=jp; + disconnect_all_alsa(client,portname); + if(is_input){ + sprintf(temp,"%soutput%d",clientname,jp->num); + jack_connect(client,temp,portname); + sprintf(temp2,"to_%s",portname); + }else{ + sprintf(temp,"%sinput%d",clientname,jp->num); + jack_connect(client,portname,temp); + sprintf(temp2,"from_%s",portname); + } + while(strstr(temp2,":")) strstr(temp2,":")[0]='-'; + if(strlen(temp2)+strlen(clientname)<32) + jack_port_set_name(jack_port_by_name(client,temp),temp2); + } + return jp->num; +} + + + + +/***********************************************************/ +/********************* PD part *****************************/ +/***********************************************************/ + +typedef struct _k_jack +{ + t_object x_obj; + int num_recs; + int num_plays; + int *rec_nums; + int *play_nums; + float x_float; +} t_k_jack; + + +static t_class *k_jack_class; + + + +static t_int *k_jack_perform_add(t_int *w){ + t_float *in = (t_float *)(w[1]); + t_float *out = (t_float *)(w[2]); + int n = (int)(w[3]); + int lokke; + + for(lokke=0;lokkenum_recs;lokke++){ + if(sp[ch]->s_n!=DEFDACBLKSIZE) + post("k_jack~ wrong framesize. Is this possible?"); + else + dsp_add( + k_jack_perform_add, + 2, + sp[ch]->s_vec, + sys_soundout + x->rec_nums[lokke]*DEFDACBLKSIZE + ); + ch++; + } + for(lokke=0;lokkenum_plays;lokke++){ + if(sp[ch]->s_n!=DEFDACBLKSIZE) + post("k_jack~ wrong framesize. Is this possible?"); + else + dsp_add( + k_jack_perform_copy, + 2, + sys_soundin + x->play_nums[lokke]*DEFDACBLKSIZE, + sp[ch]->s_vec + ); + ch++; + } +} + + +static void k_jack_free(t_k_jack *x){ + free(x->rec_nums); + free(x->play_nums); +} + + +static void *k_jack_new(t_symbol *s){ + int num_recs=0; + int num_plays=0; + int lokke=0; + static jack_client_t *client=NULL; + const char **ports=NULL; + t_k_jack *x=NULL; + + + if(sys_audioapi!=API_JACK){ + post("Error. k_jack~ will not work without jack as the sound API."); + goto exit; + } + + if(client==NULL){ + for(lokke=0;lokkes_name); + if(ports==NULL){ + post("k_jack~: Client \"%s\" not found.\n",s->s_name); + goto exit; + } + while(ports[lokke]!=NULL){ + jack_port_t* port=jack_port_by_name(client,ports[lokke]); + //post("%s, type: %s, flags: %d",ports[lokke],jack_port_type(port),jack_port_flags(port)); + if(jack_port_flags(port)&JackPortIsInput){ + num_recs++; + }else{ + if(jack_port_flags(port)&JackPortIsOutput){ + num_plays++; + } + } + lokke++; + } + + if(num_plays==0 && num_recs==0){ + post("Client(s) containing the name \"%s\" have no input or output ports.",s->s_name); + goto exit; + } + + x = (t_k_jack *)pd_new(k_jack_class); + + x->rec_nums=calloc(sizeof(int),num_recs); + x->play_nums=calloc(sizeof(int),num_plays); + + //post("recs: %d, plays: %d\n",num_recs,num_plays); + lokke=0; + while(ports[lokke]!=NULL){ + jack_port_t* port=jack_port_by_name(client,ports[lokke]); + if(jack_port_flags(port)&JackPortIsInput){ + x->rec_nums[x->num_recs]=get_portindex(client,ports[lokke],true); + if(x->num_recs>0) + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); + //post("Made inlet %s %d",ports[lokke],x->rec_nums[x->num_recs]); + x->num_recs++; + }else{ + if(jack_port_flags(port)&JackPortIsOutput){ + x->play_nums[x->num_plays]=get_portindex(client,ports[lokke],false); + outlet_new(&x->x_obj, gensym("signal")); + //post("Made outlet %s %d",ports[lokke],x->play_nums[x->num_plays]); + x->num_plays++; + } + } + lokke++; + } + + + exit: + + if(ports!=NULL) free(ports); + + /* Program crash if client is closed. (as a workaround, I made it static for reuse. -Kjetil) (I thought this gruesome bug was fixed!?!)*/ + //if(client!=NULL) jack_client_close(client); + + return (x); +} + + + +void k_jack_tilde_setup(void){ + k_jack_class = class_new(gensym("k_jack~"), (t_newmethod)k_jack_new, (t_method)k_jack_free, + sizeof(t_k_jack), 0, A_SYMBOL, 0); + CLASS_MAINSIGNALIN(k_jack_class, t_k_jack, x_float); + class_addmethod(k_jack_class, (t_method)k_jack_dsp, gensym("dsp"), 0); + + class_sethelpsymbol(k_jack_class, gensym("help-k_jack~.pd")); + + post(version); +} + + diff --git a/makefile b/makefile new file mode 100644 index 0000000..e382213 --- /dev/null +++ b/makefile @@ -0,0 +1,85 @@ +NAME=k_jack~ +CSYM=k_jack_tilde + +current: pd_linux + +# ----------------------- NT ----------------------- + +pd_nt: $(NAME).dll + +.SUFFIXES: .dll + +PDNTCFLAGS = /W3 /WX /O2 /G6 /DNT /DPD /nologo +VC="C:\Programme\Microsoft Visual Studio\VC98" + +PDNTINCLUDE = /I. /Ic:\pd\tcl\include /Ic:\pd\src /I$(VC)\include /Iinclude + +PDNTLDIR = $(VC)\Lib +PDNTLIB = $(PDNTLDIR)\libc.lib \ + $(PDNTLDIR)\oldnames.lib \ + $(PDNTLDIR)\kernel32.lib \ + $(PDNTLDIR)\user32.lib \ + $(PDNTLDIR)\uuid.lib \ + c:\pd\bin\pd.lib \ + +.c.dll: + cl $(PDNTCFLAGS) $(PDNTINCLUDE) /c $*.c + link /dll /export:$(CSYM)_setup $*.obj $(PDNTLIB) + +# ----------------------- IRIX 5.x ----------------------- + +pd_irix5: $(NAME).pd_irix5 + +.SUFFIXES: .pd_irix5 + +SGICFLAGS5 = -o32 -DPD -DUNIX -DIRIX -O2 + +SGIINCLUDE = -I../../src + +.c.pd_irix5: + cc $(SGICFLAGS5) $(SGIINCLUDE) -o $*.o -c $*.c + ld -elf -shared -rdata_shared -o $*.pd_irix5 $*.o + rm $*.o + +# ----------------------- IRIX 6.x ----------------------- + +pd_irix6: $(NAME).pd_irix6 + +.SUFFIXES: .pd_irix6 + +SGICFLAGS6 = -n32 -DPD -DUNIX -DIRIX -DN32 -woff 1080,1064,1185 \ + -OPT:roundoff=3 -OPT:IEEE_arithmetic=3 -OPT:cray_ivdep=true \ + -Ofast=ip32 + +.c.pd_irix6: + cc $(SGICFLAGS6) $(SGIINCLUDE) -o $*.o -c $*.c + ld -n32 -IPA -shared -rdata_shared -o $*.pd_irix6 $*.o + rm $*.o + +# ----------------------- LINUX i386 ----------------------- + +pd_linux: $(NAME).pd_linux + +.SUFFIXES: .pd_linux + +LINUXCFLAGS = -DPD -DUNIX -O2 -funroll-loops -fomit-frame-pointer \ + -Wall -W -Wshadow -Wstrict-prototypes \ + -Wno-unused -Wno-parentheses -Wno-switch + +PDSRCDIR=../../../src +LINUXINCLUDE = -I$(PDSRCDIR) + +.c.pd_linux: + gcc $(LINUXCFLAGS) $(LINUXINCLUDE) -g -o $*.o -c $*.c + ld -export_dynamic -shared -o $*.pd_linux $*.o -lc -lm -ljack + strip --strip-unneeded $*.pd_linux + rm -f $*.o ../$*.pd_linux + ln -s $*/$*.pd_linux .. + +# ---------------------------------------------------------- + +install: + cp help-*.pd ../../doc/5.reference + +clean: + rm -f *.o *.pd_* so_locations *~ -- cgit v1.2.1