From 64fdb009695828b788fce074135b20a5e52c5fc4 Mon Sep 17 00:00:00 2001 From: Thomas Grill Date: Tue, 23 Sep 2003 00:21:28 +0000 Subject: imported version 0.37-0 svn path=/trunk/; revision=1016 --- pd/src/build.bat | 42 + pd/src/d_array.c | 32 +- pd/src/d_ctl.c | 11 +- pd/src/d_dac.c | 2 +- pd/src/d_filter.c | 37 +- pd/src/d_soundfile.c | 57 +- pd/src/d_ugen.c | 125 +- pd/src/g_all_guis.c | 76 ++ pd/src/g_all_guis.h | 4 + pd/src/g_array.c | 3 +- pd/src/g_bang.c | 43 +- pd/src/g_canvas.c | 77 +- pd/src/g_canvas.h | 8 +- pd/src/g_editor.c | 54 +- pd/src/g_graph.c | 34 +- pd/src/g_hdial.c | 41 +- pd/src/g_hslider.c | 40 +- pd/src/g_io.c | 7 +- pd/src/g_mycanvas.c | 40 +- pd/src/g_numbox.c | 38 +- pd/src/g_readwrite.c | 3 +- pd/src/g_rtext.c | 29 +- pd/src/g_scalar.c | 4 +- pd/src/g_template.c | 5 +- pd/src/g_text.c | 18 +- pd/src/g_toggle.c | 40 +- pd/src/g_vdial.c | 38 +- pd/src/g_vslider.c | 40 +- pd/src/g_vumeter.c | 38 +- pd/src/m_binbuf.c | 26 +- pd/src/m_class.c | 27 + pd/src/m_glob.c | 53 +- pd/src/m_imp.h | 2 + pd/src/m_pd.c | 7 + pd/src/m_pd.h | 23 +- pd/src/m_sched.c | 201 +++- pd/src/makefile | 134 ++- pd/src/makefile.nt.bad | 92 -- pd/src/notes.txt | 45 +- pd/src/s_audio.c | 603 ++++++++-- pd/src/s_audio_alsa.c | 328 +++-- pd/src/s_audio_jack.c | 350 ++++++ pd/src/s_audio_mmio.c | 61 +- pd/src/s_audio_oss.c | 110 +- pd/src/s_audio_pa.c | 137 ++- pd/src/s_freebsd.c | 3072 ----------------------------------------------- pd/src/s_inter.c | 12 +- pd/src/s_linux.c | 3087 ------------------------------------------------ pd/src/s_mac.c | 377 ------ pd/src/s_main.c | 174 +-- pd/src/s_midi.c | 194 +++ pd/src/s_midi_mmio.c | 715 +++++++++++ pd/src/s_midi_oss.c | 112 +- pd/src/s_midi_pm.c | 116 +- pd/src/s_nt.c | 1586 ------------------------- pd/src/s_path.c | 107 +- pd/src/s_portaudio.c | 197 --- pd/src/s_sgi.c | 433 ------- pd/src/s_stuff.h | 56 +- pd/src/s_unix.c | 454 ------- pd/src/u_main.tk | 637 +++++++++- pd/src/u_main.tk.test | 2686 ----------------------------------------- pd/src/x_connective.c | 23 + pd/src/x_gui.c | 16 +- pd/src/z.pd | 9 - pd/src/z2.pd | 3 - pd/src/z3.pd | 17 - pd/src/z4.pd | 2 - pd/src/z5.pd | 8 - pd/src/z6.pd | 4 - 70 files changed, 4233 insertions(+), 13049 deletions(-) create mode 100644 pd/src/build.bat delete mode 100644 pd/src/makefile.nt.bad create mode 100644 pd/src/s_audio_jack.c delete mode 100644 pd/src/s_freebsd.c delete mode 100644 pd/src/s_linux.c delete mode 100644 pd/src/s_mac.c create mode 100644 pd/src/s_midi_mmio.c delete mode 100644 pd/src/s_nt.c delete mode 100644 pd/src/s_portaudio.c delete mode 100644 pd/src/s_sgi.c delete mode 100644 pd/src/s_unix.c delete mode 100644 pd/src/u_main.tk.test delete mode 100644 pd/src/z.pd delete mode 100644 pd/src/z2.pd delete mode 100644 pd/src/z3.pd delete mode 100644 pd/src/z4.pd delete mode 100644 pd/src/z5.pd delete mode 100644 pd/src/z6.pd (limited to 'pd/src') diff --git a/pd/src/build.bat b/pd/src/build.bat new file mode 100644 index 00000000..15d65957 --- /dev/null +++ b/pd/src/build.bat @@ -0,0 +1,42 @@ +nmake +cd .. +cd extra + +del *.dll + +cd bonk~ +nmake pd_nt +move bonk~.dll .. +cd .. + +cd choice +nmake pd_nt +move choice.dll .. +cd .. + +cd expr~ +nmake pd_nt +move expr.dll .. +cd .. + +cd fiddle~ +nmake pd_nt +move fiddle~.dll .. +cd .. + +cd loop~ +nmake pd_nt +move loop~.dll .. +cd .. + +cd lrshift~ +nmake pd_nt +move lrshift~.dll .. +cd .. + +cd pique +nmake pd_nt +move pique.dll .. +cd .. + + diff --git a/pd/src/d_array.c b/pd/src/d_array.c index 2a78e144..9b68b758 100644 --- a/pd/src/d_array.c +++ b/pd/src/d_array.c @@ -80,7 +80,7 @@ void tabwrite_tilde_set(t_tabwrite_tilde *x, t_symbol *s) } else if (!garray_getfloatarray(a, &x->x_nsampsintab, &x->x_vec)) { - error("%s: bad template for tabwrite~", x->x_arrayname->s_name); + pd_error(x, "%s: bad template for tabwrite~", x->x_arrayname->s_name); x->x_vec = 0; } else garray_usedindsp(a); @@ -209,7 +209,7 @@ void tabplay_tilde_set(t_tabplay_tilde *x, t_symbol *s) } else if (!garray_getfloatarray(a, &x->x_nsampsintab, &x->x_vec)) { - error("%s: bad template for tabplay~", x->x_arrayname->s_name); + pd_error(x, "%s: bad template for tabplay~", x->x_arrayname->s_name); x->x_vec = 0; } else garray_usedindsp(a); @@ -323,12 +323,12 @@ void tabread_tilde_set(t_tabread_tilde *x, t_symbol *s) if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class))) { if (*s->s_name) - error("tabread~: %s: no such array", x->x_arrayname->s_name); + pd_error(x, "tabread~: %s: no such array", x->x_arrayname->s_name); x->x_vec = 0; } else if (!garray_getfloatarray(a, &x->x_npoints, &x->x_vec)) { - error("%s: bad template for tabread~", x->x_arrayname->s_name); + pd_error(x, "%s: bad template for tabread~", x->x_arrayname->s_name); x->x_vec = 0; } else garray_usedindsp(a); @@ -452,12 +452,12 @@ void tabread4_tilde_set(t_tabread4_tilde *x, t_symbol *s) if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class))) { if (*s->s_name) - error("tabread4~: %s: no such array", x->x_arrayname->s_name); + pd_error(x, "tabread4~: %s: no such array", x->x_arrayname->s_name); x->x_vec = 0; } else if (!garray_getfloatarray(a, &x->x_npoints, &x->x_vec)) { - error("%s: bad template for tabread4~", x->x_arrayname->s_name); + pd_error(x, "%s: bad template for tabread4~", x->x_arrayname->s_name); x->x_vec = 0; } else garray_usedindsp(a); @@ -756,10 +756,10 @@ static void tabsend_dsp(t_tabsend *x, t_signal **sp) if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class))) { if (*x->x_arrayname->s_name) - error("tabsend~: %s: no such array", x->x_arrayname->s_name); + pd_error(x, "tabsend~: %s: no such array", x->x_arrayname->s_name); } else if (!garray_getfloatarray(a, &vecsize, &x->x_vec)) - error("%s: bad template for tabsend~", x->x_arrayname->s_name); + pd_error(x, "%s: bad template for tabsend~", x->x_arrayname->s_name); else { int n = sp[0]->s_n; @@ -823,10 +823,10 @@ static void tabreceive_dsp(t_tabreceive *x, t_signal **sp) if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class))) { if (*x->x_arrayname->s_name) - error("tabsend~: %s: no such array", x->x_arrayname->s_name); + pd_error(x, "tabsend~: %s: no such array", x->x_arrayname->s_name); } else if (!garray_getfloatarray(a, &vecsize, &x->x_vec)) - error("%s: bad template for tabreceive~", x->x_arrayname->s_name); + pd_error(x, "%s: bad template for tabreceive~", x->x_arrayname->s_name); else { int n = sp[0]->s_n; @@ -870,9 +870,9 @@ static void tabread_float(t_tabread *x, t_float f) t_float *vec; if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class))) - error("%s: no such array", x->x_arrayname->s_name); + pd_error(x, "%s: no such array", x->x_arrayname->s_name); else if (!garray_getfloatarray(a, &npoints, &vec)) - error("%s: bad template for tabread", x->x_arrayname->s_name); + pd_error(x, "%s: bad template for tabread", x->x_arrayname->s_name); else { int n = f; @@ -921,9 +921,9 @@ static void tabread4_float(t_tabread4 *x, t_float f) t_float *vec; if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class))) - error("%s: no such array", x->x_arrayname->s_name); + pd_error(x, "%s: no such array", x->x_arrayname->s_name); else if (!garray_getfloatarray(a, &npoints, &vec)) - error("%s: bad template for tabread4", x->x_arrayname->s_name); + pd_error(x, "%s: bad template for tabread4", x->x_arrayname->s_name); else if (npoints < 4) outlet_float(x->x_obj.ob_outlet, 0); else if (f <= 1) @@ -1001,9 +1001,9 @@ static void tabwrite_float(t_tabwrite *x, t_float f) t_float *vec; if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class))) - error("%s: no such array", x->x_arrayname->s_name); + pd_error(x, "%s: no such array", x->x_arrayname->s_name); else if (!garray_getfloatarray(a, &vecsize, &vec)) - error("%s: bad template for tabwrite", x->x_arrayname->s_name); + pd_error(x, "%s: bad template for tabwrite", x->x_arrayname->s_name); else { int n = x->x_ft1; diff --git a/pd/src/d_ctl.c b/pd/src/d_ctl.c index a2f5cd76..e94a598d 100644 --- a/pd/src/d_ctl.c +++ b/pd/src/d_ctl.c @@ -254,7 +254,7 @@ static t_int *vline_tilde_perform(t_int *w) } } if (x->x_targettime <= timenext) - f = x->x_target, inc = 0; + f = x->x_target, inc = x->x_inc = 0, x->x_targettime = 1e20; *out++ = f; f = f + inc; timenow = timenext; @@ -271,6 +271,8 @@ static void vline_tilde_stop(t_vline *x) x->x_list = 0; x->x_inc = 0; x->x_inlet1 = x->x_inlet2 = 0; + x->x_target = x->x_value; + x->x_targettime = 1e20; } static void vline_tilde_float(t_vline *x, t_float f) @@ -279,18 +281,18 @@ static void vline_tilde_float(t_vline *x, t_float f) float inlet1 = (x->x_inlet1 < 0 ? 0 : x->x_inlet1); float inlet2 = x->x_inlet2; double starttime = timenow + inlet2; - t_vseg *s1, *s2, *deletefrom = 0, - *snew = (t_vseg *)t_getbytes(sizeof(*snew)); + t_vseg *s1, *s2, *deletefrom = 0, *snew; if (PD_BADFLOAT(f)) f = 0; /* negative delay input means stop and jump immediately to new value */ if (inlet2 < 0) { - vline_tilde_stop(x); x->x_value = f; + vline_tilde_stop(x); return; } + snew = (t_vseg *)t_getbytes(sizeof(*snew)); /* check if we supplant the first item in the list. We supplant an item by having an earlier starttime, or an equal starttime unless the equal one was instantaneous and the new one isn't (in which case @@ -350,6 +352,7 @@ static void *vline_tilde_new(void) x->x_referencetime = clock_getlogicaltime(); x->x_list = 0; x->x_samppermsec = 0; + x->x_targettime = 1e20; return (x); } diff --git a/pd/src/d_dac.c b/pd/src/d_dac.c index c090a214..1606b3a1 100644 --- a/pd/src/d_dac.c +++ b/pd/src/d_dac.c @@ -171,7 +171,7 @@ static void adc_free(t_adc *x) static void adc_setup(void) { adc_class = class_new(gensym("adc~"), (t_newmethod)adc_new, - (t_method)adc_free, sizeof(t_adc), CLASS_NOINLET, A_GIMME, 0); + (t_method)adc_free, sizeof(t_adc), 0, A_GIMME, 0); class_addmethod(adc_class, (t_method)adc_dsp, gensym("dsp"), A_CANT, 0); class_sethelpsymbol(adc_class, gensym("adc~_dac~")); } diff --git a/pd/src/d_filter.c b/pd/src/d_filter.c index 88318900..732bd3d6 100644 --- a/pd/src/d_filter.c +++ b/pd/src/d_filter.c @@ -43,10 +43,13 @@ static void *sighip_new(t_floatarg f) static void sighip_ft1(t_sighip *x, t_floatarg f) { - if (f < 0.001) f = 10; + if (f < 0) f = 0; x->x_hz = f; x->x_ctl->c_coef = 1 - f * (2 * 3.14159) / x->x_sr; - if (x->x_ctl->c_coef < 0) x->x_ctl->c_coef = 0; + if (x->x_ctl->c_coef < 0) + x->x_ctl->c_coef = 0; + else if (x->x_ctl->c_coef > 1) + x->x_ctl->c_coef = 1; } static t_int *sighip_perform(t_int *w) @@ -58,15 +61,24 @@ static t_int *sighip_perform(t_int *w) int i; float last = c->c_x; float coef = c->c_coef; - for (i = 0; i < n; i++) + if (coef < 1) { - float new = *in++ + coef * last; - *out++ = new - last; - last = new; + for (i = 0; i < n; i++) + { + float new = *in++ + coef * last; + *out++ = new - last; + last = new; + } + if (PD_BADFLOAT(last)) + last = 0; + c->c_x = last; + } + else + { + for (i = 0; i < n; i++) + *out++ = *in++; + c->c_x = 0; } - if (PD_BADFLOAT(last)) - last = 0; - c->c_x = last; return (w+5); } @@ -133,10 +145,13 @@ static void *siglop_new(t_floatarg f) static void siglop_ft1(t_siglop *x, t_floatarg f) { - if (f < 0.001) f = 10; + if (f < 0) f = 0; x->x_hz = f; x->x_ctl->c_coef = f * (2 * 3.14159) / x->x_sr; - if (x->x_ctl->c_coef > 1) x->x_ctl->c_coef = 1; + if (x->x_ctl->c_coef > 1) + x->x_ctl->c_coef = 1; + else if (x->x_ctl->c_coef < 0) + x->x_ctl->c_coef = 0; } static void siglop_clear(t_siglop *x, t_floatarg q) diff --git a/pd/src/d_soundfile.c b/pd/src/d_soundfile.c index a55e4d27..5752fade 100644 --- a/pd/src/d_soundfile.c +++ b/pd/src/d_soundfile.c @@ -478,7 +478,7 @@ static void soundfile_xferin(int sfchannels, int nvecs, float **vecs, static int soundfiler_writeargparse(void *obj, int *p_argc, t_atom **p_argv, t_symbol **p_filesym, int *p_filetype, int *p_bytespersamp, int *p_swap, int *p_bigendian, - int *p_normalize, long *p_onset, long *p_nframes) + int *p_normalize, long *p_onset, long *p_nframes, float *p_rate) { int argc = *p_argc; t_atom *argv = *p_argv; @@ -486,6 +486,7 @@ static int soundfiler_writeargparse(void *obj, int *p_argc, t_atom **p_argv, endianness = -1, swap, filetype = FORMAT_WAVE, normalize = 0; long onset = 0, nframes = 0x7fffffff; t_symbol *filesym; + float rate = -1; while (argc > 0 && argv->a_type == A_SYMBOL && *argv->a_w.w_symbol->s_name == '-') { @@ -542,6 +543,13 @@ static int soundfiler_writeargparse(void *obj, int *p_argc, t_atom **p_argv, endianness = 1; argc -= 1; argv += 1; } + else if (!strcmp(flag, "r") || !strcmp(flag, "rate")) + { + if (argc < 2 || argv[1].a_type != A_FLOAT || + ((rate = argv[1].a_w.w_float) <= 0)) + goto usage; + argc -= 2; argv += 2; + } else goto usage; } /* don't handle AIFF floating point samples */ @@ -586,6 +594,7 @@ static int soundfiler_writeargparse(void *obj, int *p_argc, t_atom **p_argv, *p_onset = onset; *p_nframes = nframes; *p_bigendian = bigendian; + *p_rate = rate; return (0); usage: return (-1); @@ -593,7 +602,7 @@ usage: static int create_soundfile(t_canvas *canvas, const char *filename, int filetype, int nframes, int bytespersamp, - int bigendian, int nchannels, int swap) + int bigendian, int nchannels, int swap, float samplerate) { char filenamebuf[MAXPDSTRING], buf2[MAXPDSTRING]; char headerbuf[WRITEHDRSIZE]; @@ -616,7 +625,7 @@ static int create_soundfile(t_canvas *canvas, const char *filename, nexthdr->ns_length = 0; nexthdr->ns_format = swap4((bytespersamp == 3 ? NS_FORMAT_LINEAR_24 : (bytespersamp == 4 ? NS_FORMAT_FLOAT : NS_FORMAT_LINEAR_16)), swap);; - nexthdr->ns_sr = swap4(44100, swap); /* lie */ + nexthdr->ns_sr = swap4(samplerate, swap); nexthdr->ns_nchans = swap4(nchannels, swap); strcpy(nexthdr->ns_info, "Pd "); swapstring(nexthdr->ns_info, swap); @@ -658,8 +667,9 @@ static int create_soundfile(t_canvas *canvas, const char *filename, wavehdr->w_fmttag = swap2((bytespersamp == 4 ? WAV_FLOAT : WAV_INT), swap); wavehdr->w_nchannels = swap2(nchannels, swap); - wavehdr->w_samplespersec = swap4(44100, swap); - wavehdr->w_navgbytespersec = swap4(44100 * nchannels * bytespersamp, swap); + wavehdr->w_samplespersec = swap4(samplerate, swap); + wavehdr->w_navgbytespersec = + swap4((int)(samplerate * nchannels * bytespersamp), swap); wavehdr->w_nblockalign = swap2(bytespersamp, swap); wavehdr->w_nbitspersample = swap2(8 * bytespersamp, swap); strncpy(wavehdr->w_datachunkid, "data", 4); @@ -815,8 +825,8 @@ static void soundfile_xferout(int nchannels, float **vecs, { float f2 = *fp * normalfactor; xx = *(long *)&f2; - sp2[0] = (xx >> 24); sp2[1] = (xx >> 24); - sp2[2] = (xx >> 24); sp2[3] = xx; + sp2[0] = (xx >> 24); sp2[1] = (xx >> 16); + sp2[2] = (xx >> 8); sp2[3] = xx; } } else @@ -826,8 +836,8 @@ static void soundfile_xferout(int nchannels, float **vecs, { float f2 = *fp * normalfactor; xx = *(long *)&f2; - sp2[3] = (xx >> 24); sp2[2] = (xx >> 24); - sp2[1] = (xx >> 24); sp2[0] = xx; + sp2[3] = (xx >> 24); sp2[2] = (xx >> 16); + sp2[1] = (xx >> 8); sp2[0] = xx; } } } @@ -1078,16 +1088,18 @@ long soundfiler_dowrite(void *obj, t_canvas *canvas, char sampbuf[SAMPBUFSIZE]; int bufframes, nitems; int fd = -1; - float normfactor, biggest = 0; + float normfactor, biggest = 0, samplerate; t_symbol *filesym; if (soundfiler_writeargparse(obj, &argc, &argv, &filesym, &filetype, - &bytespersamp, &swap, &bigendian, &normalize, &onset, &nframes)) - goto usage; + &bytespersamp, &swap, &bigendian, &normalize, &onset, &nframes, + &samplerate)) + goto usage; nchannels = argc; if (nchannels < 1 || nchannels > MAXSFCHANS) goto usage; - + if (samplerate < 0) + samplerate = sys_getsr(); for (i = 0; i < nchannels; i++) { int vecsize; @@ -1121,7 +1133,7 @@ long soundfiler_dowrite(void *obj, t_canvas *canvas, if ((fd = create_soundfile(canvas, filesym->s_name, filetype, nframes, bytespersamp, bigendian, nchannels, - swap)) < 0) + swap, samplerate)) < 0) { post("%s: %s\n", filesym->s_name, strerror(errno)); goto fail; @@ -1243,6 +1255,7 @@ typedef struct _readsf int x_vecsize; /* vector size for transfers */ t_outlet *x_bangout; /* bang-on-done outlet */ int x_state; /* opened, running, or idle */ + float x_insamplerate; /* sample rate of input signal if known */ /* parameters to communicate with subthread */ int x_requestcode; /* pending request from parent to I/O thread */ char *x_filename; /* file to open (string is permanently allocated) */ @@ -1251,6 +1264,7 @@ typedef struct _readsf int x_bytespersample; /* bytes per sample (2 or 3) */ int x_bigendian; /* true if file is big-endian */ int x_sfchannels; /* number of channels in soundfile */ + float x_samplerate; /* sample rate of soundfile */ long x_onsetframes; /* number of sample frames to skip */ long x_bytelimit; /* max number of data bytes to read */ int x_fd; /* filedesc */ @@ -1831,6 +1845,7 @@ static void *writesf_child_main(void *zz) int filetype = x->x_filetype; char *filename = x->x_filename; t_canvas *canvas = x->x_canvas; + float samplerate = x->x_samplerate; /* alter the request code so that an ensuing "open" will get noticed. */ @@ -1852,7 +1867,7 @@ static void *writesf_child_main(void *zz) pthread_mutex_unlock(&x->x_mutex); fd = create_soundfile(canvas, filename, filetype, 0, bytespersample, bigendian, sfchannels, - garray_ambigendian() != bigendian); + garray_ambigendian() != bigendian, samplerate); pthread_mutex_lock(&x->x_mutex); pute("5\n"); @@ -2010,6 +2025,7 @@ static void *writesf_new(t_floatarg fnchannels, t_floatarg fbufsize) pthread_cond_init(&x->x_requestcondition, 0); pthread_cond_init(&x->x_answercondition, 0); x->x_vecsize = MAXVECSIZE; + x->x_insamplerate = x->x_samplerate = 0; x->x_state = STATE_IDLE; x->x_clock = 0; /* no callback needed here */ x->x_canvas = canvas_getcurrent(); @@ -2092,13 +2108,14 @@ static void writesf_open(t_writesf *x, t_symbol *s, int argc, t_atom *argv) t_symbol *filesym; int filetype, bytespersamp, swap, bigendian, normalize; long onset, nframes; + float samplerate; if (soundfiler_writeargparse(x, &argc, &argv, &filesym, &filetype, &bytespersamp, &swap, &bigendian, - &normalize, &onset, &nframes)) + &normalize, &onset, &nframes, &samplerate)) { pd_error(x, "writesf~: usage: open [-bytes [234]] [-wave,-nextstep,-aiff] ..."); - post("... [-big,-little] filename"); + post("... [-big,-little] [-rate ####] filename"); } if (normalize || onset || (nframes != 0x7fffffff)) pd_error(x, "normalize/onset/nframes argument to writesf~: ignored"); @@ -2118,6 +2135,11 @@ static void writesf_open(t_writesf *x, t_symbol *s, int argc, t_atom *argv) x->x_fileerror = 0; x->x_state = STATE_STARTUP; x->x_bytespersample = (bytespersamp > 2 ? bytespersamp : 2); + if (samplerate > 0) + x->x_samplerate = samplerate; + else if (x->x_insamplerate > 0) + x->x_samplerate = x->x_insamplerate; + else x->x_samplerate = sys_getsr(); /* set fifosize from bufsize. fifosize must be a multiple of the number of bytes eaten for each DSP tick. */ @@ -2143,6 +2165,7 @@ static void writesf_dsp(t_writesf *x, t_signal **sp) (x->x_bytespersample * ninlets * x->x_vecsize)); for (i = 0; i < ninlets; i++) x->x_outvec[i] = sp[i]->s_vec; + x->x_insamplerate = sp[0]->s_sr; pthread_mutex_unlock(&x->x_mutex); dsp_add(writesf_perform, 1, x); } diff --git a/pd/src/d_ugen.c b/pd/src/d_ugen.c index 2bc99936..2c359c38 100644 --- a/pd/src/d_ugen.c +++ b/pd/src/d_ugen.c @@ -125,19 +125,34 @@ typedef struct _block char x_switched; /* true if we're acting as a a switch */ char x_switchon; /* true if we're switched on */ char x_reblock; /* true if inlets and outlets are reblocking */ - - int x_upsample; /* IOhannes: upsampling-factor */ - int x_downsample; /* IOhannes: downsampling-factor */ + int x_upsample; /* IOhannes: upsampling-factor */ + int x_downsample; /* IOhannes: downsampling-factor */ } t_block; +static void block_set(t_block *x, t_floatarg fvecsize, t_floatarg foverlap, + t_floatarg fupsample); + static void *block_new(t_floatarg fvecsize, t_floatarg foverlap, t_floatarg fupsample) /* IOhannes */ { + t_block *x = (t_block *)pd_new(block_class); + x->x_phase = 0; + x->x_period = 1; + x->x_frequency = 1; + x->x_switched = 0; + x->x_switchon = 1; + block_set(x, fvecsize, foverlap, fupsample); + return (x); +} + +static void block_set(t_block *x, t_floatarg fvecsize, t_floatarg foverlap, + t_floatarg fupsample) +{ + int upsample, downsample; /* IOhannes */ int vecsize = fvecsize; int overlap = foverlap; - int upsample, downsample; /* IOhannes */ - t_block *x = (t_block *)pd_new(block_class); + int dspstate = canvas_suspend_dsp(); if (overlap < 1) overlap = 1; if (vecsize < 0) @@ -180,16 +195,11 @@ static void *block_new(t_floatarg fvecsize, t_floatarg foverlap, x->x_vecsize = vecsize; x->x_overlap = overlap; - x->x_phase = 0; - x->x_period = 1; - x->x_frequency = 1; - x->x_switched = 0; - x->x_switchon = 1; /* IOhannes { */ x->x_upsample = upsample; x->x_downsample = downsample; /* } IOhannes */ - return (x); + canvas_resume_dsp(dspstate); } static void *switch_new(t_floatarg fvecsize, t_floatarg foverlap, @@ -312,7 +322,7 @@ int ilog2(int n) /* list of signals which can be reused, sorted by buffer size */ static t_signal *signal_freelist[MAXLOGSIG+1]; - /* list of reusable "borrowed" signals */ + /* list of reusable "borrowed" signals (which don't own sample buffers) */ static t_signal *signal_freeborrowed; /* list of all signals allocated (not including "borrowed" ones) */ static t_signal *signal_usedlist; @@ -360,8 +370,8 @@ void signal_makereusable(t_signal *sig) if (ugen_loud) post("free %x: %d", sig, sig->s_isborrowed); if (sig->s_isborrowed) { - /* if the signal is borrowed, decrement the borowee's reference - count, possibly marking it reusable too */ + /* if the signal is borrowed, decrement the borrowed-from signal's + reference count, possibly marking it reusable too */ t_signal *s2 = sig->s_borrowedfrom; if ((s2 == sig) || !s2) bug("signal_free"); @@ -373,8 +383,8 @@ void signal_makereusable(t_signal *sig) } else { - /* if it's a real signal, put it on the free list so we can - reuse it. */ + /* if it's a real signal (not borrowed), put it on the free list + so we can reuse it. */ if (signal_freelist[logn] == sig) bug("signal_free 2"); sig->s_nextfree = signal_freelist[logn]; signal_freelist[logn] = sig; @@ -439,6 +449,8 @@ void signal_setborrowed(t_signal *sig, t_signal *sig2) { if (!sig->s_isborrowed || sig->s_borrowedfrom) bug("signal_setborrowed"); + if (sig == sig2) + bug("signal_setborrowed 2"); sig->s_borrowedfrom = sig2; sig->s_vec = sig2->s_vec; sig->s_n = sig2->s_n; @@ -581,7 +593,7 @@ t_dspcontext *ugen_start_graph(int toplevel, t_signal **sp, } /* first the canvas calls this to create all the boxes... */ -void ugen_add(t_dspcontext *dc, t_object *obj, int nextjump) +void ugen_add(t_dspcontext *dc, t_object *obj) { t_ugenbox *x = (t_ugenbox *)getbytes(sizeof *x); int i; @@ -619,7 +631,8 @@ void ugen_connect(t_dspcontext *dc, t_object *x1, int outno, t_object *x2, for (u2 = dc->dc_ugenlist; u2 && u2->u_obj != x2; u2 = u2->u_next); if (!u1 || !u2 || siginno < 0) { - pd_error(u1->u_obj, "signal outlet connect to nonsignal inlet (ignored)"); + pd_error(u1->u_obj, + "signal outlet connect to nonsignal inlet (ignored)"); return; } if (sigoutno < 0 || sigoutno >= u1->u_nout || siginno >= u2->u_nin) @@ -802,6 +815,7 @@ static void ugen_doit(t_dspcontext *dc, t_ugenbox *u) } } t_freebytes(insig,(u->u_nin + u->u_nout) * sizeof(t_signal *)); + u->u_done = 1; } /* once the DSP graph is built, we call this routine to sort it. @@ -851,7 +865,8 @@ void ugen_done_graph(t_dspcontext *dc) t_pd *zz = &u->u_obj->ob_pd; if (pd_class(zz) == block_class) { - if (blk) pd_error(blk, "conflicting block~ objects in same page"); + if (blk) + pd_error(blk, "conflicting block~ objects in same page"); else blk = (t_block *)zz; } } @@ -879,8 +894,10 @@ void ugen_done_graph(t_dspcontext *dc) downsample = blk->x_downsample; upsample = blk->x_upsample; if (downsample > parent_vecsize) downsample=parent_vecsize; - period = (vecsize * downsample)/(parent_vecsize * realoverlap * upsample); - frequency = (parent_vecsize * realoverlap * upsample)/(vecsize * downsample); + period = (vecsize * downsample)/ + (parent_vecsize * realoverlap * upsample); + frequency = (parent_vecsize * realoverlap * upsample)/ + (vecsize * downsample); /* } IOhannes*/ phase = blk->x_phase; srate = parent_srate * realoverlap * upsample / downsample; @@ -890,8 +907,9 @@ void ugen_done_graph(t_dspcontext *dc) blk->x_frequency = frequency; blk->x_period = period; blk->x_phase = dsp_phase & (period - 1); - if (! parent_context || (realoverlap != 1) || (vecsize != parent_vecsize) || - (downsample != 1) || (upsample != 1)) /* IOhannes */ + if (! parent_context || (realoverlap != 1) || + (vecsize != parent_vecsize) || + (downsample != 1) || (upsample != 1)) /* IOhannes */ reblock = 1; switched = blk->x_switched; } @@ -911,26 +929,29 @@ void ugen_done_graph(t_dspcontext *dc) dc->dc_vecsize = vecsize; /* if we're reblocking or switched, we now have to create output - signals to fill in for the "borrowed" ones we have now. The - output signals will be filled by the outlet epilog code. */ + signals to fill in for the "borrowed" ones we have now. This + is also possibly true even if we're not blocked/switched, in + the case that there was a signal loop. But we don't know this + yet. */ - if (reblock || switched) + if (dc->dc_iosigs && (switched || reblock)) { - t_signal **iosigs = dc->dc_iosigs; - if (iosigs) + t_signal **sigp; + for (i = 0, sigp = dc->dc_iosigs + dc->dc_ninlets; i < dc->dc_noutlets; + i++, sigp++) { - t_signal **sigp; - int noutlets = dc->dc_noutlets; - for (i = 0, sigp = iosigs + dc->dc_ninlets; i < noutlets; - i++, sigp++) + if ((*sigp)->s_isborrowed && !(*sigp)->s_borrowedfrom) { - signal_setborrowed(*sigp, - signal_new(parent_vecsize, parent_srate)); + signal_setborrowed(*sigp, + signal_new(parent_vecsize, parent_srate)); (*sigp)->s_refcount++; - if (ugen_loud) post("set %x->%x", *sigp, (*sigp)->s_borrowedfrom); + + if (ugen_loud) post("set %x->%x", *sigp, + (*sigp)->s_borrowedfrom); } - } + } } + if (ugen_loud) post("reblock %d, switched %d", reblock, switched); @@ -987,6 +1008,34 @@ void ugen_done_graph(t_dspcontext *dc) next: ; } + /* check for a DSP loop, which is evidenced here by the presence + of ugens not yet scheduled. */ + + for (u = dc->dc_ugenlist; u; u = u->u_next) + if (!u->u_done) + { + t_signal **sigp; + pd_error(u->u_obj, + "DSP loop detected (some tilde objects not scheduled)"); + /* this might imply that we have unfilled "borrowed" outputs + which we'd better fill in now. */ + for (i = 0, sigp = dc->dc_iosigs + dc->dc_ninlets; i < dc->dc_noutlets; + i++, sigp++) + { + if ((*sigp)->s_isborrowed && !(*sigp)->s_borrowedfrom) + { + t_signal *s3 = signal_new(parent_vecsize, parent_srate); + signal_setborrowed(*sigp, s3); + (*sigp)->s_refcount++; + dsp_add_zero(s3->s_vec, s3->s_n); + if (ugen_loud) + post("oops, belatedly set %x->%x", *sigp, + (*sigp)->s_borrowedfrom); + } + } + break; /* don't need to keep looking. */ + } + if (blk && (reblock || switched)) /* add block DSP epilog */ dsp_add(block_epilog, 1, blk); chainblockend = dsp_chainsize; @@ -1000,7 +1049,7 @@ void ugen_done_graph(t_dspcontext *dc) { t_signal **iosigs = dc->dc_iosigs; if (iosigs) iosigs += dc->dc_ninlets; - voutlet_dspepilog((struct _voutlet *)zz, + voutlet_dspepilog((struct _voutlet *)zz, iosigs, vecsize, dsp_phase, period, frequency, downsample, upsample, /* IOhannes */ reblock, switched); @@ -1069,6 +1118,8 @@ void d_ugen_setup(void) /* really just block_setup */ sizeof(t_block), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT/*IOhannes*/, 0); class_addcreator((t_newmethod)switch_new, gensym("switch~"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT/*IOhannes*/, 0); + class_addmethod(block_class, (t_method)block_set, gensym("set"), + A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); class_addmethod(block_class, (t_method)block_dsp, gensym("dsp"), 0); class_addfloat(block_class, block_float); } diff --git a/pd/src/g_all_guis.c b/pd/src/g_all_guis.c index 97075684..606a6cf2 100644 --- a/pd/src/g_all_guis.c +++ b/pd/src/g_all_guis.c @@ -880,3 +880,79 @@ int iemgui_dialog(t_iemgui *iemgui, t_symbol **srl, int argc, t_atom *argv) iemgui_verify_snd_ne_rcv(iemgui); return(oldsndrcvable); } + +void iem_inttosymargs(t_iem_init_symargs *symargp, int n) +{ + memset(symargp, 0, sizeof(*symargp)); + symargp->x_loadinit = (n >> 0); + symargp->x_rcv_arg_tail_len = (n >> 1); + symargp->x_snd_arg_tail_len = (n >> 7); + symargp->x_rcv_is_arg_num = (n >> 13); + symargp->x_snd_is_arg_num = (n >> 19); + symargp->x_scale = (n >> 20); + symargp->x_flashed = (n >> 21); + symargp->x_locked = (n >> 22); + symargp->x_reverse = (n >> 23); + symargp->dummy = (n >> 24); +} + +int iem_symargstoint(t_iem_init_symargs *symargp) +{ + return ( + ((symargp->x_loadinit << 0) | + (symargp->x_rcv_arg_tail_len << 1) | + (symargp->x_snd_arg_tail_len << 7) | + (symargp->x_rcv_is_arg_num << 13) | + (symargp->x_snd_is_arg_num << 19) | + (symargp->x_scale << 20) | + (symargp->x_flashed << 21) | + (symargp->x_locked << 22) | + (symargp->x_reverse << 23) | + (symargp->dummy << 24)) & IEM_INIT_ARGS_ALL + ); +} + +void iem_inttofstyle(t_iem_fstyle_flags *fstylep, int n) +{ + memset(fstylep, 0, sizeof(*fstylep)); + fstylep->x_font_style = (n >> 0); + fstylep->x_rcv_able = (n >> 6); + fstylep->x_snd_able = (n >> 7); + fstylep->x_lab_is_unique = (n >> 8); + fstylep->x_rcv_is_unique = (n >> 9); + fstylep->x_snd_is_unique = (n >> 10); + fstylep->x_lab_arg_tail_len = (n >> 11); + fstylep->x_lab_is_arg_num = (n >> 17); + fstylep->x_shiftdown = (n >> 23); + fstylep->x_selected = (n >> 24); + fstylep->x_finemoved = (n >> 25); + fstylep->x_put_in2out = (n >> 26); + fstylep->x_change = (n >> 27); + fstylep->x_thick = (n >> 28); + fstylep->x_lin0_log1 = (n >> 29); + fstylep->x_steady = (n >> 30); + fstylep->dummy = (n >> 31); +} + +int iem_fstyletoint(t_iem_fstyle_flags *fstylep) +{ + return ( + ((fstylep->x_font_style << 0) | + (fstylep->x_rcv_able << 6) | + (fstylep->x_snd_able << 7) | + (fstylep->x_lab_is_unique << 8) | + (fstylep->x_rcv_is_unique << 9) | + (fstylep->x_snd_is_unique << 10) | + (fstylep->x_lab_arg_tail_len << 11) | + (fstylep->x_lab_is_arg_num << 17) | + (fstylep->x_shiftdown << 23) | + (fstylep->x_selected << 24) | + (fstylep->x_finemoved << 25) | + (fstylep->x_put_in2out << 26) | + (fstylep->x_change << 27) | + (fstylep->x_thick << 28) | + (fstylep->x_lin0_log1 << 29) | + (fstylep->x_steady << 30) | + (fstylep->dummy << 31)) & IEM_FSTYLE_FLAGS_ALL + ); +} diff --git a/pd/src/g_all_guis.h b/pd/src/g_all_guis.h index 77cf710d..91bf1753 100644 --- a/pd/src/g_all_guis.h +++ b/pd/src/g_all_guis.h @@ -317,3 +317,7 @@ EXTERN int iemgui_dialog(t_iemgui *iemgui, t_symbol **srl, int argc, t_atom *arg EXTERN int canvas_getdollarzero(void); EXTERN void canvas_getargs(int *argcp, t_atom **argvp); +EXTERN void iem_inttosymargs(t_iem_init_symargs *symargp, int n); +EXTERN int iem_symargstoint(t_iem_init_symargs *symargp); +EXTERN void iem_inttofstyle(t_iem_fstyle_flags *fstylep, int n); +EXTERN int iem_fstyletoint(t_iem_fstyle_flags *fstylep); diff --git a/pd/src/g_array.c b/pd/src/g_array.c index 2c2dfa8b..f42e913e 100644 --- a/pd/src/g_array.c +++ b/pd/src/g_array.c @@ -735,8 +735,6 @@ t_widgetbehavior garray_widgetbehavior = garray_delete, garray_vis, garray_click, - garray_save, - 0 }; /* ----------------------- public functions -------------------- */ @@ -1362,6 +1360,7 @@ void g_array_setup(void) gensym("normalize"), A_DEFFLOAT, 0); class_addmethod(garray_class, (t_method)garray_arraydialog, gensym("arraydialog"), A_SYMBOL, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL); + class_setsavefn(garray_class, garray_save); } diff --git a/pd/src/g_bang.c b/pd/src/g_bang.c index 07553972..1b1d6f4a 100644 --- a/pd/src/g_bang.c +++ b/pd/src/g_bang.c @@ -196,20 +196,18 @@ static void bng_getrect(t_gobj *z, t_glist *glist, int *xp1, int *yp1, int *xp2, static void bng_save(t_gobj *z, t_binbuf *b) { t_bng *x = (t_bng *)z; - int bflcol[3], *ip1, *ip2; + int bflcol[3]; t_symbol *srl[3]; iemgui_save(&x->x_gui, srl, bflcol); - ip1 = (int *)(&x->x_gui.x_isa); - ip2 = (int *)(&x->x_gui.x_fsf); binbuf_addv(b, "ssiisiiiisssiiiiiii", gensym("#X"),gensym("obj"), (t_int)x->x_gui.x_obj.te_xpix, (t_int)x->x_gui.x_obj.te_ypix, gensym("bng"), x->x_gui.x_w, x->x_flashtime_hold, x->x_flashtime_break, - (*ip1)&IEM_INIT_ARGS_ALL, + iem_symargstoint(&x->x_gui.x_isa), srl[0], srl[1], srl[2], x->x_gui.x_ldx, x->x_gui.x_ldy, - (*ip2)&IEM_FSTYLE_FLAGS_ALL, x->x_gui.x_fontsize, + iem_fstyletoint(&x->x_gui.x_fsf), x->x_gui.x_fontsize, bflcol[0], bflcol[1], bflcol[2]); binbuf_addv(b, ";"); } @@ -437,12 +435,13 @@ static void *bng_new(t_symbol *s, int argc, t_atom *argv) t_symbol *srl[3]; int a=IEM_GUI_DEFAULTSIZE; int ldx=0, ldy=-6; - int fs=8, iinit=0, ifstyle=0; - int ftbreak=IEM_BNG_DEFAULTBREAKFLASHTIME, fthold=IEM_BNG_DEFAULTHOLDFLASHTIME; - t_iem_init_symargs *init=(t_iem_init_symargs *)(&iinit); - t_iem_fstyle_flags *fstyle=(t_iem_fstyle_flags *)(&ifstyle); + int fs=8; + int ftbreak=IEM_BNG_DEFAULTBREAKFLASHTIME, + fthold=IEM_BNG_DEFAULTHOLDFLASHTIME; char str[144]; + iem_inttosymargs(&x->x_gui.x_isa, 0); + iem_inttofstyle(&x->x_gui.x_fsf, 0); srl[0] = gensym("empty"); srl[1] = gensym("empty"); srl[2] = gensym("empty"); @@ -461,7 +460,7 @@ static void *bng_new(t_symbol *s, int argc, t_atom *argv) a = (int)atom_getintarg(0, argc, argv); fthold = (int)atom_getintarg(1, argc, argv); ftbreak = (int)atom_getintarg(2, argc, argv); - iinit = (int)(atom_getintarg(3, argc, argv)); + iem_inttosymargs(&x->x_gui.x_isa, atom_getintarg(3, argc, argv)); if(IS_A_SYMBOL(argv,4)) srl[0] = atom_getsymbolarg(4, argc, argv); else if(IS_A_FLOAT(argv,4)) @@ -485,7 +484,7 @@ static void *bng_new(t_symbol *s, int argc, t_atom *argv) } ldx = (int)atom_getintarg(7, argc, argv); ldy = (int)atom_getintarg(8, argc, argv); - ifstyle = (int)(atom_getintarg(9, argc, argv)); + iem_inttofstyle(&x->x_gui.x_fsf, atom_getintarg(9, argc, argv)); fs = (int)atom_getintarg(10, argc, argv); bflcol[0] = (int)atom_getintarg(11, argc, argv); bflcol[1] = (int)atom_getintarg(12, argc, argv); @@ -493,22 +492,18 @@ static void *bng_new(t_symbol *s, int argc, t_atom *argv) } x->x_gui.x_draw = (t_iemfunptr)bng_draw; - iinit &= IEM_INIT_ARGS_ALL; - ifstyle &= IEM_FSTYLE_FLAGS_ALL; - fstyle->x_snd_able = 1; - fstyle->x_rcv_able = 1; + x->x_gui.x_fsf.x_snd_able = 1; + x->x_gui.x_fsf.x_rcv_able = 1; x->x_flashed = 0; x->x_gui.x_glist = (t_glist *)canvas_getcurrent(); - x->x_gui.x_isa = *init; - if(!strcmp(srl[0]->s_name, "empty")) fstyle->x_snd_able = 0; - if(!strcmp(srl[1]->s_name, "empty")) fstyle->x_rcv_able = 0; + if(!strcmp(srl[0]->s_name, "empty")) x->x_gui.x_fsf.x_snd_able = 0; + if(!strcmp(srl[1]->s_name, "empty")) x->x_gui.x_fsf.x_rcv_able = 0; x->x_gui.x_unique_num = 0; - if(fstyle->x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica"); - else if(fstyle->x_font_style == 2) strcpy(x->x_gui.x_font, "times"); - else { fstyle->x_font_style = 0; + if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica"); + else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times"); + else { x->x_gui.x_fsf.x_font_style = 0; strcpy(x->x_gui.x_font, "courier"); } - x->x_gui.x_fsf = *fstyle; iemgui_first_dollararg2sym(&x->x_gui, srl); if(x->x_gui.x_fsf.x_rcv_able) pd_bind(&x->x_gui.x_obj.ob_pd, srl[1]); @@ -577,8 +572,8 @@ void g_bang_setup(void) bng_widgetbehavior.w_deletefn = iemgui_delete; bng_widgetbehavior.w_visfn = iemgui_vis; bng_widgetbehavior.w_clickfn = bng_newclick; - bng_widgetbehavior.w_propertiesfn = bng_properties; - bng_widgetbehavior.w_savefn = bng_save; class_setwidget(bng_class, &bng_widgetbehavior); class_sethelpsymbol(bng_class, gensym("bng")); + class_setsavefn(bng_class, bng_save); + class_setpropertiesfn(bng_class, bng_properties); } diff --git a/pd/src/g_canvas.c b/pd/src/g_canvas.c index be771aa0..aee25c77 100644 --- a/pd/src/g_canvas.c +++ b/pd/src/g_canvas.c @@ -599,8 +599,6 @@ void canvas_dirty(t_canvas *x, t_int n) } } -extern t_gobj *canvas_selectme; /* HACK */ - /* the window becomes "mapped" (visible and not miniaturized) or "unmapped" (either miniaturized or just plain gone.) This should be called from the GUI after the fact to "notify" us that we're mapped. */ @@ -623,12 +621,6 @@ void canvas_map(t_canvas *x, t_floatarg f) for (sel = x->gl_editor->e_selection; sel; sel = sel->sel_next) gobj_select(sel->sel_what, x, 1); x->gl_mapped = 1; - if (canvas_selectme) - { - glist_noselect(x); - glist_select(x, canvas_selectme); - canvas_selectme = 0; - } canvas_drawlines(x); /* simulate a mouse up so u_main will calculate scrollbars... ugly! */ @@ -639,8 +631,13 @@ void canvas_map(t_canvas *x, t_floatarg f) { if (glist_isvisible(x)) { + /* just clear out the whole canvas... */ + sys_vgui(".x%x.c delete all\n", x); + /* alternatively, we could have erased them one by one... for (y = x->gl_list; y; y = y->g_next) gobj_vis(y, x, 0); + ... but we should go through and erase the lines as well + if we do it that way. */ x->gl_mapped = 0; } } @@ -756,7 +753,7 @@ void canvas_vis(t_canvas *x, t_floatarg f) if (!x->gl_havewindow) { /* bug workaround -- a graph in a visible patch gets "invised" - when the patch is closed, and must lost the editor here. It's + when the patch is closed, and must lose the editor here. It's probably not the natural place to do this. Other cases like subpatches fall here too but don'd need the editor freed, so we check if it exists. */ @@ -1303,9 +1300,15 @@ void glob_dsp(void *dummy, t_symbol *s, int argc, t_atom *argv) { newstate = atom_getintarg(0, argc, argv); if (newstate && !canvas_dspstate) + { canvas_start_dsp(); + sys_set_audio_state(1); + } else if (!newstate && canvas_dspstate) + { canvas_stop_dsp(); + sys_set_audio_state(0); + } } else post("dsp state %d", canvas_dspstate); } @@ -1341,65 +1344,11 @@ static void glist_redrawall(t_glist *gl) void canvas_redrawallfortemplate(t_canvas *templatecanvas) { t_canvas *x; - if (!templatecanvas->gl_imatemplate) return; /* find all root canvases */ for (x = canvas_list; x; x = x->gl_next) glist_redrawall(x); } - /* Same as above but just zap them. Call this if a template - is changed by adding or removing a field. LATER we'll just - modify all the items appropriately. */ -static void glist_zapall(t_glist *gl) -{ - t_gobj *g; - for (g = gl->gl_list; g; g = g->g_next) - { - t_class *cl; - if (g->g_pd == canvas_class) - glist_zapall((t_glist *)g); - } - /* do we have any scalars? */ - for (g = gl->gl_list; g; g = g->g_next) - { - if (g->g_pd == scalar_class) - break; - } - if (!g) return; - /* delete all the scalars. This is inefficient if for some reason - you've mixed scalars with other items in a single glist. */ - while (1) - { - for (g = gl->gl_list; g; g = g->g_next) - { - if (g->g_pd == scalar_class) - { - glist_delete(gl, g); - break; - } - } - if (!g) break; - } -} - - /* public interface for above */ -void canvas_zapallfortemplate(t_canvas *templatecanvas) -{ - t_canvas *x; - if (!templatecanvas->gl_imatemplate) return; - /* find all root canvases */ - for (x = canvas_list; x; x = x->gl_next) - glist_zapall(x); -} - - /* warn a canvas that some datum has used it as a template. If a - canvas has no data associated with it (at load time, for instance) - we don't have to search through the world for instances as it changes. */ -void canvas_setusedastemplate(t_canvas *x) -{ - x->gl_imatemplate = 1; -} - /* ------------------------------- setup routine ------------------------ */ /* why are some of these "glist" and others "canvas"? */ @@ -1427,6 +1376,7 @@ extern void glist_scalar(t_glist *canvas, t_symbol *s, int argc, t_atom *argv); void g_graph_setup(void); void g_editor_setup(void); void g_readwrite_setup(void); +extern void graph_properties(t_gobj *z, t_glist *owner); void g_canvas_setup(void) { @@ -1497,6 +1447,7 @@ void g_canvas_setup(void) gensym("menu-open"), A_NULL); class_addmethod(canvas_class, (t_method)canvas_map, gensym("map"), A_FLOAT, A_NULL); + class_setpropertiesfn(canvas_class, graph_properties); /* ---------------------- list handling ------------------------ */ class_addmethod(canvas_class, (t_method)glist_clear, gensym("clear"), diff --git a/pd/src/g_canvas.h b/pd/src/g_canvas.h index afaecbf5..d3070849 100644 --- a/pd/src/g_canvas.h +++ b/pd/src/g_canvas.h @@ -174,7 +174,6 @@ struct _glist unsigned int gl_loading:1; /* am now loading from file */ unsigned int gl_willvis:1; /* make me visible after loading */ unsigned int gl_edit:1; /* edit mode */ - unsigned int gl_imatemplate:1; /* someone needs me as template */ unsigned int gl_isdeleting:1; /* we're inside glist_delete -- hack! */ unsigned int gl_stretch:1; /* stretch contents on resize */ unsigned int gl_isgraph:1; /* show as graph on parent */ @@ -259,10 +258,6 @@ typedef void (*t_visfn)(t_gobj *x, struct _glist *glist, int flag); /* field a mouse click (when not in "edit" mode) */ typedef int (*t_clickfn)(t_gobj *x, struct _glist *glist, int xpix, int ypix, int shift, int alt, int dbl, int doit); - /* save to a binbuf */ -typedef void (*t_savefn)(t_gobj *x, t_binbuf *b); - /* open properties dialog */ -typedef void (*t_propertiesfn)(t_gobj *x, struct _glist *glist); /* ... and later, resizing; getting/setting font or color... */ struct _widgetbehavior @@ -274,8 +269,6 @@ struct _widgetbehavior t_deletefn w_deletefn; t_visfn w_visfn; t_clickfn w_clickfn; - t_savefn w_savefn; - t_propertiesfn w_propertiesfn; }; /* -------- behaviors for scalars defined by objects in template --------- */ @@ -350,6 +343,7 @@ EXTERN int gobj_click(t_gobj *x, struct _glist *glist, int xpix, int ypix, int shift, int alt, int dbl, int doit); EXTERN void gobj_save(t_gobj *x, t_binbuf *b); EXTERN void gobj_properties(t_gobj *x, struct _glist *glist); +EXTERN void gobj_save(t_gobj *x, t_binbuf *b); /* -------------------- functions on glists --------------------- */ EXTERN t_glist *glist_new( void); diff --git a/pd/src/g_editor.c b/pd/src/g_editor.c index 3612d61f..74da81eb 100644 --- a/pd/src/g_editor.c +++ b/pd/src/g_editor.c @@ -74,18 +74,6 @@ int gobj_click(t_gobj *x, struct _glist *glist, else return (0); } -void gobj_save(t_gobj *x, t_binbuf *b) -{ - if (x->g_pd->c_wb && x->g_pd->c_wb->w_savefn) - (*x->g_pd->c_wb->w_savefn)(x, b); -} - -void gobj_properties(t_gobj *x, struct _glist *glist) -{ - if (x->g_pd->c_wb && x->g_pd->c_wb->w_propertiesfn) - (*x->g_pd->c_wb->w_propertiesfn)(x, glist); -} - /* ------------------------ managing the selection ----------------- */ void glist_selectline(t_glist *x, t_outconnect *oc, int index1, @@ -794,7 +782,7 @@ static t_gobj *canvas_findhitbox(t_canvas *x, int xpos, int ypos, static void canvas_rightclick(t_canvas *x, int xpos, int ypos, t_gobj *y) { int canprop, canopen; - canprop = (!y || (y && y->g_pd->c_wb && y->g_pd->c_wb->w_propertiesfn)); + canprop = (!y || (y && class_getpropertiesfn(pd_class(&y->g_pd)))); canopen = (y && zgetfn(&y->g_pd, gensym("menu-open"))); sys_vgui("pdtk_canvas_popup .x%x %d %d %d %d\n", x, xpos, ypos, canprop, canopen); @@ -906,9 +894,9 @@ static void canvas_done_popup(t_canvas *x, float which, float xpos, float ypos) { if (which == 0) /* properties */ { - if (!y->g_pd->c_wb || !y->g_pd->c_wb->w_propertiesfn) + if (!class_getpropertiesfn(pd_class(&y->g_pd))) continue; - gobj_properties(y, x); + (*class_getpropertiesfn(pd_class(&y->g_pd)))(y, x); return; } else if (which == 1) /* open */ @@ -1576,7 +1564,6 @@ static void canvas_menufont(t_canvas *x) static int canvas_find_index1, canvas_find_index2; static t_binbuf *canvas_findbuf; int binbuf_match(t_binbuf *inbuf, t_binbuf *searchbuf); -t_gobj *canvas_selectme; /* HACK */ /* find an atom or string of atoms */ static int canvas_dofind(t_canvas *x, int *myindex1p) @@ -1600,33 +1587,9 @@ static int canvas_dofind(t_canvas *x, int *myindex1p) canvas_find_index1 = myindex1; canvas_find_index2 = myindex2; glist_noselect(x); - if (glist_isvisible(x)) - { -#ifdef MSW - /* For windows canvas_vis() does something - special so here we explicitly invis - the window and proceed as in the "invis" - case below. */ - canvas_vis(x, 0); - canvas_selectme = y; - canvas_vis(x, 1); -#else - canvas_vis(x, 1); - canvas_editmode(x, 1.); - glist_select(x, y); -#endif - } - else - { - /* LATER fix so we can select it right here. - ERight now, HACK it so that canvas_map selects it. - We can't select earlier because the rtexts aren't - created in time. Should create the rtexts in - canvas_vis() but we don't so that yet. */ - - canvas_selectme = y; - canvas_vis(x, 1); - } + canvas_vis(x, 1); + canvas_editmode(x, 1.); + glist_select(x, y); return (1); } } @@ -1701,9 +1664,7 @@ static int glist_dofinderror(t_glist *gl, void *error_object) glist_noselect(gl); canvas_vis(glist_getcanvas(gl), 1); canvas_editmode(glist_getcanvas(gl), 1.); - /* we can't just select here ala glist_select(gl, g); instead, - as in "find", set "selectme" for when "map" function is called. */ - canvas_selectme = g; + glist_select(gl, g); return (1); } else if (g->g_pd == canvas_class) @@ -2160,7 +2121,6 @@ void canvas_editmode(t_canvas *x, t_floatarg fyesplease) } sys_vgui("pdtk_canvas_editval .x%x %d\n", glist_getcanvas(x), x->gl_edit); - if (yesplease) canvas_dirty(x, 1); } /* called by canvas_font below */ diff --git a/pd/src/g_graph.c b/pd/src/g_graph.c index 9bf998f8..3347fb9b 100644 --- a/pd/src/g_graph.c +++ b/pd/src/g_graph.c @@ -626,8 +626,6 @@ void glist_redraw(t_glist *x) } } -t_class *graph_class; - /* --------------------------- widget behavior ------------------- */ extern t_widgetbehavior text_widgetbehavior; @@ -1021,15 +1019,20 @@ static int graph_click(t_gobj *z, struct _glist *glist, } } -static void graph_save(t_gobj *z, t_binbuf *b) -{ - t_glist *x = (t_glist *)z; - text_widgetbehavior.w_savefn(z, b); -} - void garray_properties(t_garray *x); -static void graph_properties(t_gobj *z, t_glist *owner) +t_widgetbehavior graph_widgetbehavior = +{ + graph_getrect, + graph_displace, + graph_select, + graph_activate, + graph_delete, + graph_vis, + graph_click, +}; + +void graph_properties(t_gobj *z, t_glist *owner) { t_glist *x = (t_glist *)z; { @@ -1046,19 +1049,6 @@ static void graph_properties(t_gobj *z, t_glist *owner) } } -t_widgetbehavior graph_widgetbehavior = -{ - graph_getrect, - graph_displace, - graph_select, - graph_activate, - graph_delete, - graph_vis, - graph_click, - graph_save, - graph_properties, -}; - /* find the graph most recently added to this glist; if none exists, return 0. */ diff --git a/pd/src/g_hdial.c b/pd/src/g_hdial.c index 1d1b4c6d..f7267c99 100644 --- a/pd/src/g_hdial.c +++ b/pd/src/g_hdial.c @@ -234,22 +234,20 @@ static void hradio_getrect(t_gobj *z, t_glist *glist, int *xp1, int *yp1, int *x static void hradio_save(t_gobj *z, t_binbuf *b) { t_hradio *x = (t_hradio *)z; - int bflcol[3], *ip1, *ip2; + int bflcol[3]; t_symbol *srl[3]; iemgui_save(&x->x_gui, srl, bflcol); - ip1 = (int *)(&x->x_gui.x_isa); - ip2 = (int *)(&x->x_gui.x_fsf); binbuf_addv(b, "ssiisiiiisssiiiiiiii", gensym("#X"),gensym("obj"), (t_int)text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist), (t_int)text_ypix(&x->x_gui.x_obj, x->x_gui.x_glist), (pd_class(&x->x_gui.x_obj.ob_pd) == hradio_old_class ? gensym("hdl") : gensym("hradio")), x->x_gui.x_w, - x->x_change, (*ip1)&IEM_INIT_ARGS_ALL, x->x_number, + x->x_change, iem_symargstoint(&x->x_gui.x_isa), x->x_number, srl[0], srl[1], srl[2], x->x_gui.x_ldx, x->x_gui.x_ldy, - (*ip2)&IEM_FSTYLE_FLAGS_ALL, x->x_gui.x_fontsize, + iem_fstyletoint(&x->x_gui.x_fsf), x->x_gui.x_fontsize, bflcol[0], bflcol[1], bflcol[2], x->x_on); binbuf_addv(b, ";"); } @@ -544,12 +542,12 @@ static void *hradio_donew(t_symbol *s, int argc, t_atom *argv, int old) t_symbol *srl[3]; int a=IEM_GUI_DEFAULTSIZE, on=0, f=0; int ldx=0, ldy=-6, chg=1, num=8; - int fs=8, iinit=0, ifstyle=0; + int fs=8; int ftbreak=IEM_BNG_DEFAULTBREAKFLASHTIME, fthold=IEM_BNG_DEFAULTHOLDFLASHTIME; - t_iem_init_symargs *init=(t_iem_init_symargs *)(&iinit); - t_iem_fstyle_flags *fstyle=(t_iem_fstyle_flags *)(&ifstyle); char str[144]; + iem_inttosymargs(&x->x_gui.x_isa, 0); + iem_inttofstyle(&x->x_gui.x_fsf, 0); srl[0] = gensym("empty"); srl[1] = gensym("empty"); srl[2] = gensym("empty"); @@ -565,7 +563,7 @@ static void *hradio_donew(t_symbol *s, int argc, t_atom *argv, int old) { a = (int)atom_getintarg(0, argc, argv); chg = (int)atom_getintarg(1, argc, argv); - iinit = (int)atom_getintarg(2, argc, argv); + iem_inttosymargs(&x->x_gui.x_isa, atom_getintarg(2, argc, argv)); num = (int)atom_getintarg(3, argc, argv); if(IS_A_SYMBOL(argv,4)) srl[0] = atom_getsymbolarg(4, argc, argv); @@ -590,7 +588,7 @@ static void *hradio_donew(t_symbol *s, int argc, t_atom *argv, int old) } ldx = (int)atom_getintarg(7, argc, argv); ldy = (int)atom_getintarg(8, argc, argv); - ifstyle = (int)atom_getintarg(9, argc, argv); + iem_inttofstyle(&x->x_gui.x_fsf, atom_getintarg(9, argc, argv)); fs = (int)atom_getintarg(10, argc, argv); bflcol[0] = (int)atom_getintarg(11, argc, argv); bflcol[1] = (int)atom_getintarg(12, argc, argv); @@ -598,19 +596,15 @@ static void *hradio_donew(t_symbol *s, int argc, t_atom *argv, int old) on = (int)atom_getintarg(14, argc, argv); } x->x_gui.x_draw = (t_iemfunptr)hradio_draw; - iinit &= IEM_INIT_ARGS_ALL; - ifstyle &= IEM_FSTYLE_FLAGS_ALL; - fstyle->x_snd_able = 1; - fstyle->x_rcv_able = 1; + x->x_gui.x_fsf.x_snd_able = 1; + x->x_gui.x_fsf.x_rcv_able = 1; x->x_gui.x_glist = (t_glist *)canvas_getcurrent(); - x->x_gui.x_isa = *init; - if(!strcmp(srl[0]->s_name, "empty")) fstyle->x_snd_able = 0; - if(!strcmp(srl[1]->s_name, "empty")) fstyle->x_rcv_able = 0; - if(fstyle->x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica"); - else if(fstyle->x_font_style == 2) strcpy(x->x_gui.x_font, "times"); - else { fstyle->x_font_style = 0; + if(!strcmp(srl[0]->s_name, "empty")) x->x_gui.x_fsf.x_snd_able = 0; + if(!strcmp(srl[1]->s_name, "empty")) x->x_gui.x_fsf.x_rcv_able = 0; + if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica"); + else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times"); + else { x->x_gui.x_fsf.x_font_style = 0; strcpy(x->x_gui.x_font, "courier"); } - x->x_gui.x_fsf = *fstyle; x->x_gui.x_unique_num = 0; if(num < 1) num = 1; @@ -709,10 +703,10 @@ void g_hradio_setup(void) hradio_widgetbehavior.w_deletefn = iemgui_delete; hradio_widgetbehavior.w_visfn = iemgui_vis; hradio_widgetbehavior.w_clickfn = hradio_newclick; - hradio_widgetbehavior.w_propertiesfn = hradio_properties; - hradio_widgetbehavior.w_savefn = hradio_save; class_setwidget(hradio_class, &hradio_widgetbehavior); class_sethelpsymbol(hradio_class, gensym("hradio")); + class_setsavefn(hradio_class, hradio_save); + class_setpropertiesfn(hradio_class, hradio_properties); /*obsolete version (0.34-0.35) */ hradio_old_class = class_new(gensym("hdl"), (t_newmethod)hdial_new, @@ -759,5 +753,4 @@ void g_hradio_setup(void) gensym("double_change"), 0); class_setwidget(hradio_old_class, &hradio_widgetbehavior); class_sethelpsymbol(hradio_old_class, gensym("hradio")); - } diff --git a/pd/src/g_hslider.c b/pd/src/g_hslider.c index ed805f4b..a805e7dd 100644 --- a/pd/src/g_hslider.c +++ b/pd/src/g_hslider.c @@ -214,20 +214,18 @@ static void hslider_getrect(t_gobj *z, t_glist *glist, static void hslider_save(t_gobj *z, t_binbuf *b) { t_hslider *x = (t_hslider *)z; - int bflcol[3], *ip1, *ip2; + int bflcol[3]; t_symbol *srl[3]; iemgui_save(&x->x_gui, srl, bflcol); - ip1 = (int *)(&x->x_gui.x_isa); - ip2 = (int *)(&x->x_gui.x_fsf); binbuf_addv(b, "ssiisiiffiisssiiiiiiiii", gensym("#X"),gensym("obj"), (t_int)x->x_gui.x_obj.te_xpix, (t_int)x->x_gui.x_obj.te_ypix, gensym("hsl"), x->x_gui.x_w, x->x_gui.x_h, (float)x->x_min, (float)x->x_max, - x->x_lin0_log1, (*ip1)&IEM_INIT_ARGS_ALL, + x->x_lin0_log1, iem_symargstoint(&x->x_gui.x_isa), srl[0], srl[1], srl[2], x->x_gui.x_ldx, x->x_gui.x_ldy, - (*ip2)&IEM_FSTYLE_FLAGS_ALL, x->x_gui.x_fontsize, + iem_fstyletoint(&x->x_gui.x_fsf), x->x_gui.x_fontsize, bflcol[0], bflcol[1], bflcol[2], x->x_val, x->x_steady); binbuf_addv(b, ";"); @@ -529,12 +527,12 @@ static void *hslider_new(t_symbol *s, int argc, t_atom *argv) t_symbol *srl[3]; int w=IEM_SL_DEFAULTSIZE, h=IEM_GUI_DEFAULTSIZE; int lilo=0, ldx=-2, ldy=-6, f=0, v=0, steady=1; - int fs=8, iinit=0, ifstyle=0; + int fs=8; double min=0.0, max=(double)(IEM_SL_DEFAULTSIZE-1); - t_iem_init_symargs *init=(t_iem_init_symargs *)(&iinit); - t_iem_fstyle_flags *fstyle=(t_iem_fstyle_flags *)(&ifstyle); char str[144]; + iem_inttosymargs(&x->x_gui.x_isa, 0); + iem_inttofstyle(&x->x_gui.x_fsf, 0); srl[0] = gensym("empty"); srl[1] = gensym("empty"); srl[2] = gensym("empty"); @@ -554,7 +552,7 @@ static void *hslider_new(t_symbol *s, int argc, t_atom *argv) min = (double)atom_getfloatarg(2, argc, argv); max = (double)atom_getfloatarg(3, argc, argv); lilo = (int)atom_getintarg(4, argc, argv); - iinit = (int)atom_getintarg(5, argc, argv); + iem_inttosymargs(&x->x_gui.x_isa, atom_getintarg(5, argc, argv)); if(IS_A_SYMBOL(argv,6)) srl[0] = atom_getsymbolarg(6, argc, argv); else if(IS_A_FLOAT(argv,6)) @@ -578,7 +576,7 @@ static void *hslider_new(t_symbol *s, int argc, t_atom *argv) } ldx = (int)atom_getintarg(9, argc, argv); ldy = (int)atom_getintarg(10, argc, argv); - ifstyle = (int)atom_getintarg(11, argc, argv); + iem_inttofstyle(&x->x_gui.x_fsf, atom_getintarg(11, argc, argv)); fs = (int)atom_getintarg(12, argc, argv); bflcol[0] = (int)atom_getintarg(13, argc, argv); bflcol[1] = (int)atom_getintarg(14, argc, argv); @@ -589,14 +587,11 @@ static void *hslider_new(t_symbol *s, int argc, t_atom *argv) steady = (int)atom_getintarg(17, argc, argv); x->x_gui.x_draw = (t_iemfunptr)hslider_draw; - iinit &= IEM_INIT_ARGS_ALL; - ifstyle &= IEM_FSTYLE_FLAGS_ALL; - fstyle->x_snd_able = 1; - fstyle->x_rcv_able = 1; + x->x_gui.x_fsf.x_snd_able = 1; + x->x_gui.x_fsf.x_rcv_able = 1; x->x_gui.x_glist = (t_glist *)canvas_getcurrent(); - x->x_gui.x_isa = *init; if(x->x_gui.x_isa.x_loadinit) x->x_val = v; else @@ -606,14 +601,13 @@ static void *hslider_new(t_symbol *s, int argc, t_atom *argv) x->x_lin0_log1 = lilo; if(steady != 0) steady = 1; x->x_steady = steady; - if(!strcmp(srl[0]->s_name, "empty")) fstyle->x_snd_able = 0; - if(!strcmp(srl[1]->s_name, "empty")) fstyle->x_rcv_able = 0; + if(!strcmp(srl[0]->s_name, "empty")) x->x_gui.x_fsf.x_snd_able = 0; + if(!strcmp(srl[1]->s_name, "empty")) x->x_gui.x_fsf.x_rcv_able = 0; x->x_gui.x_unique_num = 0; - if(fstyle->x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica"); - else if(fstyle->x_font_style == 2) strcpy(x->x_gui.x_font, "times"); - else { fstyle->x_font_style = 0; + if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica"); + else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times"); + else { x->x_gui.x_fsf.x_font_style = 0; strcpy(x->x_gui.x_font, "courier"); } - x->x_gui.x_fsf = *fstyle; iemgui_first_dollararg2sym(&x->x_gui, srl); if(x->x_gui.x_fsf.x_rcv_able) pd_bind(&x->x_gui.x_obj.ob_pd, srl[1]); x->x_gui.x_snd = srl[0]; @@ -678,8 +672,8 @@ void g_hslider_setup(void) hslider_widgetbehavior.w_deletefn = iemgui_delete; hslider_widgetbehavior.w_visfn = iemgui_vis; hslider_widgetbehavior.w_clickfn = hslider_newclick; - hslider_widgetbehavior.w_propertiesfn = hslider_properties; - hslider_widgetbehavior.w_savefn = hslider_save; class_setwidget(hslider_class, &hslider_widgetbehavior); class_sethelpsymbol(hslider_class, gensym("hslider")); + class_setsavefn(hslider_class, hslider_save); + class_setpropertiesfn(hslider_class, hslider_properties); } diff --git a/pd/src/g_io.c b/pd/src/g_io.c index 487be350..196d44d8 100644 --- a/pd/src/g_io.c +++ b/pd/src/g_io.c @@ -481,11 +481,12 @@ static void voutlet_dsp(t_voutlet *x, t_signal **sp) time to copy the samples out to the containing object's outlets. If we aren't reblocking, there's nothing to do here. */ void voutlet_dspepilog(t_voutlet *x, t_signal **parentsigs, - int myvecsize, int phase, int period, int frequency, int downsample, int upsample /* IOhannes */, int reblock, - int switched) + int myvecsize, int phase, int period, int frequency, int downsample, + int upsample /* IOhannes */, int reblock, int switched) { if (!x->x_buf) return; /* this shouldn't be necesssary... */ - x->x_updown.downsample=downsample; x->x_updown.upsample=upsample; /* IOhannes */ + x->x_updown.downsample=downsample; + x->x_updown.upsample=upsample; /* IOhannes */ if (reblock) { t_signal *insig, *outsig; diff --git a/pd/src/g_mycanvas.c b/pd/src/g_mycanvas.c index 6af4e269..f723cff9 100644 --- a/pd/src/g_mycanvas.c +++ b/pd/src/g_mycanvas.c @@ -132,18 +132,16 @@ static void my_canvas_getrect(t_gobj *z, t_glist *glist, int *xp1, int *yp1, int static void my_canvas_save(t_gobj *z, t_binbuf *b) { t_my_canvas *x = (t_my_canvas *)z; - int bflcol[3], *ip1, *ip2; + int bflcol[3]; t_symbol *srl[3]; iemgui_save(&x->x_gui, srl, bflcol); - ip1 = (int *)(&x->x_gui.x_isa); - ip2 = (int *)(&x->x_gui.x_fsf); binbuf_addv(b, "ssiisiiisssiiiiiii", gensym("#X"),gensym("obj"), (t_int)x->x_gui.x_obj.te_xpix, (t_int)x->x_gui.x_obj.te_ypix, gensym("cnv"), x->x_gui.x_w, x->x_vis_w, x->x_vis_h, srl[0], srl[1], srl[2], x->x_gui.x_ldx, x->x_gui.x_ldy, - (*ip2)&IEM_FSTYLE_FLAGS_ALL, x->x_gui.x_fontsize, - bflcol[0], bflcol[2], (*ip1)&IEM_INIT_ARGS_ALL); + iem_fstyletoint(&x->x_gui.x_fsf), x->x_gui.x_fontsize, + bflcol[0], bflcol[2], iem_symargstoint(&x->x_gui.x_isa)); binbuf_addv(b, ";"); } @@ -266,11 +264,11 @@ static void *my_canvas_new(t_symbol *s, int argc, t_atom *argv) t_symbol *srl[3]; int a=IEM_GUI_DEFAULTSIZE, w=100, h=60; int ldx=20, ldy=12, f=2, i=0; - int fs=14, iinit=0, ifstyle=0; - t_iem_init_symargs *init=(t_iem_init_symargs *)(&iinit); - t_iem_fstyle_flags *fstyle=(t_iem_fstyle_flags *)(&ifstyle); + int fs=14; char str[144]; + iem_inttosymargs(&x->x_gui.x_isa, 0); + iem_inttofstyle(&x->x_gui.x_fsf, 0); srl[0] = gensym("empty"); srl[1] = gensym("empty"); srl[2] = gensym("empty"); @@ -327,24 +325,21 @@ static void *my_canvas_new(t_symbol *s, int argc, t_atom *argv) } ldx = (int)atom_getintarg(i+4, argc, argv); ldy = (int)atom_getintarg(i+5, argc, argv); - ifstyle = (int)atom_getintarg(i+6, argc, argv); + iem_inttofstyle(&x->x_gui.x_fsf, atom_getintarg(i+6, argc, argv)); fs = (int)atom_getintarg(i+7, argc, argv); bflcol[0] = (int)atom_getintarg(i+8, argc, argv); bflcol[2] = (int)atom_getintarg(i+9, argc, argv); } if((argc == 13)&&IS_A_FLOAT(argv,i+10)) { - iinit = (int)(atom_getintarg(i+10, argc, argv)); + iem_inttosymargs(&x->x_gui.x_isa, atom_getintarg(i+10, argc, argv)); } x->x_gui.x_draw = (t_iemfunptr)my_canvas_draw; - iinit &= IEM_INIT_ARGS_ALL; - ifstyle &= IEM_FSTYLE_FLAGS_ALL; - fstyle->x_snd_able = 1; - fstyle->x_rcv_able = 1; + x->x_gui.x_fsf.x_snd_able = 1; + x->x_gui.x_fsf.x_rcv_able = 1; x->x_gui.x_glist = (t_glist *)canvas_getcurrent(); - x->x_gui.x_isa = *init; - if(!strcmp(srl[0]->s_name, "empty")) fstyle->x_snd_able = 0; - if(!strcmp(srl[1]->s_name, "empty")) fstyle->x_rcv_able = 0; + if(!strcmp(srl[0]->s_name, "empty")) x->x_gui.x_fsf.x_snd_able = 0; + if(!strcmp(srl[1]->s_name, "empty")) x->x_gui.x_fsf.x_rcv_able = 0; x->x_gui.x_unique_num = 0; if(a < 1) a = 1; @@ -356,11 +351,10 @@ static void *my_canvas_new(t_symbol *s, int argc, t_atom *argv) if(h < 1) h = 1; x->x_vis_h = h; - if(fstyle->x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica"); - else if(fstyle->x_font_style == 2) strcpy(x->x_gui.x_font, "times"); - else { fstyle->x_font_style = 0; + if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica"); + else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times"); + else { x->x_gui.x_fsf.x_font_style = 0; strcpy(x->x_gui.x_font, "courier"); } - x->x_gui.x_fsf = *fstyle; iemgui_first_dollararg2sym(&x->x_gui, srl); if(x->x_gui.x_fsf.x_rcv_able) pd_bind(&x->x_gui.x_obj.ob_pd, srl[1]); x->x_gui.x_snd = srl[0]; @@ -410,8 +404,8 @@ void g_mycanvas_setup(void) my_canvas_widgetbehavior.w_deletefn = iemgui_delete; my_canvas_widgetbehavior.w_visfn = iemgui_vis; my_canvas_widgetbehavior.w_clickfn = NULL; - my_canvas_widgetbehavior.w_propertiesfn = my_canvas_properties; - my_canvas_widgetbehavior.w_savefn = my_canvas_save; class_setwidget(my_canvas_class, &my_canvas_widgetbehavior); class_sethelpsymbol(my_canvas_class, gensym("my_canvas")); + class_setsavefn(my_canvas_class, my_canvas_save); + class_setpropertiesfn(my_canvas_class, my_canvas_properties); } diff --git a/pd/src/g_numbox.c b/pd/src/g_numbox.c index abf19e44..f6288128 100644 --- a/pd/src/g_numbox.c +++ b/pd/src/g_numbox.c @@ -375,7 +375,7 @@ static void my_numbox_getrect(t_gobj *z, t_glist *glist, static void my_numbox_save(t_gobj *z, t_binbuf *b) { t_my_numbox *x = (t_my_numbox *)z; - int bflcol[3], *ip1, *ip2; + int bflcol[3]; t_symbol *srl[3]; iemgui_save(&x->x_gui, srl, bflcol); @@ -387,16 +387,14 @@ static void my_numbox_save(t_gobj *z, t_binbuf *b) (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE); } - ip1 = (int *)(&x->x_gui.x_isa); - ip2 = (int *)(&x->x_gui.x_fsf); binbuf_addv(b, "ssiisiiffiisssiiiiiiifi", gensym("#X"),gensym("obj"), (t_int)x->x_gui.x_obj.te_xpix, (t_int)x->x_gui.x_obj.te_ypix, gensym("nbx"), x->x_gui.x_w, x->x_gui.x_h, (float)x->x_min, (float)x->x_max, - x->x_lin0_log1, (*ip1)&IEM_INIT_ARGS_ALL, + x->x_lin0_log1, iem_symargstoint(&x->x_gui.x_isa), srl[0], srl[1], srl[2], x->x_gui.x_ldx, x->x_gui.x_ldy, - (*ip2)&IEM_FSTYLE_FLAGS_ALL, x->x_gui.x_fontsize, + iem_fstyletoint(&x->x_gui.x_fsf), x->x_gui.x_fontsize, bflcol[0], bflcol[1], bflcol[2], x->x_val, x->x_log_height); binbuf_addv(b, ";"); @@ -758,11 +756,9 @@ static void *my_numbox_new(t_symbol *s, int argc, t_atom *argv) t_symbol *srl[3]; int w=5, h=14; int lilo=0, f=0, ldx=0, ldy=-6; - int fs=10, iinit=0, ifstyle=0; + int fs=10; int log_height=256; double min=-1.0e+37, max=1.0e+37,v=0.0; - t_iem_init_symargs *init=(t_iem_init_symargs *)(&iinit); - t_iem_fstyle_flags *fstyle=(t_iem_fstyle_flags *)(&ifstyle); char str[144]; srl[0] = gensym("empty"); @@ -785,7 +781,7 @@ static void *my_numbox_new(t_symbol *s, int argc, t_atom *argv) min = (double)atom_getfloatarg(2, argc, argv); max = (double)atom_getfloatarg(3, argc, argv); lilo = (int)atom_getintarg(4, argc, argv); - iinit = (int)atom_getintarg(5, argc, argv); + iem_inttosymargs(&x->x_gui.x_isa, atom_getintarg(5, argc, argv)); srl[0] = atom_getsymbolarg(6, argc, argv); srl[1] = atom_getsymbolarg(7, argc, argv); srl[2] = atom_getsymbolarg(8, argc, argv); @@ -812,7 +808,7 @@ static void *my_numbox_new(t_symbol *s, int argc, t_atom *argv) } ldx = (int)atom_getintarg(9, argc, argv); ldy = (int)atom_getintarg(10, argc, argv); - ifstyle = (int)atom_getintarg(11, argc, argv); + iem_inttofstyle(&x->x_gui.x_fsf, atom_getintarg(11, argc, argv)); fs = (int)atom_getintarg(12, argc, argv); bflcol[0] = (int)atom_getintarg(13, argc, argv); bflcol[1] = (int)atom_getintarg(14, argc, argv); @@ -824,12 +820,9 @@ static void *my_numbox_new(t_symbol *s, int argc, t_atom *argv) log_height = (int)atom_getintarg(17, argc, argv); } x->x_gui.x_draw = (t_iemfunptr)my_numbox_draw; - iinit &= IEM_INIT_ARGS_ALL; - ifstyle &= IEM_FSTYLE_FLAGS_ALL; - fstyle->x_snd_able = 1; - fstyle->x_rcv_able = 1; + x->x_gui.x_fsf.x_snd_able = 1; + x->x_gui.x_fsf.x_rcv_able = 1; x->x_gui.x_glist = (t_glist *)canvas_getcurrent(); - x->x_gui.x_isa = *init; if(x->x_gui.x_isa.x_loadinit) x->x_val = v; else @@ -839,14 +832,13 @@ static void *my_numbox_new(t_symbol *s, int argc, t_atom *argv) if(log_height < 10) log_height = 10; x->x_log_height = log_height; - if(!strcmp(srl[0]->s_name, "empty")) fstyle->x_snd_able = 0; - if(!strcmp(srl[1]->s_name, "empty")) fstyle->x_rcv_able = 0; + if(!strcmp(srl[0]->s_name, "empty")) x->x_gui.x_fsf.x_snd_able = 0; + if(!strcmp(srl[1]->s_name, "empty")) x->x_gui.x_fsf.x_rcv_able = 0; x->x_gui.x_unique_num = 0; - if(fstyle->x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica"); - else if(fstyle->x_font_style == 2) strcpy(x->x_gui.x_font, "times"); - else { fstyle->x_font_style = 0; + if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica"); + else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times"); + else { x->x_gui.x_fsf.x_font_style = 0; strcpy(x->x_gui.x_font, "courier"); } - x->x_gui.x_fsf = *fstyle; iemgui_first_dollararg2sym(&x->x_gui, srl); if(x->x_gui.x_fsf.x_rcv_able) pd_bind(&x->x_gui.x_obj.ob_pd, srl[1]); x->x_gui.x_snd = srl[0]; @@ -938,8 +930,8 @@ void g_numbox_setup(void) my_numbox_widgetbehavior.w_deletefn = iemgui_delete; my_numbox_widgetbehavior.w_visfn = iemgui_vis; my_numbox_widgetbehavior.w_clickfn = my_numbox_newclick; - my_numbox_widgetbehavior.w_propertiesfn = my_numbox_properties;; - my_numbox_widgetbehavior.w_savefn = my_numbox_save; class_setwidget(my_numbox_class, &my_numbox_widgetbehavior); class_sethelpsymbol(my_numbox_class, gensym("numbox2")); + class_setsavefn(my_numbox_class, my_numbox_save); + class_setpropertiesfn(my_numbox_class, my_numbox_properties); } diff --git a/pd/src/g_readwrite.c b/pd/src/g_readwrite.c index ddf11670..edcd5e24 100644 --- a/pd/src/g_readwrite.c +++ b/pd/src/g_readwrite.c @@ -571,7 +571,8 @@ static void canvas_saveto(t_canvas *x, t_binbuf *b) (t_int)(x->gl_screeny1), (t_int)(x->gl_screenx2 - x->gl_screenx1), (t_int)(x->gl_screeny2 - x->gl_screeny1), - x->gl_name, x->gl_mapped); + (*x->gl_name->s_name ? x->gl_name: gensym("(subpatch)")), + x->gl_mapped); } /* root or abstraction */ else binbuf_addv(b, "ssiiiii;", gensym("#N"), gensym("canvas"), diff --git a/pd/src/g_rtext.c b/pd/src/g_rtext.c index ee894b7e..aeeb5dfd 100644 --- a/pd/src/g_rtext.c +++ b/pd/src/g_rtext.c @@ -229,7 +229,13 @@ static void rtext_senditup(t_rtext *x, int action, int *widthp, int *heightp, sys_vgui(".x%x.c select from %s %d\n", canvas, x->x_tag, x->x_selstart); sys_vgui(".x%x.c select to %s %d\n", canvas, - x->x_tag, x->x_selend); + x->x_tag, x->x_selend +#if defined (MSW) || defined(MACOSX) + /* Why is linux selecting text differently from MSW and OSX??? + Just adjust it here... LATER revisit this one */ + -1 +#endif + ); sys_vgui(".x%x.c focus \"\"\n", canvas); } else @@ -385,18 +391,23 @@ void rtext_key(t_rtext *x, int keynum, t_symbol *keysym) { int n = keynum; if (n == '\r') n = '\n'; - if (n == '\b') + if (n == '\b') /* backspace */ { - if ((!x->x_selstart) && (x->x_selend == x->x_bufsize)) + /* LATER delete the box if all text is selected... + this causes reentrancy problems now. */ + /* if ((!x->x_selstart) && (x->x_selend == x->x_bufsize)) { - /* LATER delete the box... this causes reentrancy - problems now. */ - /* glist_delete(x->x_glist, &x->x_text->te_g); */ - return; - } - else if (x->x_selstart && (x->x_selstart == x->x_selend)) + .... + } */ + if (x->x_selstart && (x->x_selstart == x->x_selend)) x->x_selstart--; } + else if (n == 127) /* delete */ + { + if (x->x_selend < x->x_bufsize && (x->x_selstart == x->x_selend)) + x->x_selend++; + } + ndel = x->x_selend - x->x_selstart; for (i = x->x_selend; i < x->x_bufsize; i++) x->x_buf[i- ndel] = x->x_buf[i]; diff --git a/pd/src/g_scalar.c b/pd/src/g_scalar.c index d24564e4..538ca246 100644 --- a/pd/src/g_scalar.c +++ b/pd/src/g_scalar.c @@ -348,8 +348,6 @@ static t_widgetbehavior scalar_widgetbehavior = scalar_delete, scalar_vis, scalar_click, - scalar_save, - scalar_properties, }; static void scalar_free(t_scalar *x) @@ -377,4 +375,6 @@ void g_scalar_setup(void) scalar_class = class_new(gensym("scalar"), 0, (t_method)scalar_free, 0, CLASS_GOBJ, 0); class_setwidget(scalar_class, &scalar_widgetbehavior); + class_setsavefn(scalar_class, scalar_save); + class_setpropertiesfn(scalar_class, scalar_properties); } diff --git a/pd/src/g_template.c b/pd/src/g_template.c index 67c35413..1695079b 100644 --- a/pd/src/g_template.c +++ b/pd/src/g_template.c @@ -288,7 +288,6 @@ static t_scalar *template_conformscalar(t_template *tfrom, t_template *tto, /* possibly replace the scalar */ if (scfrom->sc_template == tfrom->t_sym) { - post("match"); /* see scalar_new() for comment about the gpointer. */ gpointer_init(&gp); x = (t_scalar *)getbytes(sizeof(t_scalar) + @@ -435,10 +434,10 @@ void template_conform(t_template *tfrom, t_template *tto) if (doit) { t_glist *gl; - post("conforming template '%s' to new structure", + /* post("conforming template '%s' to new structure", tfrom->t_sym->s_name); for (i = 0; i < nto; i++) - post("... %d", conformaction[i]); + post("... %d", conformaction[i]); */ for (gl = canvas_list; gl; gl = gl->gl_next) template_conformglist(tfrom, tto, gl, conformaction); } diff --git a/pd/src/g_text.c b/pd/src/g_text.c index 13619493..7fc2bbdf 100644 --- a/pd/src/g_text.c +++ b/pd/src/g_text.c @@ -457,14 +457,19 @@ static t_symbol *gatom_realizedollar(t_gatom *x, t_symbol *s) static void gatom_set(t_gatom *x, t_symbol *s, int argc, t_atom *argv) { + t_atom oldatom = x->a_atom; + int update = 0; if (!argc) return; if (x->a_atom.a_type == A_FLOAT) - x->a_atom.a_w.w_float = atom_getfloat(argv); + x->a_atom.a_w.w_float = atom_getfloat(argv), + update = (x->a_atom.a_w.w_float != oldatom.a_w.w_float); else if (x->a_atom.a_type == A_SYMBOL) - x->a_atom.a_w.w_symbol = atom_getsymbol(argv); + x->a_atom.a_w.w_symbol = atom_getsymbol(argv), + update = (x->a_atom.a_w.w_symbol != oldatom.a_w.w_symbol); binbuf_clear(x->a_text.te_binbuf); binbuf_add(x->a_text.te_binbuf, 1, &x->a_atom); - glist_retext(x->a_glist, &x->a_text); + if (update) + glist_retext(x->a_glist, &x->a_text); x->a_buf[0] = 0; } @@ -1010,7 +1015,7 @@ static int text_click(t_gobj *z, struct _glist *glist, else return (0); } -static void text_save(t_gobj *z, t_binbuf *b) +void text_save(t_gobj *z, t_binbuf *b) { t_text *x = (t_text *)z; if (x->te_type == T_OBJECT) @@ -1076,8 +1081,6 @@ t_widgetbehavior text_widgetbehavior = text_delete, text_vis, text_click, - text_save, - 0, }; static t_widgetbehavior gatom_widgetbehavior = @@ -1089,8 +1092,6 @@ static t_widgetbehavior gatom_widgetbehavior = text_delete, gatom_vis, text_click, - text_save, - gatom_properties, }; /* -------------------- the "text" class ------------ */ @@ -1305,6 +1306,7 @@ void g_text_setup(void) class_addmethod(gatom_class, (t_method)gatom_param, gensym("param"), A_GIMME, 0); class_setwidget(gatom_class, &gatom_widgetbehavior); + class_setpropertiesfn(gatom_class, gatom_properties); } diff --git a/pd/src/g_toggle.c b/pd/src/g_toggle.c index 9f5f5c3c..c6077b89 100644 --- a/pd/src/g_toggle.c +++ b/pd/src/g_toggle.c @@ -202,20 +202,18 @@ static void toggle_getrect(t_gobj *z, t_glist *glist, int *xp1, int *yp1, int *x static void toggle_save(t_gobj *z, t_binbuf *b) { t_toggle *x = (t_toggle *)z; - int bflcol[3], *ip1, *ip2; + int bflcol[3]; t_symbol *srl[3]; iemgui_save(&x->x_gui, srl, bflcol); - ip1 = (int *)(&x->x_gui.x_isa); - ip2 = (int *)(&x->x_gui.x_fsf); binbuf_addv(b, "ssiisiisssiiiiiiiff", gensym("#X"),gensym("obj"), (t_int)x->x_gui.x_obj.te_xpix, (t_int)x->x_gui.x_obj.te_ypix, gensym("tgl"), x->x_gui.x_w, - (*ip1)&IEM_INIT_ARGS_ALL, + iem_symargstoint(&x->x_gui.x_isa), srl[0], srl[1], srl[2], x->x_gui.x_ldx, x->x_gui.x_ldy, - (*ip2)&IEM_FSTYLE_FLAGS_ALL, x->x_gui.x_fontsize, + iem_fstyletoint(&x->x_gui.x_fsf), x->x_gui.x_fontsize, bflcol[0], bflcol[1], bflcol[2], x->x_on, x->x_nonzero); binbuf_addv(b, ";"); } @@ -367,12 +365,12 @@ static void *toggle_new(t_symbol *s, int argc, t_atom *argv) t_symbol *srl[3]; int a=IEM_GUI_DEFAULTSIZE, f=0; int ldx=0, ldy=-6; - int fs=8, iinit=0, ifstyle=0; + int fs=8; float on=0.0, nonzero=1.0; - t_iem_init_symargs *init=(t_iem_init_symargs *)(&iinit); - t_iem_fstyle_flags *fstyle=(t_iem_fstyle_flags *)(&ifstyle); char str[144]; + iem_inttosymargs(&x->x_gui.x_isa, 0); + iem_inttofstyle(&x->x_gui.x_fsf, 0); srl[0] = gensym("empty"); srl[1] = gensym("empty"); srl[2] = gensym("empty"); @@ -387,7 +385,7 @@ static void *toggle_new(t_symbol *s, int argc, t_atom *argv) &&IS_A_FLOAT(argv,10)&&IS_A_FLOAT(argv,11)&&IS_A_FLOAT(argv,12)) { a = (int)atom_getintarg(0, argc, argv); - iinit = (int)atom_getintarg(1, argc, argv); + iem_inttosymargs(&x->x_gui.x_isa, atom_getintarg(1, argc, argv)); if(IS_A_SYMBOL(argv,2)) srl[0] = atom_getsymbolarg(2, argc, argv); else if(IS_A_FLOAT(argv,2)) @@ -411,7 +409,7 @@ static void *toggle_new(t_symbol *s, int argc, t_atom *argv) } ldx = (int)atom_getintarg(5, argc, argv); ldy = (int)atom_getintarg(6, argc, argv); - ifstyle = (int)atom_getintarg(7, argc, argv); + iem_inttofstyle(&x->x_gui.x_fsf, atom_getintarg(7, argc, argv)); fs = (int)atom_getintarg(8, argc, argv); bflcol[0] = (int)atom_getintarg(9, argc, argv); bflcol[1] = (int)atom_getintarg(10, argc, argv); @@ -421,21 +419,17 @@ static void *toggle_new(t_symbol *s, int argc, t_atom *argv) if((argc == 14)&&IS_A_FLOAT(argv,13)) nonzero = (float)atom_getfloatarg(13, argc, argv); x->x_gui.x_draw = (t_iemfunptr)toggle_draw; - iinit &= IEM_INIT_ARGS_ALL; - ifstyle &= IEM_FSTYLE_FLAGS_ALL; - fstyle->x_snd_able = 1; - fstyle->x_rcv_able = 1; + x->x_gui.x_fsf.x_snd_able = 1; + x->x_gui.x_fsf.x_rcv_able = 1; x->x_gui.x_glist = (t_glist *)canvas_getcurrent(); - x->x_gui.x_isa = *init; - if(!strcmp(srl[0]->s_name, "empty")) fstyle->x_snd_able = 0; - if(!strcmp(srl[1]->s_name, "empty")) fstyle->x_rcv_able = 0; + if(!strcmp(srl[0]->s_name, "empty")) x->x_gui.x_fsf.x_snd_able = 0; + if(!strcmp(srl[1]->s_name, "empty")) x->x_gui.x_fsf.x_rcv_able = 0; x->x_gui.x_unique_num = 0; - if(fstyle->x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica"); - else if(fstyle->x_font_style == 2) strcpy(x->x_gui.x_font, "times"); - else { fstyle->x_font_style = 0; + if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica"); + else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times"); + else { x->x_gui.x_fsf.x_font_style = 0; strcpy(x->x_gui.x_font, "courier"); } - x->x_gui.x_fsf = *fstyle; x->x_nonzero = (nonzero!=0.0)?nonzero:1.0; if(x->x_gui.x_isa.x_loadinit) x->x_on = (on!=0.0)?nonzero:0.0; @@ -498,8 +492,8 @@ void g_toggle_setup(void) toggle_widgetbehavior.w_deletefn = iemgui_delete; toggle_widgetbehavior.w_visfn = iemgui_vis; toggle_widgetbehavior.w_clickfn = toggle_newclick; - toggle_widgetbehavior.w_propertiesfn = toggle_properties; - toggle_widgetbehavior.w_savefn = toggle_save; class_setwidget(toggle_class, &toggle_widgetbehavior); class_sethelpsymbol(toggle_class, gensym("toggle")); + class_setsavefn(toggle_class, toggle_save); + class_setpropertiesfn(toggle_class, toggle_properties); } diff --git a/pd/src/g_vdial.c b/pd/src/g_vdial.c index 6424944a..be3956b5 100644 --- a/pd/src/g_vdial.c +++ b/pd/src/g_vdial.c @@ -234,22 +234,20 @@ static void vradio_getrect(t_gobj *z, t_glist *glist, int *xp1, int *yp1, int *x static void vradio_save(t_gobj *z, t_binbuf *b) { t_vradio *x = (t_vradio *)z; - int bflcol[3], *ip1, *ip2; + int bflcol[3]; t_symbol *srl[3]; iemgui_save(&x->x_gui, srl, bflcol); - ip1 = (int *)(&x->x_gui.x_isa); - ip2 = (int *)(&x->x_gui.x_fsf); binbuf_addv(b, "ssiisiiiisssiiiiiiii", gensym("#X"),gensym("obj"), (t_int)x->x_gui.x_obj.te_xpix, (t_int)x->x_gui.x_obj.te_ypix, (pd_class(&x->x_gui.x_obj.ob_pd) == vradio_old_class ? gensym("vdl") : gensym("vradio")), x->x_gui.x_w, - x->x_change, (*ip1)&IEM_INIT_ARGS_ALL, x->x_number, + x->x_change, iem_symargstoint(&x->x_gui.x_isa), x->x_number, srl[0], srl[1], srl[2], x->x_gui.x_ldx, x->x_gui.x_ldy, - (*ip2)&IEM_FSTYLE_FLAGS_ALL, x->x_gui.x_fontsize, + iem_fstyletoint(&x->x_gui.x_fsf), x->x_gui.x_fontsize, bflcol[0], bflcol[1], bflcol[2], x->x_on); binbuf_addv(b, ";"); } @@ -547,10 +545,8 @@ static void *vradio_donew(t_symbol *s, int argc, t_atom *argv, int old) t_symbol *srl[3]; int a=IEM_GUI_DEFAULTSIZE, on=0, f=0; int ldx=0, ldy=-6, chg=1, num=8; - int fs=8, iinit=0, ifstyle=0; + int fs=8; int ftbreak=IEM_BNG_DEFAULTBREAKFLASHTIME, fthold=IEM_BNG_DEFAULTHOLDFLASHTIME; - t_iem_init_symargs *init=(t_iem_init_symargs *)(&iinit); - t_iem_fstyle_flags *fstyle=(t_iem_fstyle_flags *)(&ifstyle); char str[144]; /* post("new %s %d", s->s_name, old); */ @@ -569,7 +565,7 @@ static void *vradio_donew(t_symbol *s, int argc, t_atom *argv, int old) { a = (int)atom_getintarg(0, argc, argv); chg = (int)atom_getintarg(1, argc, argv); - iinit = (int)atom_getintarg(2, argc, argv); + iem_inttosymargs(&x->x_gui.x_isa, atom_getintarg(2, argc, argv)); num = (int)atom_getintarg(3, argc, argv); if(IS_A_SYMBOL(argv,4)) srl[0] = atom_getsymbolarg(4, argc, argv); @@ -594,7 +590,7 @@ static void *vradio_donew(t_symbol *s, int argc, t_atom *argv, int old) } ldx = (int)atom_getintarg(7, argc, argv); ldy = (int)atom_getintarg(8, argc, argv); - ifstyle = (int)atom_getintarg(9, argc, argv); + iem_inttofstyle(&x->x_gui.x_fsf, atom_getintarg(9, argc, argv)); fs = (int)atom_getintarg(10, argc, argv); bflcol[0] = (int)atom_getintarg(11, argc, argv); bflcol[1] = (int)atom_getintarg(12, argc, argv); @@ -602,19 +598,15 @@ static void *vradio_donew(t_symbol *s, int argc, t_atom *argv, int old) on = (int)atom_getintarg(14, argc, argv); } x->x_gui.x_draw = (t_iemfunptr)vradio_draw; - iinit &= IEM_INIT_ARGS_ALL; - ifstyle &= IEM_FSTYLE_FLAGS_ALL; - fstyle->x_snd_able = 1; - fstyle->x_rcv_able = 1; + x->x_gui.x_fsf.x_snd_able = 1; + x->x_gui.x_fsf.x_rcv_able = 1; x->x_gui.x_glist = (t_glist *)canvas_getcurrent(); - x->x_gui.x_isa = *init; - if(!strcmp(srl[0]->s_name, "empty")) fstyle->x_snd_able = 0; - if(!strcmp(srl[1]->s_name, "empty")) fstyle->x_rcv_able = 0; - if(fstyle->x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica"); - else if(fstyle->x_font_style == 2) strcpy(x->x_gui.x_font, "times"); - else { fstyle->x_font_style = 0; + if(!strcmp(srl[0]->s_name, "empty")) x->x_gui.x_fsf.x_snd_able = 0; + if(!strcmp(srl[1]->s_name, "empty")) x->x_gui.x_fsf.x_rcv_able = 0; + if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica"); + else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times"); + else { x->x_gui.x_fsf.x_font_style = 0; strcpy(x->x_gui.x_font, "courier"); } - x->x_gui.x_fsf = *fstyle; x->x_gui.x_unique_num = 0; if(num < 1) num = 1; @@ -713,10 +705,10 @@ void g_vradio_setup(void) vradio_widgetbehavior.w_deletefn = iemgui_delete; vradio_widgetbehavior.w_visfn = iemgui_vis; vradio_widgetbehavior.w_clickfn = vradio_newclick; - vradio_widgetbehavior.w_propertiesfn = vradio_properties; - vradio_widgetbehavior.w_savefn = vradio_save; class_setwidget(vradio_class, &vradio_widgetbehavior); class_sethelpsymbol(vradio_class, gensym("vradio")); + class_setsavefn(vradio_class, vradio_save); + class_setpropertiesfn(vradio_class, vradio_properties); /* obsolete version (0.34-0.35) */ vradio_old_class = class_new(gensym("vdl"), (t_newmethod)vdial_new, diff --git a/pd/src/g_vslider.c b/pd/src/g_vslider.c index a7780135..25522af3 100644 --- a/pd/src/g_vslider.c +++ b/pd/src/g_vslider.c @@ -206,20 +206,18 @@ static void vslider_getrect(t_gobj *z, t_glist *glist, static void vslider_save(t_gobj *z, t_binbuf *b) { t_vslider *x = (t_vslider *)z; - int bflcol[3], *ip1, *ip2; + int bflcol[3]; t_symbol *srl[3]; iemgui_save(&x->x_gui, srl, bflcol); - ip1 = (int *)(&x->x_gui.x_isa); - ip2 = (int *)(&x->x_gui.x_fsf); binbuf_addv(b, "ssiisiiffiisssiiiiiiiii", gensym("#X"),gensym("obj"), (t_int)x->x_gui.x_obj.te_xpix, (t_int)x->x_gui.x_obj.te_ypix, gensym("vsl"), x->x_gui.x_w, x->x_gui.x_h, (float)x->x_min, (float)x->x_max, - x->x_lin0_log1, (*ip1)&IEM_INIT_ARGS_ALL, + x->x_lin0_log1, iem_symargstoint(&x->x_gui.x_isa), srl[0], srl[1], srl[2], x->x_gui.x_ldx, x->x_gui.x_ldy, - (*ip2)&IEM_FSTYLE_FLAGS_ALL, x->x_gui.x_fontsize, + iem_fstyletoint(&x->x_gui.x_fsf), x->x_gui.x_fontsize, bflcol[0], bflcol[1], bflcol[2], x->x_val, x->x_steady); binbuf_addv(b, ";"); @@ -510,12 +508,12 @@ static void *vslider_new(t_symbol *s, int argc, t_atom *argv) t_symbol *srl[3]; int w=IEM_GUI_DEFAULTSIZE, h=IEM_SL_DEFAULTSIZE; int lilo=0, f=0, ldx=0, ldy=-8; - int fs=8, iinit=0, ifstyle=0, v=0, steady=1; + int fs=8, v=0, steady=1; double min=0.0, max=(double)(IEM_SL_DEFAULTSIZE-1); - t_iem_init_symargs *init=(t_iem_init_symargs *)(&iinit); - t_iem_fstyle_flags *fstyle=(t_iem_fstyle_flags *)(&ifstyle); char str[144]; + iem_inttosymargs(&x->x_gui.x_isa, 0); + iem_inttofstyle(&x->x_gui.x_fsf, 0); srl[0] = gensym("empty"); srl[1] = gensym("empty"); srl[2] = gensym("empty"); @@ -536,7 +534,7 @@ static void *vslider_new(t_symbol *s, int argc, t_atom *argv) min = (double)atom_getfloatarg(2, argc, argv); max = (double)atom_getfloatarg(3, argc, argv); lilo = (int)atom_getintarg(4, argc, argv); - iinit = (int)atom_getintarg(5, argc, argv); + iem_inttosymargs(&x->x_gui.x_isa, atom_getintarg(5, argc, argv)); srl[0] = atom_getsymbolarg(6, argc, argv); srl[1] = atom_getsymbolarg(7, argc, argv); srl[2] = atom_getsymbolarg(8, argc, argv); @@ -563,7 +561,7 @@ static void *vslider_new(t_symbol *s, int argc, t_atom *argv) } ldx = (int)atom_getintarg(9, argc, argv); ldy = (int)atom_getintarg(10, argc, argv); - ifstyle = (int)atom_getintarg(11, argc, argv); + iem_inttofstyle(&x->x_gui.x_fsf, atom_getintarg(11, argc, argv)); fs = (int)atom_getintarg(12, argc, argv); bflcol[0] = (int)atom_getintarg(13, argc, argv); bflcol[1] = (int)atom_getintarg(14, argc, argv); @@ -573,12 +571,9 @@ static void *vslider_new(t_symbol *s, int argc, t_atom *argv) if((argc == 18)&&IS_A_FLOAT(argv,17)) steady = (int)atom_getintarg(17, argc, argv); x->x_gui.x_draw = (t_iemfunptr)vslider_draw; - iinit &= IEM_INIT_ARGS_ALL; - ifstyle &= IEM_FSTYLE_FLAGS_ALL; - fstyle->x_snd_able = 1; - fstyle->x_rcv_able = 1; + x->x_gui.x_fsf.x_snd_able = 1; + x->x_gui.x_fsf.x_rcv_able = 1; x->x_gui.x_glist = (t_glist *)canvas_getcurrent(); - x->x_gui.x_isa = *init; if(x->x_gui.x_isa.x_loadinit) x->x_val = v; else @@ -588,14 +583,13 @@ static void *vslider_new(t_symbol *s, int argc, t_atom *argv) x->x_lin0_log1 = lilo; if(steady != 0) steady = 1; x->x_steady = steady; - if(!strcmp(srl[0]->s_name, "empty")) fstyle->x_snd_able = 0; - if(!strcmp(srl[1]->s_name, "empty")) fstyle->x_rcv_able = 0; + if(!strcmp(srl[0]->s_name, "empty")) x->x_gui.x_fsf.x_snd_able = 0; + if(!strcmp(srl[1]->s_name, "empty")) x->x_gui.x_fsf.x_rcv_able = 0; x->x_gui.x_unique_num = 0; - if(fstyle->x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica"); - else if(fstyle->x_font_style == 2) strcpy(x->x_gui.x_font, "times"); - else { fstyle->x_font_style = 0; + if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica"); + else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times"); + else { x->x_gui.x_fsf.x_font_style = 0; strcpy(x->x_gui.x_font, "courier"); } - x->x_gui.x_fsf = *fstyle; iemgui_first_dollararg2sym(&x->x_gui, srl); if(x->x_gui.x_fsf.x_rcv_able) pd_bind(&x->x_gui.x_obj.ob_pd, srl[1]); x->x_gui.x_snd = srl[0]; @@ -658,8 +652,8 @@ void g_vslider_setup(void) vslider_widgetbehavior.w_deletefn = iemgui_delete; vslider_widgetbehavior.w_visfn = iemgui_vis; vslider_widgetbehavior.w_clickfn = vslider_newclick; - vslider_widgetbehavior.w_propertiesfn = vslider_properties;; - vslider_widgetbehavior.w_savefn = vslider_save; class_setwidget(vslider_class, &vslider_widgetbehavior); class_sethelpsymbol(vslider_class, gensym("vslider")); + class_setsavefn(vslider_class, vslider_save); + class_setpropertiesfn(vslider_class, vslider_properties); } diff --git a/pd/src/g_vumeter.c b/pd/src/g_vumeter.c index f538eda7..dcb95b04 100644 --- a/pd/src/g_vumeter.c +++ b/pd/src/g_vumeter.c @@ -397,19 +397,18 @@ static void vu_getrect(t_gobj *z, t_glist *glist, static void vu_save(t_gobj *z, t_binbuf *b) { t_vu *x = (t_vu *)z; - int bflcol[3], *ip1, *ip2; + int bflcol[3]; t_symbol *srl[3]; iemgui_save(&x->x_gui, srl, bflcol); - ip1 = (int *)(&x->x_gui.x_isa); - ip2 = (int *)(&x->x_gui.x_fsf); binbuf_addv(b, "ssiisiissiiiiiiii", gensym("#X"),gensym("obj"), (t_int)x->x_gui.x_obj.te_xpix, (t_int)x->x_gui.x_obj.te_ypix, gensym("vu"), x->x_gui.x_w, x->x_gui.x_h, srl[1], srl[2], x->x_gui.x_ldx, x->x_gui.x_ldy, - (*ip2)&IEM_FSTYLE_FLAGS_ALL, x->x_gui.x_fontsize, - bflcol[0], bflcol[2], x->x_scale, (*ip1)&IEM_INIT_ARGS_ALL); + iem_fstyletoint(&x->x_gui.x_fsf), x->x_gui.x_fontsize, + bflcol[0], bflcol[2], x->x_scale, + iem_symargstoint(&x->x_gui.x_isa)); binbuf_addv(b, ";"); } @@ -611,12 +610,11 @@ static void *vu_new(t_symbol *s, int argc, t_atom *argv) t_symbol *srl[3]; int w=IEM_GUI_DEFAULTSIZE, h=IEM_VU_STEPS*IEM_VU_DEFAULTSIZE; int ldx=-1, ldy=-8, f=0, fs=8, scale=1; - int iinit=0, ifstyle=0; int ftbreak=IEM_BNG_DEFAULTBREAKFLASHTIME, fthold=IEM_BNG_DEFAULTHOLDFLASHTIME; - t_iem_init_symargs *init=(t_iem_init_symargs *)(&iinit); - t_iem_fstyle_flags *fstyle=(t_iem_fstyle_flags *)(&ifstyle); char str[144]; + iem_inttosymargs(&x->x_gui.x_isa, 0); + iem_inttofstyle(&x->x_gui.x_fsf, 0); srl[0] = gensym("empty"); srl[1] = gensym("empty"); srl[2] = gensym("empty"); @@ -646,29 +644,25 @@ static void *vu_new(t_symbol *s, int argc, t_atom *argv) } ldx = (int)atom_getintarg(4, argc, argv); ldy = (int)atom_getintarg(5, argc, argv); - ifstyle = (int)atom_getintarg(6, argc, argv); + iem_inttofstyle(&x->x_gui.x_fsf, atom_getintarg(6, argc, argv)); fs = (int)atom_getintarg(7, argc, argv); bflcol[0] = (int)atom_getintarg(8, argc, argv); bflcol[2] = (int)atom_getintarg(9, argc, argv); scale = (int)atom_getintarg(10, argc, argv); } if((argc == 12)&&IS_A_FLOAT(argv,11)) - iinit = (int)atom_getintarg(11, argc, argv); + iem_inttosymargs(&x->x_gui.x_isa, atom_getintarg(11, argc, argv)); x->x_gui.x_draw = (t_iemfunptr)vu_draw; - iinit &= IEM_INIT_ARGS_ALL; - ifstyle &= IEM_FSTYLE_FLAGS_ALL; - fstyle->x_snd_able = 0; - fstyle->x_rcv_able = 1; + x->x_gui.x_fsf.x_snd_able = 0; + x->x_gui.x_fsf.x_rcv_able = 1; x->x_gui.x_glist = (t_glist *)canvas_getcurrent(); - x->x_gui.x_isa = *init; - if(!strcmp(srl[1]->s_name, "empty")) fstyle->x_rcv_able = 0; + if(!strcmp(srl[1]->s_name, "empty")) x->x_gui.x_fsf.x_rcv_able = 0; x->x_gui.x_unique_num = 0; - if(fstyle->x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica"); - else if(fstyle->x_font_style == 2) strcpy(x->x_gui.x_font, "times"); - else { fstyle->x_font_style = 0; + if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica"); + else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times"); + else { x->x_gui.x_fsf.x_font_style = 0; strcpy(x->x_gui.x_font, "courier"); } - x->x_gui.x_fsf = *fstyle; iemgui_first_dollararg2sym(&x->x_gui, srl); if(x->x_gui.x_fsf.x_rcv_able) pd_bind(&x->x_gui.x_obj.ob_pd, srl[1]); x->x_gui.x_snd = srl[0]; @@ -729,8 +723,8 @@ void g_vumeter_setup(void) vu_widgetbehavior.w_deletefn = iemgui_delete; vu_widgetbehavior.w_visfn = iemgui_vis; vu_widgetbehavior.w_clickfn = NULL; - vu_widgetbehavior.w_propertiesfn = vu_properties; - vu_widgetbehavior.w_savefn = vu_save; class_setwidget(vu_class,&vu_widgetbehavior); class_sethelpsymbol(vu_class, gensym("vu")); + class_setsavefn(vu_class, vu_save); + class_setpropertiesfn(vu_class, vu_properties); } diff --git a/pd/src/m_binbuf.c b/pd/src/m_binbuf.c index c40e5dff..60fb9974 100644 --- a/pd/src/m_binbuf.c +++ b/pd/src/m_binbuf.c @@ -851,6 +851,13 @@ static t_binbuf *binbuf_convert(t_binbuf *oldb, int maxtopd) } if (!strcmp(first, "#P")) { + /* drop initial "hidden" flag */ + if (!strcmp(second, "hidden")) + { + nextmess++; + natom--; + second = (nextmess+1)->a_w.w_symbol->s_name; + } if (natom >= 7 && !strcmp(second, "newobj") && (ISSYMBOL(&nextmess[6], "patcher") || ISSYMBOL(&nextmess[6], "p"))) @@ -919,6 +926,9 @@ static t_binbuf *binbuf_convert(t_binbuf *oldb, int maxtopd) } else if (!strcmp(second, "slider")) { + float inc = atom_getfloatarg(7, natom, nextmess); + if (inc <= 0) + inc = 1; binbuf_addv(newb, "ssffsffffffsssfffffffff;", gensym("#X"), gensym("obj"), atom_getfloatarg(2, natom, nextmess), @@ -926,10 +936,9 @@ static t_binbuf *binbuf_convert(t_binbuf *oldb, int maxtopd) gensym("vsl"), atom_getfloatarg(4, natom, nextmess), atom_getfloatarg(5, natom, nextmess), - atom_getfloatarg(7, natom, nextmess), - atom_getfloatarg(7, natom, nextmess) - + (atom_getfloatarg(5, natom, nextmess) - 1) - * atom_getfloatarg(6, natom, nextmess), + atom_getfloatarg(6, natom, nextmess), + atom_getfloatarg(6, natom, nextmess) + + (atom_getfloatarg(5, natom, nextmess) - 1) * inc, 0., 0., gensym("empty"), gensym("empty"), gensym("empty"), 0., -8., 0., 8., -262144., -1., -1., 0., 1.); @@ -962,6 +971,15 @@ static t_binbuf *binbuf_convert(t_binbuf *oldb, int maxtopd) gensym((natom > 5 ? "outlet~" : "outlet"))); nobj++; } + else if (!strcmp(second, "user")) + { + binbuf_addv(newb, "ssffs;", + gensym("#X"), gensym("obj"), + atom_getfloatarg(3, natom, nextmess), + atom_getfloatarg(4, natom, nextmess), + atom_getsymbolarg(2, natom, nextmess)); + nobj++; + } else if (!strcmp(second, "connect")|| !strcmp(second, "fasten")) { diff --git a/pd/src/m_class.c b/pd/src/m_class.c index b13db89d..15610b23 100644 --- a/pd/src/m_class.c +++ b/pd/src/m_class.c @@ -86,6 +86,7 @@ static void pd_defaultsymbol(t_pd *x, t_symbol *s) } void obj_list(t_object *x, t_symbol *s, int argc, t_atom *argv); +static void class_nosavefn(t_gobj *z, t_binbuf *b); /* handle "list" messages to Pds without explicit list methods defined. */ static void pd_defaultlist(t_pd *x, t_symbol *s, int argc, t_atom *argv) @@ -141,6 +142,7 @@ static void pd_defaultlist(t_pd *x, t_symbol *s, int argc, t_atom *argv) how this is handled. */ extern t_widgetbehavior text_widgetbehavior; +extern void text_save(t_gobj *z, t_binbuf *b); t_class *class_new(t_symbol *s, t_newmethod newmethod, t_method freemethod, size_t size, int flags, t_atomtype type1, ...) @@ -205,6 +207,7 @@ t_class *class_new(t_symbol *s, t_newmethod newmethod, t_method freemethod, c->c_drawcommand = 0; c->c_floatsignalin = 0; c->c_externdir = class_extern_dir; + c->c_savefn = (typeflag == CLASS_PATCHABLE ? text_save : class_nosavefn); #if 0 post("class: %s", c->c_name->s_name); #endif @@ -417,6 +420,30 @@ char *class_gethelpdir(t_class *c) return (c->c_externdir->s_name); } +static void class_nosavefn(t_gobj *z, t_binbuf *b) +{ + bug("save function called but not defined"); +} + +void class_setsavefn(t_class *c, t_savefn f) +{ + c->c_savefn = f; +} + +t_savefn class_getsavefn(t_class *c) +{ + return (c->c_savefn); +} + +void class_setpropertiesfn(t_class *c, t_propertiesfn f) +{ + c->c_propertiesfn = f; +} + +t_propertiesfn class_getpropertiesfn(t_class *c) +{ + return (c->c_propertiesfn); +} /* ---------------- the symbol table ------------------------ */ diff --git a/pd/src/m_glob.c b/pd/src/m_glob.c index eb240068..ba460aea 100644 --- a/pd/src/m_glob.c +++ b/pd/src/m_glob.c @@ -5,7 +5,7 @@ #include "m_pd.h" #include "m_imp.h" -static t_class *pdclass; +t_class *glob_pdobject; static t_class *maxclass; /* These "glob" routines, which implement messages to Pd, are from all @@ -18,6 +18,13 @@ void glob_meters(void *dummy, t_floatarg f); void glob_key(void *dummy, t_symbol *s, int ac, t_atom *av); void glob_audiostatus(void *dummy); void glob_finderror(t_pd *dummy); +void glob_audio_properties(t_pd *dummy, t_floatarg flongform); +void glob_audio_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv); +void glob_audio_setapi(t_pd *dummy, t_floatarg f); +void glob_midi_properties(t_pd *dummy, t_floatarg flongform); +void glob_midi_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv); +void glob_start_path_dialog(t_pd *dummy, t_floatarg flongform); +void glob_path_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv); void glob_ping(t_pd *dummy); void alsa_resync( void); @@ -30,7 +37,7 @@ void glob_audio(void *dummy, t_floatarg adc, t_floatarg dac); /* a method you add for debugging printout */ void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv); -#if 1 +#if 0 void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv) { *(int *)1 = 3; @@ -58,27 +65,41 @@ void glob_init(void) class_addanything(maxclass, max_default); pd_bind(&maxclass, gensym("max")); - pdclass = class_new(gensym("pd"), 0, 0, sizeof(t_pd), + glob_pdobject = class_new(gensym("pd"), 0, 0, sizeof(t_pd), CLASS_DEFAULT, A_NULL); - class_addmethod(pdclass, (t_method)glob_initfromgui, gensym("init"), + class_addmethod(glob_pdobject, (t_method)glob_initfromgui, gensym("init"), A_GIMME, 0); - class_addmethod(pdclass, (t_method)glob_setfilename, gensym("filename"), + class_addmethod(glob_pdobject, (t_method)glob_setfilename, gensym("filename"), A_SYMBOL, A_SYMBOL, 0); - class_addmethod(pdclass, (t_method)glob_evalfile, gensym("open"), + class_addmethod(glob_pdobject, (t_method)glob_evalfile, gensym("open"), A_SYMBOL, A_SYMBOL, 0); - class_addmethod(pdclass, (t_method)glob_quit, gensym("quit"), 0); - class_addmethod(pdclass, (t_method)glob_foo, gensym("foo"), A_GIMME, 0); - class_addmethod(pdclass, (t_method)glob_dsp, gensym("dsp"), A_GIMME, 0); - class_addmethod(pdclass, (t_method)glob_meters, gensym("meters"), + class_addmethod(glob_pdobject, (t_method)glob_quit, gensym("quit"), 0); + class_addmethod(glob_pdobject, (t_method)glob_foo, gensym("foo"), A_GIMME, 0); + class_addmethod(glob_pdobject, (t_method)glob_dsp, gensym("dsp"), A_GIMME, 0); + class_addmethod(glob_pdobject, (t_method)glob_meters, gensym("meters"), A_FLOAT, 0); - class_addmethod(pdclass, (t_method)glob_key, gensym("key"), A_GIMME, 0); - class_addmethod(pdclass, (t_method)glob_audiostatus, + class_addmethod(glob_pdobject, (t_method)glob_key, gensym("key"), A_GIMME, 0); + class_addmethod(glob_pdobject, (t_method)glob_audiostatus, gensym("audiostatus"), 0); - class_addmethod(pdclass, (t_method)glob_finderror, + class_addmethod(glob_pdobject, (t_method)glob_finderror, gensym("finderror"), 0); + class_addmethod(glob_pdobject, (t_method)glob_audio_properties, + gensym("audio-properties"), A_DEFFLOAT, 0); + class_addmethod(glob_pdobject, (t_method)glob_audio_dialog, + gensym("audio-dialog"), A_GIMME, 0); + class_addmethod(glob_pdobject, (t_method)glob_audio_setapi, + gensym("audio-setapi"), A_FLOAT, 0); + class_addmethod(glob_pdobject, (t_method)glob_midi_properties, + gensym("midi-properties"), A_DEFFLOAT, 0); + class_addmethod(glob_pdobject, (t_method)glob_midi_dialog, + gensym("midi-dialog"), A_GIMME, 0); + class_addmethod(glob_pdobject, (t_method)glob_start_path_dialog, + gensym("start-path-dialog"), A_DEFFLOAT, 0); + class_addmethod(glob_pdobject, (t_method)glob_path_dialog, + gensym("path-dialog"), A_GIMME, 0); #ifdef UNIX - class_addmethod(pdclass, (t_method)glob_ping, gensym("ping"), 0); + class_addmethod(glob_pdobject, (t_method)glob_ping, gensym("ping"), 0); #endif - class_addanything(pdclass, max_default); - pd_bind(&pdclass, gensym("pd")); + class_addanything(glob_pdobject, max_default); + pd_bind(&glob_pdobject, gensym("pd")); } diff --git a/pd/src/m_imp.h b/pd/src/m_imp.h index b95f5d0e..f6724f9c 100644 --- a/pd/src/m_imp.h +++ b/pd/src/m_imp.h @@ -44,6 +44,8 @@ struct _class t_anymethod c_anymethod; struct _widgetbehavior *c_wb; /* "gobjs" only */ struct _parentwidgetbehavior *c_pwb;/* widget behavior in parent */ + t_savefn c_savefn; /* function to call when saving */ + t_propertiesfn c_propertiesfn; /* function to start prop dialog */ int c_floatsignalin; /* onset to float for signal input */ char c_gobj; /* true if is a gobj */ char c_patchable; /* true if we have a t_object header */ diff --git a/pd/src/m_pd.c b/pd/src/m_pd.c index 8192c7e4..7ae53082 100644 --- a/pd/src/m_pd.c +++ b/pd/src/m_pd.c @@ -39,6 +39,13 @@ void pd_free(t_pd *x) if (c->c_size) t_freebytes(x, c->c_size); } +void gobj_save(t_gobj *x, t_binbuf *b) +{ + t_class *c = x->g_pd; + if (c->c_savefn) + (c->c_savefn)(x, b); +} + /* deal with several objects bound to the same symbol. If more than one, we actually bind a collection object to the symbol, which forwards messages sent to the symbol. */ diff --git a/pd/src/m_pd.h b/pd/src/m_pd.h index b5f7f037..fd8d61bf 100644 --- a/pd/src/m_pd.h +++ b/pd/src/m_pd.h @@ -38,7 +38,7 @@ extern "C" { /* and depending on the compiler, hidden data structures are declared differently: */ -#if defined( __GNUC__) || defined( __BORLANDC__ ) +#if defined( __GNUC__) || defined( __BORLANDC__ ) || defined( __MWERKS__ ) #define EXTERN_STRUCT struct #else #define EXTERN_STRUCT extern struct @@ -419,6 +419,15 @@ EXTERN void class_domainsignalin(t_class *c, int onset); #define CLASS_MAINSIGNALIN(c, type, field) \ class_domainsignalin(c, (char *)(&((type *)0)->field) - (char *)0) + /* prototype for functions to save Pd's to a binbuf */ +typedef void (*t_savefn)(t_gobj *x, t_binbuf *b); +EXTERN void class_setsavefn(t_class *c, t_savefn f); +EXTERN t_savefn class_getsavefn(t_class *c); + /* prototype for functions to open properties dialogs */ +typedef void (*t_propertiesfn)(t_gobj *x, struct _glist *glist); +EXTERN void class_setpropertiesfn(t_class *c, t_propertiesfn f); +EXTERN t_propertiesfn class_getpropertiesfn(t_class *c); + #ifndef PD_CLASS_DEF #define class_addbang(x, y) class_addbang((x), (t_method)(y)) #define class_addpointer(x, y) class_addpointer((x), (t_method)(y)) @@ -457,6 +466,15 @@ EXTERN int open_via_path(const char *name, const char *ext, const char *dir, EXTERN int sched_geteventno(void); EXTERN double sys_getrealtime(void); + +/* ------------ threading ------------------- */ +/* T.Grill - see m_sched.c */ + +EXTERN void sys_lock(void); +EXTERN void sys_unlock(void); +EXTERN int sys_trylock(void); + + /* --------------- signals ----------------------------------- */ typedef float t_sample; @@ -577,9 +595,12 @@ EXTERN int value_setfloat(t_symbol *s, t_float f); EXTERN void sys_vgui(char *fmt, ...); EXTERN void sys_gui(char *s); + /* dialog window creation and destruction */ EXTERN void gfxstub_new(t_pd *owner, void *key, const char *cmd); EXTERN void gfxstub_deleteforkey(void *key); +extern t_class *glob_pdobject; /* object to send "pd" messages */ + /*------------- Max 0.26 compatibility --------------------*/ /* the following reflects the new way classes are laid out, with the class diff --git a/pd/src/m_sched.c b/pd/src/m_sched.c index b4a5dc3b..4020be06 100644 --- a/pd/src/m_sched.c +++ b/pd/src/m_sched.c @@ -12,10 +12,15 @@ rates we expect to see: 32000, 44100, 48000, 88200, 96000. */ #define TIMEUNITPERSEC (32.*441000.) + +/* T.Grill - enable PD global thread locking - sys_lock, sys_unlock, sys_trylock functions */ +#define THREAD_LOCKING +#include "pthread.h" + + static int sys_quit; static double sys_time; static double sys_time_per_msec = TIMEUNITPERSEC / 1000.; -static double sys_time_per_dsp_tick; int sys_schedblocksize = DEFDACBLKSIZE; int sys_usecsincelastsleep(void); @@ -128,7 +133,7 @@ static int sys_bin[] = {0, 2, 5, 10, 20, 30, 50, 100, 1000}; #define NHIST 10 static int sys_histogram[NHIST][NBIN]; static double sys_histtime; -static int sched_diddsp, sched_didmidi, sched_didpoll, sched_didnothing; +static int sched_diddsp, sched_didpoll, sched_didnothing; static void sys_clearhist( void) { @@ -136,7 +141,7 @@ static void sys_clearhist( void) for (i = 0; i < NHIST; i++) for (j = 0; j < NBIN; j++) sys_histogram[i][j] = 0; sys_histtime = sys_getrealtime(); - sched_diddsp = sched_didmidi = sched_didpoll = sched_didnothing = 0; + sched_diddsp = sched_didpoll = sched_didnothing = 0; } void sys_printhist( void) @@ -159,8 +164,8 @@ void sys_printhist( void) sys_histogram[i][7]); } } - post("dsp %d, midi %d, poll %d, nothing %d", - sched_diddsp, sched_didmidi, sched_didpoll, sched_didnothing); + post("dsp %d, pollgui %d, nothing %d", + sched_diddsp, sched_didpoll, sched_didnothing); } static int sys_histphase; @@ -238,7 +243,8 @@ void sys_log_error(int type) oss_resync[oss_resyncphase].r_error = type; oss_nresync++; if (++oss_resyncphase == NRESYNC) oss_resyncphase = 0; - if (type != ERR_NOTHING && !sched_diored) + if (type != ERR_NOTHING && !sched_diored && + (sched_diddsp >= sched_dioredtime)) { sys_vgui("pdtk_pd_dio 1\n"); sched_diored = 1; @@ -322,13 +328,42 @@ void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv) void dsp_tick(void); -static int m_nodacs = 0; +static int sched_usedacs = 1; +static double sched_referencerealtime, sched_referencelogicaltime; +static double sys_time_per_dsp_tick; + +void sched_set_using_dacs(int flag) +{ + sched_usedacs = flag; + if (!flag) + { + sched_referencerealtime = sys_getrealtime(); + sched_referencelogicaltime = clock_getlogicaltime(); + } + sys_time_per_dsp_tick = (TIMEUNITPERSEC) * + ((double)sys_schedblocksize) / sys_dacsr; +} - /* this must be called earlier than any patches are loaded */ -void m_schedsetsr( void) + /* take the scheduler forward one DSP tick, also handling clock timeouts */ +static void sched_tick(double next_sys_time) { - sys_time_per_dsp_tick = - (TIMEUNITPERSEC) * ((double)sys_schedblocksize) / sys_dacsr; + int countdown = 5000; + while (clock_setlist && clock_setlist->c_settime < next_sys_time) + { + t_clock *c = clock_setlist; + sys_time = c->c_settime; + clock_unset(clock_setlist); + outlet_setstacklim(); + (*c->c_fn)(c->c_owner); + if (!countdown--) + { + countdown = 5000; + sys_pollgui(); + } + } + sys_time = next_sys_time; + dsp_tick(); + sched_diddsp++; } /* @@ -339,26 +374,30 @@ lower priority than the rest. The time source is normally the audio I/O subsystem via the "sys_send_dacs()" call. This call returns true if samples were transferred; false means that -the audio I/O system is still bussy with previous transfers. -The sys_send_dacs call is OS dependent and is variously implemented in -s_linux.c, s_nt.c, and s_sgi.c. +the audio I/O system is still busy with previous transfers. */ void sys_pollmidiqueue( void); void sys_initmidiqueue( void); -int m_scheduler(int nodacs) +int m_scheduler( void) { - int lasttimeforward = SENDDACS_YES; int idlecount = 0; - double lastdactime = 0; sys_time_per_dsp_tick = (TIMEUNITPERSEC) * ((double)sys_schedblocksize) / sys_dacsr; + +#ifdef THREAD_LOCKING + /* T.Grill - lock mutex */ + sys_lock(); +#endif + sys_clearhist(); - m_nodacs = nodacs; if (sys_sleepgrain < 1000) - sys_sleepgrain = (sys_schedadvance >= 4000? - (sys_schedadvance >> 2) : 1000); + sys_sleepgrain = sys_schedadvance/4; + if (sys_sleepgrain < 100) + sys_sleepgrain = 100; + else if (sys_sleepgrain > 5000) + sys_sleepgrain = 5000; sys_initmidiqueue(); while (1) { @@ -366,23 +405,14 @@ int m_scheduler(int nodacs) int timeforward; sys_addhist(0); - if (m_nodacs) - { - double elapsed = sys_getrealtime() - lastdactime; - static double next = 0; - if (elapsed > next) - { - timeforward = SENDDACS_YES; - next += (double)sys_schedblocksize / sys_dacsr; - } - else timeforward = SENDDACS_NO; - } - else + waitfortick: + if (sched_usedacs) { timeforward = sys_send_dacs(); /* if dacs remain "idle" for 1 sec, they're hung up. */ - if (timeforward != 0) idlecount = 0; + if (timeforward != 0) + idlecount = 0; else { idlecount++; @@ -396,42 +426,26 @@ int m_scheduler(int nodacs) else if (sys_getrealtime() - idletime > 1.) { post("audio I/O stuck... closing audio\n"); - m_nodacs = 1; sys_close_audio(); - lastdactime = sys_getrealtime(); + sched_set_using_dacs(0); + goto waitfortick; } } } } + else + { + if (1000. * (sys_getrealtime() - sched_referencerealtime) + > clock_gettimesince(sched_referencelogicaltime)) + timeforward = SENDDACS_YES; + else timeforward = SENDDACS_NO; + } sys_setmiditimediff(0, 1e-6 * sys_schedadvance); - lasttimeforward = timeforward; sys_addhist(1); if (timeforward != SENDDACS_NO) - { - /* time has moved forward. Check MIDI and clocks */ - - double next_sys_time = sys_time + sys_time_per_dsp_tick; - int countdown = 5000; - while (clock_setlist && clock_setlist->c_settime < next_sys_time) - { - t_clock *c = clock_setlist; - sys_time = c->c_settime; - clock_unset(clock_setlist); - outlet_setstacklim(); - (*c->c_fn)(c->c_owner); - if (!countdown--) - { - countdown = 5000; - sys_pollgui(); - } - } - sys_time = next_sys_time; - if (sys_quit) break; - dsp_tick(); - if (timeforward != SENDDACS_SLEPT) - didsomething = 1; - sched_diddsp++; - } + sched_tick(sys_time + sys_time_per_dsp_tick); + if (timeforward == SENDDACS_YES) + didsomething = 1; sys_addhist(2); sys_pollmidiqueue(); @@ -445,15 +459,72 @@ int m_scheduler(int nodacs) /* test for idle; if so, do graphics updates. */ if (!didsomething) { - sched_pollformeters(); - sys_reportidle(); + sched_pollformeters(); + sys_reportidle(); + +#ifdef THREAD_LOCKING + /* T.Grill - enter idle phase -> unlock thread lock */ + sys_unlock(); +#endif if (timeforward != SENDDACS_SLEPT) - sys_microsleep(sys_sleepgrain); + sys_microsleep(sys_sleepgrain); +#ifdef THREAD_LOCKING + /* T.Grill - leave idle phase -> lock thread lock */ + sys_lock(); +#endif + sys_addhist(5); - sched_didnothing++; + sched_didnothing++; + } } + +#ifdef THREAD_LOCKING + /* T.Grill - done */ + sys_unlock(); +#endif + return (0); } +/* ------------ thread locking ------------------- */ +/* added by Thomas Grill */ + +#ifdef THREAD_LOCKING +static pthread_mutex_t sys_mutex = PTHREAD_MUTEX_INITIALIZER; + +void sys_lock(void) +{ + pthread_mutex_lock(&sys_mutex); +} + +void sys_unlock(void) +{ + pthread_mutex_unlock(&sys_mutex); +} + +int sys_trylock(void) +{ + return pthread_mutex_trylock(&sys_mutex); +} + +#else + +void sys_lock(void) {} +void sys_unlock(void) {} +int sys_trylock(void) {} + +#endif + + +/* ------------ soft quit ------------------- */ +/* added by Thomas Grill - + just set the quit flag for the scheduler loop + this is useful for applications using the PD shared library to signal the scheduler to terminate +*/ + +void sys_exit(void) +{ + sys_quit = 1; +} diff --git a/pd/src/makefile b/pd/src/makefile index 62e5f34b..8b7a7246 100644 --- a/pd/src/makefile +++ b/pd/src/makefile @@ -1,3 +1,131 @@ -all: - ./configure - make +# Makefile for PD on MSW + +all: pd gui ..\bin\pd.tk ..\bin\pdsend.exe ..\bin\pdreceive.exe + +VC = "C:\Program Files\Microsoft Visual Studio\VC98" +#VC="\Program Files\DevStudio\Vc" +INCLUDE = -I.\ -I..\Tcl\include -I$(VC)\include + +LDIR = $(VC)\lib + +LIB = /NODEFAULTLIB:libc /NODEFAULTLIB:oldnames /NODEFAULTLIB:kernel \ + /NODEFAULTLIB:uuid \ + $(LDIR)\libc.lib $(LDIR)\oldnames.lib $(LDIR)\kernel32.lib \ + $(LDIR)\wsock32.lib $(LDIR)\winmm.lib ..\bin\pthreadVC.lib + +GLIB = $(LIB) ..\bin\tcl83.lib ..\bin\tk83.lib +CFLAGS = /nologo /W3 /DMSW /DNT /DPD /DPD_INTERNAL /DWIN32 /DWINDOWS /Ox \ + -DPA_LITTLE_ENDIAN -DUSEAPI_MMIO -DUSEAPI_PORTAUDIO +LFLAGS = /nologo + +SYSSRC = s_audio_pa.c s_audio_mmio.c s_midi_pm.c + +SRC = g_canvas.c g_graph.c g_text.c g_rtext.c g_array.c g_template.c g_io.c \ + g_scalar.c g_traversal.c g_guiconnect.c g_readwrite.c g_editor.c \ + g_all_guis.c g_bang.c g_hdial.c g_hslider.c g_mycanvas.c g_numbox.c \ + g_toggle.c g_vdial.c g_vslider.c g_vumeter.c \ + m_pd.c m_class.c m_obj.c m_atom.c m_memory.c m_binbuf.c \ + m_conf.c m_glob.c m_sched.c \ + s_main.c s_inter.c s_file.c s_print.c \ + s_loader.c s_path.c s_entry.c s_audio.c s_midi.c \ + d_ugen.c d_ctl.c d_arithmetic.c d_osc.c d_filter.c d_dac.c d_misc.c \ + d_math.c d_fft.c d_mayer_fft.c d_fftroutine.c d_array.c d_global.c \ + d_delay.c d_resample.c \ + x_arithmetic.c x_connective.c x_interface.c x_midi.c x_misc.c \ + x_time.c x_acoustics.c x_net.c x_qlist.c x_gui.c d_soundfile.c \ + $(SYSSRC) + +PADIR = ..\portaudio +INCPA = -I$(PADIR) -I$(PADIR)\pa_common -I$(PADIR)\pablio -I..\lib\asio +SRCPA = $(PADIR)/pa_common/pa_lib.c $(PADIR)/pa_common/pa_trace.c \ + $(PADIR)/pablio/pablio_pd.c $(PADIR)/pablio/ringbuffer_pd.c +SRCASIO = $(PADIR)/pa_asio/pa_asio.cpp + +ASIOLIB = $(LDIR)\user32.lib $(LDIR)\gdi32.lib $(LDIR)\winspool.lib $(LDIR)\comdlg32.lib \ +$(LDIR)\advapi32.lib $(LDIR)\shell32.lib $(LDIR)\ole32.lib $(LDIR)\oleaut32.lib $(LDIR)\uuid.lib \ +$(LDIR)\odbc32.lib $(LDIR)\odbccp32.lib ..\lib\asio\asiolib.lib + + +PAOBJ = pa_lib.obj pa_trace.obj pablio_pd.obj ringbuffer_pd.obj pa_asio.obj + +PMDIR = ..\portmidi +INCPM = -I$(PMDIR)\pm_common -I$(PMDIR)\pm_win -I$(PMDIR)\porttime +SRCPM = \ + $(PMDIR)/pm_common/portmidi.c \ + $(PMDIR)/pm_common/pmutil.c \ + $(PMDIR)/pm_win/pmwin.c \ + $(PMDIR)/pm_win/pmwinmm.c \ + $(PMDIR)/porttime/porttime.c \ + $(PMDIR)/porttime/ptwinmm.c \ + +PMOBJ = portmidi.obj pmutil.obj pmwin.obj pmwinmm.obj porttime.obj ptwinmm.obj + +OBJC = $(SRC:.c=.obj) $(PAOBJ) $(PMOBJ) + +GSRC = t_main.c t_tkcmd.c + +GOBJ = $(GSRC:.c=.obj) +.PHONY: pd gui + +ALLCF = $(CFLAGS) $(INCLUDE) $(INCASIO) $(INCPA) $(INCPM) /D_WINDOWS /DPA_NO_DS + +.c.obj: + cl /c $(ALLCF) /Tc$*.c + +pd: ..\bin\pd.exe + +gui: ..\bin\pdtcl.dll + +..\bin\pd.exe: s_entry.obj ..\bin\pd.lib + link $(LFLAGS) /out:..\bin\pd.exe /INCREMENTAL:NO s_entry.obj \ + ..\bin\pd.lib $(LIB) $(ASIOLIB) + +..\bin\pd.dll ..\bin\pd.lib: $(OBJC) $(OBJASIO) + link $(LFLAGS) /dll /export:sys_main /out:..\bin\pd.dll $(OBJC) \ + $(OBJASIO) $(LIB) $(ASIOLIB) + +..\bin\pdtcl.dll: t_tkcmd.obj + link $(LFLAGS) /dll /export:Pdtcl_Init /out:..\bin\pdtcl.dll \ + t_tkcmd.obj $(GLIB) + +..\bin\pd.tk: u_main.tk; copy u_main.tk ..\bin\pd.tk + +..\bin\pdsend.exe: u_pdsend.obj + link $(LFLAGS) /out:..\bin\pdsend.exe /INCREMENTAL:NO u_pdsend.obj \ + $(LIB) + +..\bin\pdreceive.exe: u_pdreceive.obj + link $(LFLAGS) /out:..\bin\pdreceive.exe /INCREMENTAL:NO u_pdreceive.obj \ + $(LIB) + +# explicit rules to compile portaudio and portmidi sources: +pa_lib.obj: $(PADIR)\pa_common\pa_lib.c + cl /c $(ALLCF) $(PADIR)\pa_common\pa_lib.c +pa_trace.obj: $(PADIR)\pa_common\pa_trace.c + cl /c $(ALLCF) $(PADIR)\pa_common\pa_trace.c +pablio_pd.obj: $(PADIR)\pablio\pablio_pd.c + cl /c $(ALLCF) $(PADIR)\pablio\pablio_pd.c +ringbuffer_pd.obj: $(PADIR)\pablio\ringbuffer_pd.c + cl /c $(ALLCF) $(PADIR)\pablio\ringbuffer_pd.c + +pa_asio.obj: $(PADIR)\pa_asio\pa_asio.cpp + cl /c $(ALLCF) $(PADIR)\pa_asio\pa_asio.cpp + +portmidi.obj: $(PMDIR)\pm_common\portmidi.c + cl /c $(ALLCF) $(PMDIR)\pm_common\portmidi.c +pmutil.obj: $(PMDIR)\pm_common\pmutil.c + cl /c $(ALLCF) $(PMDIR)\pm_common\pmutil.c +pmwin.obj: $(PMDIR)\pm_win\pmwin.c + cl /c $(ALLCF) $(PMDIR)\pm_win\pmwin.c +pmwinmm.obj: $(PMDIR)\pm_win\pmwinmm.c + cl /c $(ALLCF) $(PMDIR)\pm_win\pmwinmm.c +porttime.obj: $(PMDIR)\porttime\porttime.c + cl /c $(ALLCF) $(PMDIR)\porttime\porttime.c +ptwinmm.obj: $(PMDIR)\porttime\ptwinmm.c + cl /c $(ALLCF) $(PMDIR)\porttime\ptwinmm.c + +# the following should also clean up "bin" but it doesn't because "bin" holds +# precious stuff from elsewhere. +clean: + del *.obj + diff --git a/pd/src/makefile.nt.bad b/pd/src/makefile.nt.bad deleted file mode 100644 index d45b72e0..00000000 --- a/pd/src/makefile.nt.bad +++ /dev/null @@ -1,92 +0,0 @@ -# Makefile for portaudio ASIO driver version of PD - -all: pd gui ..\bin\pd.tk - -VC = "C:\Program Files\Microsoft Visual Studio\VC98" -#VC="\Program Files\DevStudio\Vc" -INCLUDE = -I.\ -I..\Tcl\include -I$(VC)\include - -LDIR = $(VC)\lib - -LIB = /NODEFAULTLIB:libc /NODEFAULTLIB:oldnames /NODEFAULTLIB:kernel \ - /NODEFAULTLIB:uuid \ - $(LDIR)\libc.lib $(LDIR)\oldnames.lib $(LDIR)\kernel32.lib \ - $(LDIR)\wsock32.lib $(LDIR)\winmm.lib ..\bin\pthreadVC.lib - -GLIB = $(LIB) ..\lib\tcl83.lib ..\lib\tk83.lib -CFLAGS = /nologo /W3 /DNT /DPD /DPD_INTERNAL /DWIN32 /DWINDOWS /Ox -LFLAGS = /nologo - -SYSSRC = s_nt.c s_portaudio.c - -SRC = g_canvas.c g_graph.c g_text.c g_rtext.c g_array.c g_template.c g_io.c \ - g_scalar.c g_traversal.c g_guiconnect.c g_readwrite.c g_editor.c \ - g_all_guis.c g_bang.c g_hdial.c g_hslider.c g_mycanvas.c g_numbox.c \ - g_toggle.c g_vdial.c g_vslider.c g_vumeter.c \ - m_pd.c m_class.c m_obj.c m_atom.c m_memory.c m_binbuf.c \ - m_conf.c m_glob.c m_sched.c \ - s_main.c s_inter.c s_unix.c s_file.c s_print.c \ - s_loader.c s_path.c s_entry.c \ - d_ugen.c d_ctl.c d_arithmetic.c d_osc.c d_filter.c d_dac.c d_misc.c \ - d_math.c d_fft.c d_mayer_fft.c d_fftroutine.c d_array.c d_global.c \ - d_delay.c d_resample.c \ - x_arithmetic.c x_connective.c x_interface.c x_midi.c x_misc.c \ - x_time.c x_acoustics.c x_net.c x_qlist.c x_gui.c d_soundfile.c \ - $(SYSSRC) - -SRCPA = pa_lib.c pa_trace.c pablio_pd.c ringbuffer_pd.c -SRCASIO = pa_asio.cpp - -ASIOLIB = $(LDIR)\user32.lib $(LDIR)\gdi32.lib $(LDIR)\winspool.lib $(LDIR)\comdlg32.lib \ -$(LDIR)\advapi32.lib $(LDIR)\shell32.lib $(LDIR)\ole32.lib $(LDIR)\oleaut32.lib $(LDIR)\uuid.lib \ -$(LDIR)\odbc32.lib $(LDIR)\odbccp32.lib ..\lib\asio\asiolib.lib - - -PAOBJ = pa_lib.obj pa_trace.obj pablio_pd.obj ringbuffer_pd.obj pa_asio.obj -OBJC = $(SRC:.c=.obj) $(PAOBJ) - -GSRC = t_main.c t_tkcmd.c - -GOBJ = $(GSRC:.c=.obj) -.PHONY: pd gui - -ALLCF = $(CFLAGS) $(INCLUDE) $(INCASIO) $(INCPA) /D_WINDOWS - -.c.obj: - cl /c $(ALLCF) /Tc$*.c - -pd: ..\bin\pd.exe - -gui: ..\bin\pdtcl.dll - -..\bin\pd.exe: s_entry.obj ..\bin\pd.lib - link $(LFLAGS) /out:..\bin\pd.exe /INCREMENTAL:NO s_entry.obj \ - ..\bin\pd.lib $(LIB) $(ASIOLIB) - -..\bin\pd.dll ..\bin\pd.lib: $(OBJC) $(OBJASIO) - link $(LFLAGS) /dll /export:sys_main /out:..\bin\pd.dll $(OBJC) \ - $(OBJASIO) $(LIB) $(ASIOLIB) - -..\bin\pdtcl.dll: t_tkcmd.obj - link $(LFLAGS) /dll /export:Pdtcl_Init /out:..\bin\pdtcl.dll \ - t_tkcmd.obj $(GLIB) - -..\bin\pd.tk: u_main.tk; copy u_main.tk ..\bin\pd.tk - -# explicit rules to compile portaudio sources: -pa_lib.obj: pa_lib.c - cl /c $(ALLCF) pa_lib.c -pa_trace.obj: pa_trace.c - cl /c $(ALLCF) pa_trace.c -pablio_pd.obj: pablio_pd.c - cl /c $(ALLCF) pablio_pd.c -ringbuffer_pd.obj: ringbuffer_pd.c - cl /c $(ALLCF) ringbuffer_pd.c -pa_asio.obj: pa_asio.cpp - cl /c $(ALLCF) pa_asio.cpp - -# the following should also clean up "bin" but it doesn't because "bin" holds -# precious stuff from elsewhere. -clean: - del *.obj - diff --git a/pd/src/notes.txt b/pd/src/notes.txt index 0f95929d..6cd97820 100644 --- a/pd/src/notes.txt +++ b/pd/src/notes.txt @@ -1,15 +1,29 @@ -vline object -arrow keys in text objs for mac - ---------------- dolist -------------------- -vline~ help window -writesf help window, support 32 bit wav files, and fix sample rate writing -check that latency is actually set (esp. in windows) + +fix for 0.37: +don't prepend help- if sethalpname is called +Tom schouten: $HOME undefined crashes Pd +update 'getting pd to run' to start in with dialog panels +MIDI on windows? + +0.38: +message dialog not to disappear +sprout inlets/outlets on objects whose creation failed. +portaudio_pd files into src +GOP bounding box object +pd $1 bug ($1 is saved as it was evaluated, not as '$1') +why does changing the name of an explode in jupiter patch take so long? +close-subwindows menu item +trouble typing into number boxes +abstraction reload doesn't have to vis everyone?? +check MIDI device numbering on MSW +show results of opening audio and MIDI on dialogs +settings saver +latency testing windows escape from control-C -dialogs for a/d/a, midi, path -ALSA deglitch back in -bug: resizing grow-upward patches leaves line traces around +add standard bindings (ctl-o, etc) to dialogs +settable netsend and netreceive port numbers suspend/resume graphics updates scheduler to handle callbacks scheduler to do DSP computations even if no audio @@ -22,6 +36,7 @@ try again to fix the font scene addcomma message to message pasting should look at current mouse location open/save panel to take messages to init directory +look at prctl(2) for FP exception handling problems: arrays of non-existent templates crash @@ -36,14 +51,11 @@ deal with spaces in iemgui labels and send/receive names get rid of messages causing renaming; try to prevent patches closing themselves. Krzysztof's qlist_next reentrancy bug dac~/ adc~/ block~ incompatibility -is ALSA really checking /proc!? scofo reports error on reading score1.txt data copy/paste doesn't check templates aren't changed rfft~ loses nyquist bin -- see "to hell with it" comment in d_fft.c -soundfile writing gets wrong sample rate; see /* lie */ in d_soundfile.c data: -doesn't redraw when changing draw commands? vget, vset traversal objects cursor to show (x, y) location better hit detection (getrect is too greedy) @@ -55,6 +67,7 @@ sublists should display on parent if desired? sublists seem not to handle canvas allocation right (get.pd->pointer.pd bug) scalar hook to catch the mouse protect against "plots" going away while you drag on them +figure out why Pd sometimes crashes when you close example after adding fields features: command line flag to defeat loading objects @@ -72,15 +85,10 @@ think about x and y scale preservation when changing between graph and object show outlines of objects even when graph is "open" make graph labels persistent and add to dialog array click protection (Krzysztof's suggestion) -Alsa in data late should carefuly reset DAC/ADC fill&empty pointers increase MIDIQSIZE to at least 1024 in s_unix.c add nonblock to linux open calls instead of using alarm -make a hook so objects can specify help windows to open (for scheme object) graph_vis() to decorate graphs when they're toplevel (parent_glist == 0) get graphs to expand to hold their contents -writing FLOAT wav files -make "table" rescalable vertically --compat34 flag to save files so that 0.34 can read them suita.chopin.edu.pl/~czaja/miXed/externs/xeq.html -- MIDI file reader in glist_delete, consider why this can't be just "vis 0" -- why do we need it? abstraction auto-reload @@ -89,10 +97,8 @@ switching between dac and gettimeofday timing on dsp_start/stop check that -blocksize really reflects in audiobuf calc for Hammerfall -version to print version and exit; usage() also to print version NT and OSX: opening HTML files? -message to change block~ sizes dynamically MIDI file reading/writing? makefile to have make install depend on make local. -borrow arrow keys from IEMLIB pd messages to close and reopen sound driver Float method for random figure out list, message objects @@ -139,7 +145,6 @@ vreadsf~ benchmarking flash menu when accelerator hits? fix edit mode menu item -"undo" fancier text editing tools (reassigns meaning of primary click) get gui to notice early EOF diff --git a/pd/src/s_audio.c b/pd/src/s_audio.c index ca5e34c6..23c2197e 100644 --- a/pd/src/s_audio.c +++ b/pd/src/s_audio.c @@ -6,7 +6,6 @@ audio settings from argparse routine and from dialog window. */ - #include "m_pd.h" #include "s_stuff.h" #include @@ -27,12 +26,11 @@ typedef long t_pa_sample; #define SYS_BYTESPERCHAN (DEFDACBLKSIZE * SYS_SAMPLEWIDTH) #define SYS_XFERSAMPS (SYS_DEFAULTCH*DEFDACBLKSIZE) #define SYS_XFERSIZE (SYS_SAMPLEWIDTH * SYS_XFERSAMPS) -#define MAXAUDIODEV 4 int sys_inchannels; int sys_outchannels; int sys_advance_samples; /* scheduler advance in samples */ -int sys_blocksize = 256; /* audio I/O block size in sample frames */ +int sys_blocksize = 0; /* audio I/O block size in sample frames */ int sys_audioapi = API_DEFAULT; static int sys_meters; /* true if we're metering */ @@ -40,24 +38,94 @@ static float sys_inmax; /* max input amplitude */ static float sys_outmax; /* max output amplitude */ /* exported variables */ -#ifdef MSW -#define DEFAULTADVANCE 70000 -#else -#define DEFAULTADVANCE 50000 -#endif -int sys_schedadvance = DEFAULTADVANCE; /* scheduler advance in microseconds */ +int sys_schedadvance; /* scheduler advance in microseconds */ float sys_dacsr; int sys_hipriority = 0; t_sample *sys_soundout; t_sample *sys_soundin; + /* the "state" is normally one if we're open and zero otherwise; + but if the state is one, we still haven't necessarily opened the + audio hardware; see audio_isopen() below. */ +static int audio_state; + + /* last requested parameters */ +static int audio_naudioindev; +static int audio_audioindev[MAXAUDIOINDEV]; +static int audio_audiochindev[MAXAUDIOINDEV]; +static int audio_naudiooutdev; +static int audio_audiooutdev[MAXAUDIOOUTDEV]; +static int audio_audiochoutdev[MAXAUDIOOUTDEV]; +static int audio_rate; +static int audio_advance; + +static int audio_isopen(void) +{ + return (audio_state && + ((audio_naudioindev > 0 && audio_audiochindev[0] > 0) + || (audio_naudiooutdev > 0 && audio_audiochoutdev[0] > 0))); +} + +static void sys_get_audio_params( + int *pnaudioindev, int *paudioindev, int *chindev, + int *pnaudiooutdev, int *paudiooutdev, int *choutdev, + int *prate, int *padvance) +{ + int i; + *pnaudioindev = audio_naudioindev; + for (i = 0; i < MAXAUDIOINDEV; i++) + paudioindev[i] = audio_audioindev[i], + chindev[i] = audio_audiochindev[i]; + *pnaudiooutdev = audio_naudiooutdev; + for (i = 0; i < MAXAUDIOOUTDEV; i++) + paudiooutdev[i] = audio_audiooutdev[i], + choutdev[i] = audio_audiochoutdev[i]; + *prate = audio_rate; + *padvance = audio_advance; +} + +static void sys_save_audio_params( + int naudioindev, int *audioindev, int *chindev, + int naudiooutdev, int *audiooutdev, int *choutdev, + int rate, int advance) +{ + int i; + audio_naudioindev = naudioindev; + for (i = 0; i < MAXAUDIOINDEV; i++) + audio_audioindev[i] = audioindev[i], + audio_audiochindev[i] = chindev[i]; + audio_naudiooutdev = naudiooutdev; + for (i = 0; i < MAXAUDIOOUTDEV; i++) + audio_audiooutdev[i] = audiooutdev[i], + audio_audiochoutdev[i] = choutdev[i]; + audio_rate = rate; + audio_advance = advance; +} + + /* init routines for any API which needs to set stuff up before + any other API gets used. This is only true of OSS so far. */ +#ifdef USEAPI_OSS +void oss_init(void); +#endif + +static void audio_init( void) +{ + static int initted = 0; + if (initted) + return; + initted = 1; +#ifdef USEAPI_OSS + oss_init(); +#endif +} + /* set channels and sample rate. */ static void sys_setchsr(int chin, int chout, int sr) { int nblk; - int inbytes = chin * (DEFDACBLKSIZE*sizeof(float)); - int outbytes = chout * (DEFDACBLKSIZE*sizeof(float)); + int inbytes = (chin ? chin : 2) * (DEFDACBLKSIZE*sizeof(float)); + int outbytes = (chout ? chout : 2) * (DEFDACBLKSIZE*sizeof(float)); sys_inchannels = chin; sys_outchannels = chout; @@ -79,49 +147,32 @@ static void sys_setchsr(int chin, int chout, int sr) if (sys_verbose) post("input channels = %d, output channels = %d", sys_inchannels, sys_outchannels); + canvas_resume_dsp(canvas_suspend_dsp()); } /* ----------------------- public routines ----------------------- */ -#if 0 -void sys_open_audio(int naudioindev, int *audioindev, int nchindev, - int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev, - int *choutdev, int rate) /* IOhannes */ -{ - int inchans= - (nchindev > 0 ? chindev[0] : (nchindev == 0 ? 0 : SYS_DEFAULTCH)); - int outchans= - (nchoutdev > 0 ? choutdev[0] : (nchoutdev == 0 ? 0 : SYS_DEFAULTCH)); - int soundindev = (naudioindev <= 0 ? -1 : (audioindev[0]-1)); - int soundoutdev = (naudiooutdev <= 0 ? -1 : (audiooutdev[0]-1)); - int sounddev = (inchans > 0 ? soundindev : soundoutdev); - if (naudioindev > 1 || nchindev > 1 || naudiooutdev > 1 || nchoutdev > 1) - post("sorry, only one portaudio device can be open at once.\n"); - /* post("nindev %d, noutdev %d", naudioindev, naudiooutdev); - post("soundindev %d, soundoutdev %d", soundindev, soundoutdev); */ - if (sys_verbose) - post("channels in %d, out %d", inchans, outchans); - if (rate < 1) - rate = SYS_DEFAULTSRATE; - sys_setchsr(inchans, outchans, rate); - pa_open_audio(inchans, outchans, rate, sys_soundin, sys_soundout, - sys_blocksize, sys_advance_samples/sys_blocksize, - soundindev, soundoutdev); -} -#endif + /* open audio devices (after cleaning up the specified device and channel + vectors). The audio devices are "zero based" (i.e. "0" means the first + one.) We also save the cleaned-up device specification so that we + can later re-open audio and/or show the settings on a dialog window. */ void sys_open_audio(int naudioindev, int *audioindev, int nchindev, int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev, - int *choutdev, int rate) /* IOhannes */ + int *choutdev, int rate, int advance, int enable) { int i, *ip; int defaultchannels = SYS_DEFAULTCH; int inchans, outchans; if (rate < 1) rate = SYS_DEFAULTSRATE; - + audio_init(); + /* Since the channel vector might be longer than the + audio device vector, or vice versa, we fill the shorter one + in to match the longer one. Also, if both are empty, we fill in + one device (the default) and two channels. */ if (naudioindev == -1) - { /* not set */ + { /* no input audio devices specified */ if (nchindev == -1) { nchindev=1; @@ -131,7 +182,7 @@ void sys_open_audio(int naudioindev, int *audioindev, int nchindev, } else { - for (i = 0; i < MAXAUDIODEV; i++) + for (i = 0; i < MAXAUDIOINDEV; i++) audioindev[i] = i+1; naudioindev = nchindev; } @@ -177,7 +228,7 @@ void sys_open_audio(int naudioindev, int *audioindev, int nchindev, } else { - for (i = 0; i < MAXAUDIODEV; i++) + for (i = 0; i < MAXAUDIOOUTDEV; i++) audiooutdev[i] = i+1; naudiooutdev = nchoutdev; } @@ -211,52 +262,89 @@ void sys_open_audio(int naudioindev, int *audioindev, int nchindev, naudiooutdev = nchoutdev; } } + + /* count total number of input and output channels */ for (i = inchans = 0; i < naudioindev; i++) inchans += chindev[i]; for (i = outchans = 0; i < naudiooutdev; i++) outchans += choutdev[i]; - + /* if no input or output devices seem to have been specified, + this really means just disable audio, which we now do. Meanwhile, + we can set audio input and output devices to their defaults. */ + if (!inchans && !outchans) + { + enable = 0; + naudioindev = nchindev = naudiooutdev = nchoutdev = 1; + audioindev[0] = audiooutdev[0] = DEFAULTAUDIODEV; + chindev[0] = choutdev[0] = 0; + } + sys_schedadvance = advance * 1000; sys_setchsr(inchans, outchans, rate); + sys_log_error(ERR_NOTHING); + + if (enable && (inchans > 0 || outchans > 0)) + { +#ifdef USEAPI_PORTAUDIO + if (sys_audioapi == API_PORTAUDIO) + { + int blksize = (sys_blocksize ? sys_blocksize : 64); + pa_open_audio(inchans, outchans, rate, sys_soundin, sys_soundout, + blksize, sys_advance_samples/blksize, + (naudiooutdev > 0 ? audioindev[0] : 0), + (naudiooutdev > 0 ? audiooutdev[0] : 0)); + } +else +#endif +#ifdef USEAPI_JACK + if (sys_audioapi == API_JACK) + jack_open_audio((naudioindev > 0 ? chindev[0] : 0), + (naudiooutdev > 0 ? choutdev[0] : 0), rate); + + else +#endif #ifdef USEAPI_OSS - if (sys_audioapi == API_OSS) - oss_open_audio(naudioindev, audioindev, nchindev, chindev, - naudiooutdev, audiooutdev, nchoutdev, choutdev, rate); - else + if (sys_audioapi == API_OSS) + oss_open_audio(naudioindev, audioindev, nchindev, chindev, + naudiooutdev, audiooutdev, nchoutdev, choutdev, rate); + else #endif #ifdef USEAPI_ALSA - /* for alsa, the "device numbers" are ignored; they are sent - straight to the alsa code via linux_alsa_devname(). Only one - device is supported for each of input, output. */ - if (sys_audioapi == API_ALSA) - alsa_open_audio((naudioindev > 0 ? chindev[0] : 0), - (naudiooutdev > 0 ? choutdev[0] : 0), rate); - else -#endif -#ifdef USEAPI_PORTAUDIO - if (sys_audioapi == API_PORTAUDIO) - pa_open_audio(inchans, outchans, rate, sys_soundin, sys_soundout, - sys_blocksize, sys_advance_samples/sys_blocksize, - (naudiooutdev > 0 ? audioindev[0] : 0), - (naudiooutdev > 0 ? audiooutdev[0] : 0)); - else + /* for alsa, only one device is supported; it may + be open for both input and output. */ + if (sys_audioapi == API_ALSA) + alsa_open_audio(naudioindev, audioindev, nchindev, chindev, + naudiooutdev, audiooutdev, nchoutdev, choutdev, rate); + else #endif #ifdef USEAPI_MMIO - if (sys_audioapi == API_MMIO) - mmio_open_audio(naudioindev, audioindev, nchindev, chindev, - naudiooutdev, audiooutdev, nchoutdev, choutdev, rate); - else + if (sys_audioapi == API_MMIO) + mmio_open_audio(naudioindev, audioindev, nchindev, chindev, + naudiooutdev, audiooutdev, nchoutdev, choutdev, rate); + else #endif - post("unknown audio API specified"); + post("unknown audio API specified"); + } + sys_save_audio_params(naudioindev, audioindev, chindev, + naudiooutdev, audiooutdev, choutdev, rate, advance); + audio_state = enable; + sys_vgui("set pd_whichapi %d\n", (audio_isopen() ? sys_audioapi : 0)); + sched_set_using_dacs(enable); } void sys_close_audio(void) { - + if (!audio_isopen()) + return; #ifdef USEAPI_PORTAUDIO if (sys_audioapi == API_PORTAUDIO) pa_close_audio(); else #endif +#ifdef USEAPI_JACK + if (sys_audioapi == API_JACK) + jack_close_audio(); + else +#endif #ifdef USEAPI_OSS if (sys_audioapi == API_OSS) oss_close_audio(); @@ -266,14 +354,26 @@ void sys_close_audio(void) if (sys_audioapi == API_ALSA) alsa_close_audio(); else +#endif #ifdef USEAPI_MMIO if (sys_audioapi == API_MMIO) mmio_close_audio(); else #endif -#endif - post("unknown API"); + post("sys_close_audio: unknown API %d", sys_audioapi); + sys_inchannels = sys_outchannels = 0; +} + /* open audio using whatever parameters were last used */ +void sys_reopen_audio( void) +{ + int naudioindev, audioindev[MAXAUDIOINDEV], chindev[MAXAUDIOINDEV]; + int naudiooutdev, audiooutdev[MAXAUDIOOUTDEV], choutdev[MAXAUDIOOUTDEV]; + int rate, advance; + sys_get_audio_params(&naudioindev, audioindev, chindev, + &naudiooutdev, audiooutdev, choutdev, &rate, &advance); + sys_open_audio(naudioindev, audioindev, naudioindev, chindev, + naudiooutdev, audiooutdev, naudiooutdev, choutdev, rate, advance, 1); } int sys_send_dacs(void) @@ -305,6 +405,11 @@ int sys_send_dacs(void) return (pa_send_dacs()); else #endif +#ifdef USEAPI_JACK + if (sys_audioapi == API_JACK) + return (jack_send_dacs()); + else +#endif #ifdef USEAPI_OSS if (sys_audioapi == API_OSS) return (oss_send_dacs()); @@ -364,26 +469,249 @@ void sys_reportidle(void) { } +#define MAXNDEV 20 +#define DEVDESCSIZE 80 + +static void audio_getdevs(char *indevlist, int *nindevs, + char *outdevlist, int *noutdevs, int *canmulti, + int maxndev, int devdescsize) +{ + audio_init(); +#ifdef USEAPI_OSS + if (sys_audioapi == API_OSS) + { + oss_getdevs(indevlist, nindevs, outdevlist, noutdevs, canmulti, + maxndev, devdescsize); + } + else +#endif +#ifdef USEAPI_ALSA + if (sys_audioapi == API_ALSA) + { + alsa_getdevs(indevlist, nindevs, outdevlist, noutdevs, canmulti, + maxndev, devdescsize); + } + else +#endif +#ifdef USEAPI_PORTAUDIO + if (sys_audioapi == API_PORTAUDIO) + { + pa_getdevs(indevlist, nindevs, outdevlist, noutdevs, canmulti, + maxndev, devdescsize); + } + else +#endif +#ifdef USEAPI_MMIO + if (sys_audioapi == API_MMIO) + { + mmio_getdevs(indevlist, nindevs, outdevlist, noutdevs, canmulti, + maxndev, devdescsize); + } + else +#endif + { + /* this shouldn't happen once all the above get filled in. */ + int i; + *nindevs = *noutdevs = 3; + for (i = 0; i < 3; i++) + { + sprintf(indevlist + i * devdescsize, "input device #%d", i+1); + sprintf(outdevlist + i * devdescsize, "output device #%d", i+1); + } + *canmulti = 0; + } +} + +#ifdef MSW +#define DEVONSET 0 /* microsoft device list starts at 0 (the "mapper"). */ +#else /* (see also MSW ifdef in sys_parsedevlist(), s_main.c) */ +#define DEVONSET 1 /* To agree with command line flags, normally start at 1 */ +#endif + +static void sys_listaudiodevs(void ) +{ + char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE]; + int nindevs = 0, noutdevs = 0, i, canmulti = 0; + + audio_getdevs(indevlist, &nindevs, outdevlist, &noutdevs, &canmulti, + MAXNDEV, DEVDESCSIZE); + + if (!nindevs) + post("no audio input devices found"); + else + { + post("input devices:"); + for (i = 0; i < nindevs; i++) + post("%d. %s", i+1, indevlist + i * DEVDESCSIZE); + } + if (!noutdevs) + post("no audio output devices found"); + else + { + post("output devices:"); + for (i = 0; i < noutdevs; i++) + post("%d. %s", i + DEVONSET, outdevlist + i * DEVDESCSIZE); + } + post("API number %d\n", sys_audioapi); +} + + /* start an audio settings dialog window */ +void glob_audio_properties(t_pd *dummy, t_floatarg flongform) +{ + char buf[1024 + 2 * MAXNDEV*(DEVDESCSIZE+4)]; + /* these are the devices you're using: */ + int naudioindev, audioindev[MAXAUDIOINDEV], chindev[MAXAUDIOINDEV]; + int naudiooutdev, audiooutdev[MAXAUDIOOUTDEV], choutdev[MAXAUDIOOUTDEV]; + int audioindev1, audioindev2, audioindev3, audioindev4, + audioinchan1, audioinchan2, audioinchan3, audioinchan4, + audiooutdev1, audiooutdev2, audiooutdev3, audiooutdev4, + audiooutchan1, audiooutchan2, audiooutchan3, audiooutchan4; + int rate, advance; + /* these are all the devices on your system: */ + char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE]; + int nindevs = 0, noutdevs = 0, canmulti = 0, i; + + char indevliststring[MAXNDEV*(DEVDESCSIZE+4)+80], + outdevliststring[MAXNDEV*(DEVDESCSIZE+4)+80]; + + audio_getdevs(indevlist, &nindevs, outdevlist, &noutdevs, &canmulti, + MAXNDEV, DEVDESCSIZE); + + strcpy(indevliststring, "{"); + for (i = 0; i < nindevs; i++) + { + strcat(indevliststring, "\""); + strcat(indevliststring, indevlist + i * DEVDESCSIZE); + strcat(indevliststring, "\" "); + } + strcat(indevliststring, "}"); + + strcpy(outdevliststring, "{"); + for (i = 0; i < noutdevs; i++) + { + strcat(outdevliststring, "\""); + strcat(outdevliststring, outdevlist + i * DEVDESCSIZE); + strcat(outdevliststring, "\" "); + } + strcat(outdevliststring, "}"); + + sys_get_audio_params(&naudioindev, audioindev, chindev, + &naudiooutdev, audiooutdev, choutdev, &rate, &advance); + + /* post("naudioindev %d naudiooutdev %d longform %f", + naudioindev, naudiooutdev, flongform); */ + if (naudioindev > 1 || naudiooutdev > 1) + flongform = 1; + + + audioindev1 = (naudioindev > 0 && audioindev[0]>= 0 ? audioindev[0] : 0); + audioindev2 = (naudioindev > 1 && audioindev[1]>= 0 ? audioindev[1] : 0); + audioindev3 = (naudioindev > 2 && audioindev[2]>= 0 ? audioindev[2] : 0); + audioindev4 = (naudioindev > 3 && audioindev[3]>= 0 ? audioindev[3] : 0); + audioinchan1 = (naudioindev > 0 ? chindev[0] : 0); + audioinchan2 = (naudioindev > 1 ? chindev[1] : 0); + audioinchan3 = (naudioindev > 2 ? chindev[2] : 0); + audioinchan4 = (naudioindev > 3 ? chindev[3] : 0); + audiooutdev1 = (naudiooutdev > 0 && audiooutdev[0]>=0 ? audiooutdev[0] : 0); + audiooutdev2 = (naudiooutdev > 1 && audiooutdev[1]>=0 ? audiooutdev[1] : 0); + audiooutdev3 = (naudiooutdev > 2 && audiooutdev[2]>=0 ? audiooutdev[2] : 0); + audiooutdev4 = (naudiooutdev > 3 && audiooutdev[3]>=0 ? audiooutdev[3] : 0); + audiooutchan1 = (naudiooutdev > 0 ? choutdev[0] : 0); + audiooutchan2 = (naudiooutdev > 1 ? choutdev[1] : 0); + audiooutchan3 = (naudiooutdev > 2 ? choutdev[2] : 0); + audiooutchan4 = (naudiooutdev > 3 ? choutdev[3] : 0); + sprintf(buf, +"pdtk_audio_dialog %%s \ +%s %d %d %d %d %d %d %d %d \ +%s %d %d %d %d %d %d %d %d \ +%d %d %d %d\n", + indevliststring, + audioindev1, audioindev2, audioindev3, audioindev4, + audioinchan1, audioinchan2, audioinchan3, audioinchan4, + outdevliststring, + audiooutdev1, audiooutdev2, audiooutdev3, audiooutdev4, + audiooutchan1, audiooutchan2, audiooutchan3, audiooutchan4, + rate, advance, canmulti, (flongform != 0)); + gfxstub_deleteforkey(0); + gfxstub_new(&glob_pdobject, glob_audio_properties, buf); +} + + /* new values from dialog window */ +void glob_audio_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv) +{ + int naudioindev, audioindev[MAXAUDIOINDEV], chindev[MAXAUDIOINDEV]; + int naudiooutdev, audiooutdev[MAXAUDIOOUTDEV], choutdev[MAXAUDIOOUTDEV]; + int rate, advance, audioon, i, nindev, noutdev; + int audioindev1, audioinchan1, audiooutdev1, audiooutchan1; + int newaudioindev[4], newaudioinchan[4], + newaudiooutdev[4], newaudiooutchan[4]; + /* the new values the dialog came back with: */ + int newrate = atom_getintarg(16, argc, argv); + int newadvance = atom_getintarg(17, argc, argv); + int statewas; + + for (i = 0; i < 4; i++) + { + newaudioindev[i] = atom_getintarg(i, argc, argv); + newaudioinchan[i] = atom_getintarg(i+4, argc, argv); + newaudiooutdev[i] = atom_getintarg(i+8, argc, argv); + newaudiooutchan[i] = atom_getintarg(i+12, argc, argv); + } + + for (i = 0, nindev = 0; i < 4; i++) + { + if (newaudioinchan[i] > 0) + { + newaudioindev[nindev] = newaudioindev[i]; + newaudioinchan[nindev] = newaudioinchan[i]; + /* post("in %d %d %d", nindev, + newaudioindev[nindev] , newaudioinchan[nindev]); */ + nindev++; + } + } + for (i = 0, noutdev = 0; i < 4; i++) + { + if (newaudiooutchan[i] > 0) + { + newaudiooutdev[noutdev] = newaudiooutdev[i]; + newaudiooutchan[noutdev] = newaudiooutchan[i]; + /* post("out %d %d %d", noutdev, + newaudiooutdev[noutdev] , newaudioinchan[noutdev]); */ + noutdev++; + } + } + + sys_close_audio(); + sys_open_audio(nindev, newaudioindev, nindev, newaudioinchan, + noutdev, newaudiooutdev, noutdev, newaudiooutchan, + newrate, newadvance, 1); +} + void sys_listdevs(void ) { #ifdef USEAPI_PORTAUDIO if (sys_audioapi == API_PORTAUDIO) - pa_listdevs(); + sys_listaudiodevs(); else #endif +#ifdef USEAPI_JACK + if (sys_audioapi == API_JACK) + jack_listdevs(); + else +#endif #ifdef USEAPI_OSS if (sys_audioapi == API_OSS) - oss_listdevs(); + sys_listaudiodevs(); else #endif #ifdef USEAPI_MMIO if (sys_audioapi == API_MMIO) - mmio_listdevs(); + sys_listaudiodevs(); else #endif #ifdef USEAPI_ALSA if (sys_audioapi == API_ALSA) - alsa_listdevs(); + sys_listaudiodevs(); else #endif post("unknown API"); @@ -401,10 +729,135 @@ void sys_setblocksize(int n) sys_blocksize = n; } -void sys_set_sound_api(int which) +void sys_set_audio_api(int which) { sys_audioapi = which; if (sys_verbose) post("sys_audioapi %d", sys_audioapi); } +void glob_audio_setapi(void *dummy, t_floatarg f) +{ + int newapi = f; + if (newapi) + { + if (newapi == sys_audioapi) + { + if (!audio_isopen()) + sys_reopen_audio(); + } + else + { + sys_close_audio(); + sys_audioapi = newapi; + /* bash device params back to default */ + audio_naudioindev = audio_naudiooutdev = 1; + audio_audioindev[0] = audio_audiooutdev[0] = DEFAULTAUDIODEV; + audio_audiochindev[0] = audio_audiochoutdev[0] = SYS_DEFAULTCH; + sys_reopen_audio(); + } + glob_audio_properties(0, 0); + } + else if (audio_isopen()) + { + sys_close_audio(); + audio_state = 0; + sched_set_using_dacs(0); + } +} + + /* start or stop the audio hardware */ +void sys_set_audio_state(int onoff) +{ + if (onoff) /* start */ + { + if (!audio_isopen()) + sys_reopen_audio(); + } + else + { + if (audio_isopen()) + { + sys_close_audio(); + sched_set_using_dacs(0); + } + } + audio_state = onoff; +} + +void sys_get_audio_apis(char *buf) +{ + int n = 0; + strcpy(buf, "{ "); +#ifdef USEAPI_OSS + sprintf(buf + strlen(buf), "{OSS %d} ", API_OSS); n++; +#endif +#ifdef USEAPI_MMIO + sprintf(buf + strlen(buf), "{\"standard (MMIO)\" %d} ", API_MMIO); n++; +#endif +#ifdef USEAPI_ALSA + sprintf(buf + strlen(buf), "{ALSA %d} ", API_ALSA); n++; +#endif +#ifdef USEAPI_PORTAUDIO +#ifdef MSW + sprintf(buf + strlen(buf), + "{\"ASIO (via portaudio)\" %d} ", API_PORTAUDIO); +#else +#ifdef OSX + sprintf(buf + strlen(buf), + "{\"standard (portaudio)\" %d} ", API_PORTAUDIO); +#else + sprintf(buf + strlen(buf), "{portaudio %d} ", API_PORTAUDIO); +#endif +#endif + n++; +#endif +#ifdef USEAPI_JACK + sprintf(buf + strlen(buf), "{jack %d} ", API_JACK); n++; +#endif + strcat(buf, "}"); + /* then again, if only one API (or none) we don't offer any choice. */ + if (n < 2) + strcpy(buf, "{}"); + +} + +#ifdef USEAPI_ALSA +void alsa_putzeros(int n); +void alsa_getzeros(int n); +void alsa_printstate( void); +#endif + + /* debugging */ +void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv) +{ + t_symbol *arg = atom_getsymbolarg(0, argc, argv); + if (arg == gensym("restart")) + { + int naudioindev, audioindev[MAXAUDIOINDEV], chindev[MAXAUDIOINDEV]; + int naudiooutdev, audiooutdev[MAXAUDIOOUTDEV], choutdev[MAXAUDIOOUTDEV]; + int rate, advance; + sys_get_audio_params(&naudioindev, audioindev, chindev, + &naudiooutdev, audiooutdev, choutdev, &rate, &advance); + sys_close_audio(); + sys_open_audio(naudioindev, audioindev, naudioindev, chindev, + naudiooutdev, audiooutdev, naudiooutdev, choutdev, rate, advance, + 1); + } +#ifdef USEAPI_ALSA + else if (arg == gensym("alsawrite")) + { + int n = atom_getintarg(1, argc, argv); + alsa_putzeros(n); + } + else if (arg == gensym("alsaread")) + { + int n = atom_getintarg(1, argc, argv); + alsa_getzeros(n); + } + else if (arg == gensym("print")) + { + alsa_printstate(); + } +#endif +} diff --git a/pd/src/s_audio_alsa.c b/pd/src/s_audio_alsa.c index 0fa3d791..b94a4e04 100644 --- a/pd/src/s_audio_alsa.c +++ b/pd/src/s_audio_alsa.c @@ -45,39 +45,27 @@ typedef struct _alsa_dev } t_alsa_dev; t_alsa_dev alsa_device; -static short *alsa_buf; +static short *alsa_buf = 0; static int alsa_samplewidth; static snd_pcm_status_t* in_status; static snd_pcm_status_t* out_status; static int alsa_mode; +static int alsa_buf_samps; /* believed actual ALSA bufsize in sample frames */ +static int alsa_inchannels; +static int alsa_outchannels; /* Defines */ #define DEBUG(x) x #define DEBUG2(x) {x;} -static char alsa_devname[512] = "hw:0,0"; -static int alsa_use_plugin = 0; +static void alsa_checkiosync( void); /* don't assume we can turn all 31 bits when doing float-to-fix; otherwise some audio drivers (e.g. Midiman/ALSA) wrap around. */ #define FMAX 0x7ffff000 #define CLIP32(x) (((x)>FMAX)?FMAX:((x) < -FMAX)?-FMAX:(x)) - /* ugly Alsa-specific flags */ -void linux_alsa_devname(char *devname) -{ - strncpy(alsa_devname, devname, 511); -} - -void linux_alsa_use_plugin(int t) -{ - if (t == 1) - alsa_use_plugin = 1; - else - alsa_use_plugin = 0; -} - /* support for ALSA pcmv2 api by Karl MacMillan */ static void check_error(int err, const char *why) @@ -86,7 +74,11 @@ static void check_error(int err, const char *why) fprintf(stderr, "%s: %s\n", why, snd_strerror(err)); } -int alsa_open_audio(int wantinchans, int wantoutchans, int srate) +/* was: alsa_open_audio(int wantinchans, int wantoutchans, int srate) */ + +int alsa_open_audio(int naudioindev, int *audioindev, int nchindev, + int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev, + int *choutdev, int rate) { int err, inchans = 0, outchans = 0, subunitdir; char devname[512]; @@ -97,14 +89,42 @@ int alsa_open_audio(int wantinchans, int wantoutchans, int srate) int nfrags, i; short* tmp_buf; unsigned int tmp_uint; + int wantinchans, wantoutchans, devno; + + if (naudioindev >= 2 || naudiooutdev >= 2) + post("alsa: only one input and output device allowed (extras ignored"); + if (naudioindev >= 1 && naudiooutdev >= 1 && + audioindev[0] != audiooutdev[0]) + post("alsa: changing output device to agree with input device"); + if (nchindev) + wantinchans = chindev[0]; + else wantinchans = (naudioindev ? 2 : 0); + if (nchoutdev) + wantoutchans = choutdev[0]; + else wantoutchans = (naudiooutdev ? 2 : 0); + devno = (naudioindev > 0 ? audioindev[0] : + (naudiooutdev > 0 ? audiooutdev[0] : 0)); + + /* device names are hw:0, plughw:0, hw:1, and so on. */ + if (devno & 1) + sprintf(devname, "plughw:%d", devno/2); + else sprintf(devname, "hw:%d", devno/2); - nfrags = sys_schedadvance * (float)srate / (1e6 * frag_size); + if (sys_verbose) + post("device name %s; channels in %d, out %d", devname, wantinchans, + wantoutchans); + + nfrags = sys_schedadvance * (float)rate / (1e6 * frag_size); + /* save our belief as to ALSA's buffer size for later */ + alsa_buf_samps = nfrags * frag_size; if (sys_verbose) post("audio buffer set to %d", (int)(0.001 * sys_schedadvance)); + + if (wantinchans) { - err = snd_pcm_open(&alsa_device.inhandle, alsa_devname, + err = snd_pcm_open(&alsa_device.inhandle, devname, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK); check_error(err, "snd_pcm_open (input)"); @@ -118,7 +138,7 @@ int alsa_open_audio(int wantinchans, int wantoutchans, int srate) } if (wantoutchans) { - err = snd_pcm_open(&alsa_device.outhandle, alsa_devname, + err = snd_pcm_open(&alsa_device.outhandle, devname, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); check_error(err, "snd_pcm_open (output)"); @@ -175,7 +195,7 @@ int alsa_open_audio(int wantinchans, int wantoutchans, int srate) inchans = tmp_uint; // set the sampling rate err = snd_pcm_hw_params_set_rate_min(alsa_device.inhandle, hw_params, - &srate, 0); + &rate, 0); check_error(err, "snd_pcm_hw_params_set_rate_min (input)"); #if 0 err = snd_pcm_hw_params_get_rate(hw_params, &subunitdir); @@ -191,7 +211,7 @@ int alsa_open_audio(int wantinchans, int wantoutchans, int srate) snd_pcm_hw_params_get_period_size(hw_params, 0), snd_pcm_hw_params_get_period_size_min(hw_params, 0), snd_pcm_hw_params_get_period_size_max(hw_params, 0)); -#endif +#endif err = snd_pcm_hw_params_set_period_size_near(alsa_device.inhandle, hw_params, (snd_pcm_uframes_t) @@ -217,22 +237,12 @@ int alsa_open_audio(int wantinchans, int wantoutchans, int srate) check_error(err, "snd_pcm_sw_params_malloc (input)"); err = snd_pcm_sw_params_current(alsa_device.inhandle, sw_params); check_error(err, "snd_pcm_sw_params_current (input)"); -#if 1 - err = snd_pcm_sw_params_set_start_mode(alsa_device.inhandle, sw_params, - SND_PCM_START_EXPLICIT); - check_error(err, "snd_pcm_sw_params_set_start_mode (input)"); - err = snd_pcm_sw_params_set_xrun_mode(alsa_device.inhandle, sw_params, - SND_PCM_XRUN_NONE); - check_error(err, "snd_pcm_sw_params_set_xrun_mode (input)"); -#else err = snd_pcm_sw_params_set_start_threshold(alsa_device.inhandle, sw_params, nfrags * frag_size); check_error(err, "snd_pcm_sw_params_set_start_threshold (input)"); err = snd_pcm_sw_params_set_stop_threshold(alsa_device.inhandle, - sw_params, 1); + sw_params, 0x7fffffff); check_error(err, "snd_pcm_sw_params_set_stop_threshold (input)"); -#endif - err = snd_pcm_sw_params_set_avail_min(alsa_device.inhandle, sw_params, frag_size); check_error(err, "snd_pcm_sw_params_set_avail_min (input)"); @@ -296,7 +306,7 @@ int alsa_open_audio(int wantinchans, int wantoutchans, int srate) outchans = tmp_uint; // set the sampling rate err = snd_pcm_hw_params_set_rate_min(alsa_device.outhandle, hw_params, - &srate, 0); + &rate, 0); check_error(err, "snd_pcm_hw_params_set_rate_min (output)"); #if 0 err = snd_pcm_hw_params_get_rate(hw_params, &subunitdir); @@ -325,39 +335,27 @@ int alsa_open_audio(int wantinchans, int wantoutchans, int srate) hw_params, nfrags * frag_size); check_error(err, "snd_pcm_hw_params_set_buffer_size_near (output)"); - + err = snd_pcm_hw_params(alsa_device.outhandle, hw_params); check_error(err, "snd_pcm_hw_params (output)"); - + snd_pcm_hw_params_free(hw_params); err = snd_pcm_sw_params_malloc(&sw_params); check_error(err, "snd_pcm_sw_params_malloc (output)"); err = snd_pcm_sw_params_current(alsa_device.outhandle, sw_params); check_error(err, "snd_pcm_sw_params_current (output)"); -#if 1 - err = snd_pcm_sw_params_set_start_mode(alsa_device.outhandle, - sw_params, - SND_PCM_START_EXPLICIT); - check_error(err, "snd_pcm_sw_params_set_start_mode (output)"); - err = snd_pcm_sw_params_set_xrun_mode(alsa_device.outhandle, sw_params, - SND_PCM_XRUN_NONE); - check_error(err, "snd_pcm_sw_params_set_xrun_mode (output)"); -#else - err = snd_pcm_sw_params_set_start_threshold(alsa_device.inhandle, + err = snd_pcm_sw_params_set_start_threshold(alsa_device.outhandle, sw_params, nfrags * frag_size); check_error(err, "snd_pcm_sw_params_set_start_threshold (output)"); - err = snd_pcm_sw_params_set_stop_threshold(alsa_device.inhandle, - sw_params, 1); + err = snd_pcm_sw_params_set_stop_threshold(alsa_device.outhandle, + sw_params, 0x7fffffff); check_error(err, "snd_pcm_sw_params_set_stop_threshold (output)"); -#endif - err = snd_pcm_sw_params_set_avail_min(alsa_device.outhandle, sw_params, - frag_size); + frag_size); check_error(err, "snd_pcm_sw_params_set_avail_min (output)"); err = snd_pcm_sw_params(alsa_device.outhandle, sw_params); check_error(err, "snd_pcm_sw_params (output)"); - snd_pcm_sw_params_free(sw_params); snd_output_stdio_attach(&out, stderr, 0); @@ -379,40 +377,36 @@ int alsa_open_audio(int wantinchans, int wantoutchans, int srate) if (inchans && outchans) snd_pcm_link(alsa_device.inhandle, alsa_device.outhandle); - // set up the buffer - if (outchans > inchans) - alsa_buf = (short *)calloc(sizeof(char) * alsa_samplewidth, - DEFDACBLKSIZE * outchans); - else - alsa_buf = (short *)calloc(sizeof(char) * alsa_samplewidth, - DEFDACBLKSIZE * inchans); - // fill the buffer with silence - if (outchans) - { - i = nfrags + 1; - while (i--) - snd_pcm_writei(alsa_device.outhandle, alsa_buf, frag_size); - } - // set up the status variables err = snd_pcm_status_malloc(&in_status); check_error(err, "snd_pcm_status_malloc"); err = snd_pcm_status_malloc(&out_status); check_error(err, "snd_pcm_status_malloc"); - // start the device -#if 1 + // set up the buffer + if (alsa_buf) + free(alsa_buf); + alsa_buf = (short *)malloc( + sizeof(char) * alsa_samplewidth * DEFDACBLKSIZE * + (outchans > inchans ? outchans : inchans)); + memset(alsa_buf, 0, sizeof(char) * alsa_samplewidth * DEFDACBLKSIZE * + (outchans > inchans ? outchans : inchans)); + // fill the buffer with silence if (outchans) { - err = snd_pcm_start(alsa_device.outhandle); - check_error(err, "snd_pcm_start"); - } - else if (inchans) - { - err = snd_pcm_start(alsa_device.inhandle); - check_error(err, "snd_pcm_start"); + i = (frag_size * nfrags)/DEFDACBLKSIZE + 1; + while (i--) + snd_pcm_writei(alsa_device.outhandle, alsa_buf, DEFDACBLKSIZE); + /* apparently we're not suppposed to start it in this case, + but can (and must) if there's only ADC open (below). */ + /* if ((err = snd_pcm_start(alsa_device.outhandle) < 0)) + check_error(err, "output start failed\n"); */ } -#endif + else if (snd_pcm_start(alsa_device.inhandle) < 0) + check_error(err, "input start failed\n"); + + alsa_outchannels = outchans; + alsa_inchannels = inchans; return 0; } @@ -445,8 +439,10 @@ int alsa_send_dacs(void) int i, j, k, err, devno = 0; int inputcount = 0, outputcount = 0, inputlate = 0, outputlate = 0; int result; - int inchannels = sys_inchannels; - int outchannels = sys_outchannels; + int inchannels = (sys_inchannels > alsa_inchannels ? + alsa_inchannels : sys_inchannels); + int outchannels = (sys_outchannels > alsa_outchannels ? + alsa_outchannels : sys_outchannels); unsigned int intransfersize = DEFDACBLKSIZE; unsigned int outtransfersize = DEFDACBLKSIZE; @@ -467,13 +463,15 @@ int alsa_send_dacs(void) callno++; - if (inchannels) + alsa_checkiosync(); /* check I/O are in sync and data not late */ + + if (alsa_inchannels) { snd_pcm_status(alsa_device.inhandle, in_status); if (snd_pcm_status_get_avail(in_status) < intransfersize) return SENDDACS_NO; } - if (outchannels) + if (alsa_outchannels) { snd_pcm_status(alsa_device.outhandle, out_status); if (snd_pcm_status_get_avail(out_status) < outtransfersize) @@ -481,7 +479,7 @@ int alsa_send_dacs(void) } /* do output */ - if (outchannels) + if (alsa_outchannels) { fp = sys_soundout; if (alsa_samplewidth == 4) @@ -489,7 +487,7 @@ int alsa_send_dacs(void) for (i = 0, fp1 = fp; i < outchannels; i++, fp1 += DEFDACBLKSIZE) { for (j = i, k = DEFDACBLKSIZE, fp2 = fp1; k--; - j += outchannels, fp2++) + j += alsa_outchannels, fp2++) { float s1 = *fp2 * INT32_MAX; ((t_alsa_sample32 *)alsa_buf)[j] = CLIP32(s1); @@ -501,7 +499,7 @@ int alsa_send_dacs(void) for (i = 0, fp1 = fp; i < outchannels; i++, fp1 += DEFDACBLKSIZE) { for (j = i, k = DEFDACBLKSIZE, fp2 = fp1; k--; - j += outchannels, fp2++) + j += alsa_outchannels, fp2++) { int s = *fp2 * 32767.; if (s > 32767) @@ -547,7 +545,7 @@ int alsa_send_dacs(void) } } /* do input */ - if (sys_inchannels) + if (alsa_inchannels) { result = snd_pcm_readi(alsa_device.inhandle, alsa_buf, intransfersize); if (result < (int)intransfersize) @@ -575,7 +573,7 @@ int alsa_send_dacs(void) for (i = 0, fp1 = fp; i < inchannels; i++, fp1 += DEFDACBLKSIZE) { for (j = i, k = DEFDACBLKSIZE, fp2 = fp1; k--; - j += inchannels, fp2++) + j += alsa_inchannels, fp2++) *fp2 = (float) ((t_alsa_sample32 *)alsa_buf)[j] * (1./ INT32_MAX); } @@ -584,8 +582,8 @@ int alsa_send_dacs(void) { for (i = 0, fp1 = fp; i < inchannels; i++, fp1 += DEFDACBLKSIZE) { - for (j = i, k = DEFDACBLKSIZE, fp2 = fp1; k--; j += inchannels, - fp2++) + for (j = i, k = DEFDACBLKSIZE, fp2 = fp1; k--; + j += alsa_inchannels, fp2++) *fp2 = (float) ((t_alsa_sample16 *)alsa_buf)[j] * 3.051850e-05; } @@ -603,6 +601,35 @@ int alsa_send_dacs(void) return SENDDACS_YES; } +void alsa_printstate( void) +{ + int i, result; + snd_pcm_sframes_t indelay, outdelay; + if (sys_audioapi != API_ALSA) + { + error("restart-audio: implemented for ALSA only."); + return; + } + if (sys_inchannels) + { + result = snd_pcm_delay(alsa_device.inhandle, &indelay); + if (result < 0) + post("snd_pcm_delay 1 failed"); + else post("in delay %d", indelay); + } + if (sys_outchannels) + { + result = snd_pcm_delay(alsa_device.outhandle, &outdelay); + if (result < 0) + post("snd_pcm_delay 2 failed"); + else post("out delay %d", outdelay); + } + post("sum %d (%d mod 64)\n", indelay + outdelay, (indelay+outdelay)%64); + + post("buf samples %d", alsa_buf_samps); +} + + void alsa_resync( void) { int i, result; @@ -623,8 +650,131 @@ void alsa_resync( void) post("%d written", i); } +void alsa_putzeros(int n) +{ + int i, result; + memset(alsa_buf, 0, + sizeof(char) * alsa_samplewidth * DEFDACBLKSIZE * alsa_outchannels); + for (i = 0; i < n; i++) + { + result = snd_pcm_writei(alsa_device.outhandle, alsa_buf, DEFDACBLKSIZE); +#if 0 + if (result != DEFDACBLKSIZE) + post("result %d", result); +#endif + } +} + +void alsa_getzeros(int n) +{ + int i, result; + for (i = 0; i < n; i++) + { + result = snd_pcm_readi(alsa_device.inhandle, alsa_buf, DEFDACBLKSIZE); +#if 0 + if (result != DEFDACBLKSIZE) + post("result %d", result); +#endif + } +} + + /* call this only if both input and output are open */ +static void alsa_checkiosync( void) +{ + int i, result, checkit = 1, giveup = 1000, alreadylogged = 0; + snd_pcm_sframes_t indelay, outdelay, defect; + + if (!(alsa_outchannels && alsa_inchannels)) + return; + while (checkit) + { + checkit = 0; + if (giveup-- <= 0) + return; + result = snd_pcm_delay(alsa_device.outhandle, &outdelay); + if (result < 0) + { + post("output snd_pcm_delay failed: %s", snd_strerror(result)); + if (snd_pcm_status(alsa_device.outhandle, out_status) < 0) + post("output snd_pcm_status failed"); + else post("astate %d", + snd_pcm_status_get_state(out_status)); + return; + } + if (outdelay < 0) + sys_log_error(ERR_DATALATE), alreadylogged = 1; + + if (sys_inchannels) + { + result = snd_pcm_delay(alsa_device.inhandle, &indelay); + if (result < 0) + { + post("input snd_pcm_delay failed"); + return; + } + defect = indelay + outdelay - alsa_buf_samps; + if (defect < -DEFDACBLKSIZE) + { + checkit = 1; + alsa_putzeros(1); + if (!alreadylogged) + sys_log_error(ERR_RESYNC), alreadylogged = 1; + } + else if (defect > 0) + { + checkit = 1; + alsa_getzeros(1); + if (!alreadylogged) + sys_log_error(ERR_RESYNC), alreadylogged = 1; + } + } + } +} + void alsa_listdevs( void) { post("device listing not implemented in ALSA yet\n"); } + /* For each hardware card found, we list two devices, the "hard" and + "plug" one. The card scan is derived from portaudio code. */ +void alsa_getdevs(char *indevlist, int *nindevs, + char *outdevlist, int *noutdevs, int *canmulti, + int maxndev, int devdescsize) +{ + int ndev = 0, cardno = -1; + *canmulti = 0; /* only one device; must be the same for input&output */ + while (!snd_card_next(&cardno) && cardno >= 0) + { + snd_ctl_t *ctl; + snd_ctl_card_info_t *info; + char devname[80]; + const char *desc; + if (2 * ndev + 2 > maxndev) + break; + /* apparently, "cardno" is just a counter; but check that here */ + if (ndev != cardno) + fprintf(stderr, "oops: ALSA cards not reported in order?\n"); + sprintf(devname, "hw:%d", cardno ); + /* fprintf(stderr, "\ntry %s...\n", devname); */ + if (snd_ctl_open(&ctl, devname, 0) >= 0) + { + snd_ctl_card_info_malloc(&info); + snd_ctl_card_info(ctl, info); + desc = snd_ctl_card_info_get_name(info); + snd_ctl_card_info_free(info); + } + else + { + fprintf(stderr, "ALSA card scan error\n"); + desc = "???"; + } + /* fprintf(stderr, "name: %s\n", snd_ctl_card_info_get_name(info)); */ + sprintf(indevlist + 2*ndev * devdescsize, "%s (hardware)", desc); + sprintf(indevlist + (2*ndev + 1) * devdescsize, "%s (plug-in)", desc); + sprintf(outdevlist + 2*ndev * devdescsize, "%s (hardware)", desc); + sprintf(outdevlist + (2*ndev + 1) * devdescsize, "%s (plug-in)", desc); + ndev++; + } + *nindevs = *noutdevs = 2 * ndev; +} diff --git a/pd/src/s_audio_jack.c b/pd/src/s_audio_jack.c new file mode 100644 index 00000000..6f9937db --- /dev/null +++ b/pd/src/s_audio_jack.c @@ -0,0 +1,350 @@ + + +/* ----------------------- Experimental routines for jack -------------- */ +#ifdef USEAPI_JACK + +#include +#include +#include +#include +#include +#include +#include + + +#define MAX_CLIENTS 100 +#define NUM_JACK_PORTS 32 +#define BUF_JACK 4096 +static jack_nframes_t jack_out_max; +#define JACK_OUT_MAX 64 +static jack_nframes_t jack_filled = 0; +static float jack_outbuf[NUM_JACK_PORTS*BUF_JACK]; +static float jack_inbuf[NUM_JACK_PORTS*BUF_JACK]; +static int jack_started = 0; + + +static jack_port_t *input_port[NUM_JACK_PORTS]; +static jack_port_t *output_port[NUM_JACK_PORTS]; +static jack_client_t *jack_client; +char *jack_client_names[MAX_CLIENTS]; + +pthread_mutex_t jack_mutex; +pthread_cond_t jack_sem; + +static int +process (jack_nframes_t nframes, void *arg) +{ + int j; + float *out; + float *in; + + if (nframes > JACK_OUT_MAX) jack_out_max = nframes; + else jack_out_max = JACK_OUT_MAX; + + if (jack_filled >= nframes) { + if (jack_filled != nframes) fprintf(stderr,"Partial read"); + + for (j = 0; j < sys_outchannels; j++) { + out = jack_port_get_buffer (output_port[j], nframes); + memcpy(out, jack_outbuf + (j * BUF_JACK), sizeof (float) * nframes); + } + for (j = 0; j < sys_inchannels; j++) { + in = jack_port_get_buffer( input_port[j], nframes); + memcpy(jack_inbuf + (j * BUF_JACK), in, sizeof (float) * nframes); + } + jack_filled -= nframes; + } else { /* PD could not keep up ! */ + if (jack_started) sys_log_error(ERR_RESYNC); + for (j = 0; j < sys_outchannels; j++) { + out = jack_port_get_buffer (output_port[j], nframes); + memset(out, 0, sizeof (float) * nframes); + } + memset(jack_outbuf,0,sizeof(jack_outbuf)); + jack_filled = 0; + } + pthread_cond_broadcast(&jack_sem); + return 0; +} + +static int +srate (jack_nframes_t srate, void *arg) +{ + printf ("jack: sample rate %ld/sec\n", srate); + sys_dacsr = srate; + return 0; +} + +static void +jack_shutdown (void *arg) +{ + /* Ignore for now */ + // exit (1); +} + +static int jack_xrun(void* arg) { + sys_log_error(ERR_DACSLEPT); + return 0; +} + + +static char** jack_get_clients(void) +{ + const char **jack_ports; + int i,j; + int num_clients = 0; + regex_t port_regex; + jack_ports = jack_get_ports( jack_client, "", "", 0 ); + regcomp( &port_regex, "^[^:]*", REG_EXTENDED ); + + jack_client_names[0] = NULL; + + /* Build a list of clients from the list of ports */ + for( i = 0; jack_ports[i] != NULL; i++ ) + { + int client_seen; + regmatch_t match_info; + char tmp_client_name[100]; + + /* extract the client name from the port name, using a regex + * that parses the clientname:portname syntax */ + regexec( &port_regex, jack_ports[i], 1, &match_info, 0 ); + memcpy( tmp_client_name, &jack_ports[i][match_info.rm_so], + match_info.rm_eo - match_info.rm_so ); + tmp_client_name[ match_info.rm_eo - match_info.rm_so ] = '\0'; + + /* do we know about this port's client yet? */ + client_seen = 0; + + for( j = 0; j < num_clients; j++ ) + if( strcmp( tmp_client_name, jack_client_names[j] ) == 0 ) + client_seen = 1; + + if( client_seen == 0 ) + { + jack_client_names[num_clients] = (char*)getbytes(strlen(tmp_client_name) + 1); + + /* The alsa_pcm client should go in spot 0. If this + * is the alsa_pcm client AND we are NOT about to put + * it in spot 0 put it in spot 0 and move whatever + * was already in spot 0 to the end. */ + + if( strcmp( "alsa_pcm", tmp_client_name ) == 0 && num_clients > 0 ) + { + char* tmp; + /* alsa_pcm goes in spot 0 */ + tmp = jack_client_names[ num_clients ]; + jack_client_names[ num_clients ] = jack_client_names[0]; + jack_client_names[0] = tmp; + strcpy( jack_client_names[0], tmp_client_name); + } + else + { + /* put the new client at the end of the client list */ + strcpy( jack_client_names[ num_clients ], tmp_client_name ); + } + num_clients++; + + } + } + + /* for (i=0;i 96) return -1; + + sprintf( regex_pattern, "%s:.*", client ); + + jack_ports = jack_get_ports( jack_client, regex_pattern, + NULL, JackPortIsOutput); + if (jack_ports) + for (i=0;jack_ports[i] != NULL && i < sys_inchannels;i++) + if (jack_connect (jack_client, jack_ports[i], jack_port_name (input_port[i]))) + fprintf (stderr, "cannot connect input ports %s -> %s\n", jack_ports[i],jack_port_name (input_port[i])); + + + + jack_ports = jack_get_ports( jack_client, regex_pattern, + NULL, JackPortIsInput); + if (jack_ports) + for (i=0;jack_ports[i] != NULL && i < sys_outchannels;i++) + if (jack_connect (jack_client, jack_port_name (output_port[i]), jack_ports[i])) + fprintf (stderr, "cannot connect output ports %s -> %s\n", jack_port_name (output_port[i]),jack_ports[i]); + + + + free(jack_ports); + return 0; +} + + +void jack_error(const char *desc) { + return; +} + + +int +jack_open_audio(int inchans, int outchans, int rate) + +{ + int j; + char port_name[80] = ""; + int samplerate; + int client_iterator = 0; + + if ((inchans == 0) && (outchans == 0)) return 0; + + post("Testing for Jack"); + if (outchans > NUM_JACK_PORTS) { + fprintf(stderr,"%d output ports not supported, setting to %d\n",outchans, NUM_JACK_PORTS); + outchans = NUM_JACK_PORTS; + } + + if (inchans > NUM_JACK_PORTS) { + fprintf(stderr,"%d input ports not supported, setting to %d\n",inchans, NUM_JACK_PORTS); + inchans = NUM_JACK_PORTS; + } + + /* try to become a client of the JACK server (we allow two pd's)*/ + + do { + sprintf(port_name,"pure_data_%d",client_iterator); + client_iterator++; + } + while (((jack_client = jack_client_new (port_name)) == 0) && client_iterator < 2); + + if (!jack_client) { // jack spits out enough messages already, do not warn + return 1; + } + + jack_get_clients(); + + /* tell the JACK server to call `process()' whenever + there is work to be done. + */ + + jack_set_process_callback (jack_client, process, 0); + + jack_set_error_function (jack_error); + +#ifdef JACK_XRUN + jack_set_xrun_callback (jack_client, jack_xrun, NULL); +#endif + + /* tell the JACK server to call `srate()' whenever + the sample rate of the system changes. + */ + + jack_set_sample_rate_callback (jack_client, srate, 0); + + + /* tell the JACK server to call `jack_shutdown()' if + it ever shuts down, either entirely, or if it + just decides to stop calling us. + */ + + jack_on_shutdown (jack_client, jack_shutdown, 0); + + + /* display the current sample rate. once the client is activated + (see below), you should rely on your own sample rate + callback (see above) for this value. + */ + + samplerate = jack_get_sample_rate (jack_client); + + /* create the ports */ + + for (j = 0; j < inchans; j++) { + sprintf(port_name, "input%d", j); + input_port[j] = jack_port_register (jack_client, port_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); + } + for (j = 0; j < outchans; j++) { + sprintf(port_name, "output%d", j); + output_port[j] = jack_port_register (jack_client, port_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); + } + + /* tell the JACK server that we are ready to roll */ + + if (jack_activate (jack_client)) { + fprintf (stderr, "cannot activate client"); + return 1; + } + + memset(jack_outbuf,0,sizeof(jack_outbuf)); + + if (jack_client_names[0]) + jack_connect_ports(jack_client_names[0]); + + pthread_mutex_init(&jack_mutex,NULL); + pthread_cond_init(&jack_sem,NULL); + + post("using JACK audio interface"); + return 0; +} + +void jack_close_audio(void) + +{ + jack_started = 0; + /* ignore for now */ +} + +int jack_send_dacs(void) + +{ + float * fp; + int j; + int rtnval = SENDDACS_YES; + int timenow; + int timeref = sys_getrealtime(); + + if (!jack_client) return SENDDACS_NO; + + if (!sys_inchannels && !sys_outchannels) return (SENDDACS_NO); + + if (jack_filled >= jack_out_max) + pthread_cond_wait(&jack_sem,&jack_mutex); + + jack_started = 1; + + fp = sys_soundout; + for (j = 0; j < sys_outchannels; j++) { + memcpy(jack_outbuf + (j * BUF_JACK) + jack_filled,fp, DEFDACBLKSIZE*sizeof(float)); + fp += DEFDACBLKSIZE; + } + fp = sys_soundin; + for (j = 0; j < sys_inchannels; j++) { + memcpy(fp, jack_inbuf + (j * BUF_JACK) + jack_filled, DEFDACBLKSIZE*sizeof(float)); + fp += DEFDACBLKSIZE; + } + + if ((timenow = sys_getrealtime()) - timeref > 0.002) + { + rtnval = SENDDACS_SLEPT; + } + + memset(sys_soundout,0,DEFDACBLKSIZE*sizeof(float)*sys_outchannels); + jack_filled += DEFDACBLKSIZE; + return rtnval; +} + +void jack_listdevs( void) +{ + post("device listing not implemented for jack yet\n"); +} + +#endif /* JACK */ diff --git a/pd/src/s_audio_mmio.c b/pd/src/s_audio_mmio.c index d0657be4..9c088574 100644 --- a/pd/src/s_audio_mmio.c +++ b/pd/src/s_audio_mmio.c @@ -26,7 +26,8 @@ static void postflags(void); #define DEFAULTSRATE 44100 #define SAMPSIZE 2 -#define REALDACBLKSIZE (4 * DEFDACBLKSIZE) /* larger underlying bufsize */ +int nt_realdacblksize; +#define DEFREALDACBLKSIZE (4 * DEFDACBLKSIZE) /* larger underlying bufsize */ #define MAXBUFFER 100 /* number of buffers in use at maximum advance */ #define DEFBUFFER 30 /* default is about 30x6 = 180 msec! */ @@ -83,7 +84,7 @@ static void wave_prep(t_sbuf *bp) if (!(bp->hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, - (DWORD) (CHANNELS_PER_DEVICE * REALDACBLKSIZE * SAMPSIZE)))) + (DWORD) (CHANNELS_PER_DEVICE * SAMPSIZE * nt_realdacblksize)))) printf("alloc 1 failed\n"); if (!(bp->lpData = @@ -100,12 +101,12 @@ static void wave_prep(t_sbuf *bp) (WAVEHDR *) GlobalLock(bp->hWaveHdr))) printf("lock 2 failed\n"); - for (i = CHANNELS_PER_DEVICE * REALDACBLKSIZE, + for (i = CHANNELS_PER_DEVICE * nt_realdacblksize, sp = (short *)bp->lpData; i--; ) *sp++ = 0; wh->lpData = bp->lpData; - wh->dwBufferLength = (CHANNELS_PER_DEVICE * REALDACBLKSIZE * SAMPSIZE); + wh->dwBufferLength = (CHANNELS_PER_DEVICE * SAMPSIZE * nt_realdacblksize); wh->dwFlags = 0; wh->dwLoops = 0L; wh->lpNext = 0; @@ -273,7 +274,7 @@ static void nt_midisync(void) if (initsystime == -1) nt_resetmidisync(); jittersec = (nt_dacjitterbufsallowed > nt_adcjitterbufsallowed ? nt_dacjitterbufsallowed : nt_adcjitterbufsallowed) - * REALDACBLKSIZE / sys_getsr(); + * nt_realdacblksize / sys_getsr(); diff = sys_getrealtime() - 0.001 * clock_gettimesince(initsystime); if (diff > nt_hibuftime) nt_hibuftime = diff; if (diff < nt_hibuftime - jittersec) @@ -436,7 +437,7 @@ static void nt_resyncaudio(void) outwavehdr, sizeof(WAVEHDR)); outwavehdr->dwFlags = 0L; memset((char *)(ntsnd_outvec[nda][phase].lpData), - 0, (CHANNELS_PER_DEVICE * REALDACBLKSIZE * SAMPSIZE)); + 0, (CHANNELS_PER_DEVICE * SAMPSIZE * nt_realdacblksize)); waveOutPrepareHeader(ntsnd_outdev[nda], outwavehdr, sizeof(WAVEHDR)); mmresult = waveOutWrite(ntsnd_outdev[nda], outwavehdr, @@ -598,7 +599,7 @@ int mmio_send_dacs(void) } nt_fill = nt_fill + DEFDACBLKSIZE; - if (nt_fill == REALDACBLKSIZE) + if (nt_fill == nt_realdacblksize) { nt_fill = 0; @@ -692,11 +693,12 @@ void mmio_open_audio(int naudioindev, int *audioindev, { int nbuf; - nbuf = sys_advance_samples/REALDACBLKSIZE; + nt_realdacblksize = (sys_blocksize ? sys_blocksize : DEFREALDACBLKSIZE); + nbuf = sys_advance_samples/nt_realdacblksize; if (nbuf >= MAXBUFFER) { fprintf(stderr, "pd: audio buffering maxed out to %d\n", - (int)(MAXBUFFER * ((REALDACBLKSIZE * 1000.)/44100.))); + (int)(MAXBUFFER * ((nt_realdacblksize * 1000.)/44100.))); nbuf = MAXBUFFER; } else if (nbuf < 4) nbuf = 4; @@ -710,13 +712,9 @@ void mmio_open_audio(int naudioindev, int *audioindev, nt_nwavein = sys_inchannels / 2; nt_nwaveout = sys_outchannels / 2; nt_whichadc = (naudioindev < 1 ? - (nt_nwavein > 1 ? WAVE_MAPPER : -1) : - (audioindev[0] == DEFAULTAUDIODEV ? WAVE_MAPPER : - audioindev[0] - 1)); + (nt_nwavein > 1 ? WAVE_MAPPER : -1) : audioindev[0]); nt_whichdac = (naudiooutdev < 1 ? - (nt_nwaveout > 1 ? WAVE_MAPPER : -1) : - (audiooutdev[0] == DEFAULTAUDIODEV ? WAVE_MAPPER : - audiooutdev[0] - 1)); + (nt_nwaveout > 1 ? WAVE_MAPPER : -1) : audiooutdev[0]); if (naudiooutdev > 1 || naudioindev > 1) post("separate audio device choice not supported; using sequential devices."); mmio_do_open_audio(); @@ -727,7 +725,7 @@ void mmio_reportidle(void) { } - +#if 0 /* list the audio and MIDI device names */ void mmio_listdevs(void) { @@ -756,3 +754,34 @@ void mmio_listdevs(void) "audio output device #%d: %s\n", i+1, wocap.szPname); } } +#endif + +void mmio_getdevs(char *indevlist, int *nindevs, + char *outdevlist, int *noutdevs, int *canmulti, + int maxndev, int devdescsize) +{ + int wRtn, ndev, i; + + *canmulti = 2; /* supports multiple devices */ + ndev = waveInGetNumDevs(); + if (ndev > maxndev) + ndev = maxndev; + *nindevs = ndev; + for (i = 0; i < ndev; i++) + { + WAVEINCAPS wicap; + wRtn = waveInGetDevCaps(i, (LPWAVEINCAPS) &wicap, sizeof(wicap)); + sprintf(indevlist + i * devdescsize, (wRtn ? "???" : wicap.szPname)); + } + + ndev = waveOutGetNumDevs(); + if (ndev > maxndev) + ndev = maxndev; + *noutdevs = ndev; + for (i = 0; i < ndev; i++) + { + WAVEOUTCAPS wocap; + wRtn = waveOutGetDevCaps(i, (LPWAVEOUTCAPS) &wocap, sizeof(wocap)); + sprintf(outdevlist + i * devdescsize, (wRtn ? "???" : wocap.szPname)); + } +} diff --git a/pd/src/s_audio_oss.c b/pd/src/s_audio_oss.c index 382e6a75..b612b458 100644 --- a/pd/src/s_audio_oss.c +++ b/pd/src/s_audio_oss.c @@ -78,25 +78,37 @@ static char ossdsp[] = "/dev/dsp%d"; #define FMAX 0x7ffff000 #define CLIP32(x) (((x)>FMAX)?FMAX:((x) < -FMAX)?-FMAX:(x)) +/* ---------------- public routines ----------------------- */ -/* ------------- private routines for all APIS ------------------- */ +static int oss_ndev = 0; -static void linux_flush_all_underflows_to_zero(void) + /* find out how many OSS devices we have. Since this has to + open the devices to find out if they're there, we have + to be called before audio is actually started up. So we + cache the results, which in effect are the number of available + devices. */ +void oss_init(void) { -/* - TODO: Implement similar thing for linux (GGeiger) - - One day we will figure this out, I hope, because it - costs CPU time dearly on Intel - LT - */ - /* union fpc_csr f; - f.fc_word = get_fpc_csr(); - f.fc_struct.flush = 1; - set_fpc_csr(f.fc_word); - */ + int fd, i; + static int countedthem = 0; + if (countedthem) + return; + for (i = 0; i < 10; i++) + { + char devname[100]; + if (i == 0) + strcpy(devname, "/dev/dsp"); + else sprintf(devname, "/dev/dsp%d", i); + if ( (fd = open(devname, O_WRONLY|O_NONBLOCK)) != -1) + { + oss_ndev++; + close(fd); + } + else break; + } + countedthem = 1; } - void oss_set32bit( void) { oss_32bit = 1; @@ -172,11 +184,12 @@ void oss_configure(t_oss_dev *dev, int srate, int dac, int skipblocksize) { int fragbytes, logfragsize, nfragment; /* setting fragment count and size. */ + linux_fragsize = sys_blocksize; if (!linux_fragsize) { linux_fragsize = OSS_DEFFRAGSIZE; while (linux_fragsize > DEFDACBLKSIZE - && linux_fragsize * 4 > sys_advance_samples) + && linux_fragsize * 6 > sys_advance_samples) linux_fragsize = linux_fragsize/2; } /* post("adv_samples %d", sys_advance_samples); */ @@ -239,14 +252,14 @@ static int oss_setchannels(int fd, int wantchannels, char *devname) { /* IOhannes */ int param = wantchannels; - while (param>1) { - int save = param; - if (ioctl(fd, SNDCTL_DSP_CHANNELS, ¶m) == -1) { - error("OSS: SNDCTL_DSP_CHANNELS failed %s",devname); - } else { - if (param == save) return (param); - } - param=save-1; + while (param > 1) + { + int save = param; + if (ioctl(fd, SNDCTL_DSP_CHANNELS, ¶m) == -1) + error("OSS: SNDCTL_DSP_CHANNELS failed %s",devname); + else if (param == save) + return (param); + param = save - 1; } return (0); @@ -268,11 +281,9 @@ int oss_open_audio(int nindev, int *indev, int nchin, int *chin, audio_buf_info ainfo; linux_nindevs = linux_noutdevs = 0; - - - /* mark input devices unopened */ + /* mark devices unopened */ for (i = 0; i < OSS_MAXDEV; i++) - linux_adcs[i].d_fd = -1; + linux_adcs[i].d_fd = linux_dacs[i].d_fd = -1; /* open output devices */ wantmore=0; @@ -282,16 +293,15 @@ int oss_open_audio(int nindev, int *indev, int nchin, int *chin, for (n = 0; n < noutdev; n++) { int gotchans, j, inindex = -1; - int thisdevice = (outdev[n] >= 0 ? outdev[n] : n-1); + int thisdevice = (outdev[n] >= 0 ? outdev[n] : 0); int wantchannels = (nchout>n) ? chout[n] : wantmore; fd = -1; if (!wantchannels) goto end_out_loop; - if (thisdevice > 1) - sprintf(devname, "/dev/dsp%d", thisdevice-1); + if (thisdevice > 0) + sprintf(devname, "/dev/dsp%d", thisdevice); else sprintf(devname, "/dev/dsp"); - /* search for input request for same device. Succeed only if the number of channels matches. */ for (j = 0; j < nindev; j++) @@ -369,14 +379,14 @@ int oss_open_audio(int nindev, int *indev, int nchin, int *chin, for (n = 0; n < nindev; n++) { int gotchans=0; - int thisdevice = (indev[n] >= 0 ? indev[n] : n-1); + int thisdevice = (indev[n] >= 0 ? indev[n] : 0); int wantchannels = (nchin>n)?chin[n]:wantmore; int alreadyopened = 0; if (!wantchannels) goto end_in_loop; - if (thisdevice > 1) - sprintf(devname, "/dev/dsp%d", thisdevice - 1); + if (thisdevice > 0) + sprintf(devname, "/dev/dsp%d", thisdevice); else sprintf(devname, "/dev/dsp"); sys_setalarm(1000000); @@ -399,12 +409,13 @@ int oss_open_audio(int nindev, int *indev, int nchin, int *chin, post("opened %s for reading only\n", devname); } linux_adcs[linux_nindevs].d_fd = fd; + gotchans = oss_setchannels(fd, (wantchannels>OSS_MAXCHPERDEV)?OSS_MAXCHPERDEV:wantchannels, devname); if (sys_verbose) - post("opened audio input device %s; got %d channels", - devname, gotchans); + post("opened audio input device %s; got %d channels", + devname, gotchans); if (gotchans < 1) { @@ -441,6 +452,17 @@ int oss_open_audio(int nindev, int *indev, int nchin, int *chin, linux_adcs[0].d_nchannels * DEFDACBLKSIZE); if (sys_verbose) fprintf(stderr, "...done.\n"); + } + /* now go and fill all the output buffers. */ + for (i = 0; i < linux_noutdevs; i++) + { + int j; + memset(buf, 0, linux_dacs[i].d_bytespersamp * + linux_dacs[i].d_nchannels * DEFDACBLKSIZE); + for (j = 0; j < sys_advance_samples/DEFDACBLKSIZE; j++) + write(linux_dacs[i].d_fd, buf, + linux_dacs[i].d_bytespersamp * + linux_dacs[i].d_nchannels * DEFDACBLKSIZE); } sys_setalarm(0); return (0); @@ -765,8 +787,18 @@ int oss_send_dacs(void) return (rtnval); } -void oss_listdevs( void) +void oss_getdevs(char *indevlist, int *nindevs, + char *outdevlist, int *noutdevs, int *canmulti, + int maxndev, int devdescsize) { - post("device listing not implemented in OSS yet\n"); + int i, ndev; + *canmulti = 2; /* supports multiple devices */ + if ((ndev = oss_ndev) > maxndev) + ndev = maxndev; + for (i = 0; i < ndev; i++) + { + sprintf(indevlist + i * devdescsize, "OSS device #%d", i+1); + sprintf(outdevlist + i * devdescsize, "OSS device #%d", i+1); + } + *nindevs = *noutdevs = ndev; } - diff --git a/pd/src/s_audio_pa.c b/pd/src/s_audio_pa.c index 253b33cd..85f6252e 100644 --- a/pd/src/s_audio_pa.c +++ b/pd/src/s_audio_pa.c @@ -14,7 +14,10 @@ #include "portaudio.h" #include "pablio_pd.h" -#ifdef MACOSX + /* LATER try to figure out how to handle default devices in portaudio; + the way s_audio.c handles them isn't going to work here. */ + +#if defined(MACOSX) || defined(MSW) #define Pa_GetDefaultInputDevice Pa_GetDefaultInputDeviceID #define Pa_GetDefaultOutputDevice Pa_GetDefaultOutputDeviceID #endif @@ -35,7 +38,8 @@ int pa_open_audio(int inchans, int outchans, int rate, t_sample *soundin, { PaError err; static int initialized; - + int j, devno, pa_indev = 0, pa_outdev = 0; + if (!initialized) { /* Initialize PortAudio */ @@ -53,9 +57,6 @@ int pa_open_audio(int inchans, int outchans, int rate, t_sample *soundin, /* post("in %d out %d rate %d device %d", inchans, outchans, rate, deviceno); */ if (inchans != 0 && outchans != 0 && inchans != outchans) error("portaudio: number of input and output channels must match"); - if (sys_verbose) - post("portaudio: opening for %d channels in, %d out", - inchans, outchans); if (inchans > MAX_PA_CHANS) { post("input channels reduced to maximum %d", MAX_PA_CHANS); @@ -66,25 +67,59 @@ int pa_open_audio(int inchans, int outchans, int rate, t_sample *soundin, post("output channels reduced to maximum %d", MAX_PA_CHANS); outchans = MAX_PA_CHANS; } - if (indeviceno < 0) - indeviceno = Pa_GetDefaultInputDevice(); - if (outdeviceno < 0) - outdeviceno = Pa_GetDefaultOutputDevice(); - - fprintf(stderr, "input device %d, output device %d\n", - indeviceno, outdeviceno); + + if (inchans > 0) + { + for (j = 0, devno = 0; j < Pa_CountDevices(); j++) + { + const PaDeviceInfo *info = Pa_GetDeviceInfo(j); + if (info->maxInputChannels > 0) + { + if (devno == indeviceno) + { + pa_indev = j; + break; + } + devno++; + } + } + } + + if (outchans > 0) + { + for (j = 0, devno = 0; j < Pa_CountDevices(); j++) + { + const PaDeviceInfo *info = Pa_GetDeviceInfo(j); + if (info->maxOutputChannels > 0) + { + if (devno == outdeviceno) + { + pa_outdev = j; + break; + } + devno++; + } + } + } + + if (sys_verbose) + { + post("input device %d, channels %d", pa_indev, inchans); + post("output device %d, channels %d", pa_outdev, outchans); + post("framesperbuf %d, nbufs %d", framesperbuf, nbuffers); + } if (inchans && outchans) err = OpenAudioStream( &pa_stream, rate, paFloat32, PABLIO_READ_WRITE, inchans, framesperbuf, nbuffers, - indeviceno, outdeviceno); + pa_indev, pa_outdev); else if (inchans) err = OpenAudioStream( &pa_stream, rate, paFloat32, PABLIO_READ, inchans, framesperbuf, nbuffers, - indeviceno, outdeviceno); + pa_indev, pa_outdev); else if (outchans) err = OpenAudioStream( &pa_stream, rate, paFloat32, PABLIO_WRITE, outchans, framesperbuf, nbuffers, - indeviceno, outdeviceno); + pa_indev, pa_outdev); else err = 0; if ( err != paNoError ) { @@ -117,9 +152,36 @@ int pa_send_dacs(void) double timebefore; timebefore = sys_getrealtime(); + if ((pa_inchans && GetAudioStreamReadable(pa_stream) < DEFDACBLKSIZE) || + (pa_outchans && GetAudioStreamWriteable(pa_stream) < DEFDACBLKSIZE)) + { + if (pa_inchans && pa_outchans) + { + int synced = 0; + while (GetAudioStreamWriteable(pa_stream) > 2*DEFDACBLKSIZE) + { + for (j = 0; j < pa_outchans; j++) + for (i = 0, fp2 = samples + j; i < DEFDACBLKSIZE; i++, + fp2 += pa_outchans) + { + *fp2 = 0; + } + synced = 1; + WriteAudioStream(pa_stream, samples, DEFDACBLKSIZE); + } + while (GetAudioStreamReadable(pa_stream) > 2*DEFDACBLKSIZE) + { + synced = 1; + ReadAudioStream(pa_stream, samples, DEFDACBLKSIZE); + } + /* if (synced) + post("sync"); */ + } + return (SENDDACS_NO); + } if (pa_inchans) { - ReadAudioStream(pa_stream, samples, DEFDACBLKSIZE); + ReadAudioStream(pa_stream, samples, DEFDACBLKSIZE); for (j = 0, fp1 = pa_soundin; j < pa_inchans; j++, fp1 += DEFDACBLKSIZE) for (i = 0, fp2 = samples + j; i < DEFDACBLKSIZE; i++, fp2 += pa_inchans) @@ -127,6 +189,18 @@ int pa_send_dacs(void) fp1[i] = *fp2; } } +#if 0 + { + static int nread; + if (nread == 0) + { + post("it's %f %f %f %f", + pa_soundin[0], pa_soundin[1], pa_soundin[2], pa_soundin[3]); + nread = 1000; + } + nread--; + } +#endif if (pa_outchans) { for (j = 0, fp1 = pa_soundout; j < pa_outchans; j++, @@ -141,7 +215,10 @@ int pa_send_dacs(void) } if (sys_getrealtime() > timebefore + 0.002) + { + /* post("slept"); */ return (SENDDACS_SLEPT); + } else return (SENDDACS_YES); } @@ -183,4 +260,32 @@ error: fprintf( stderr, "Error number: %d\n", err ); fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); +} + + /* scanning for devices */ +void pa_getdevs(char *indevlist, int *nindevs, + char *outdevlist, int *noutdevs, int *canmulti, + int maxndev, int devdescsize) +{ + int i, nin = 0, nout = 0, ndev; + *canmulti = 1; /* one dev each for input and output */ + + Pa_Initialize(); + ndev = Pa_CountDevices(); + for (i = 0; i < ndev; i++) + { + const PaDeviceInfo *pdi = Pa_GetDeviceInfo(i); + if (pdi->maxInputChannels > 0 && nin < maxndev) + { + strcpy(indevlist + nin * devdescsize, pdi->name); + nin++; + } + if (pdi->maxOutputChannels > 0 && nout < maxndev) + { + strcpy(outdevlist + nout * devdescsize, pdi->name); + nout++; + } + } + *nindevs = nin; + *noutdevs = nout; } diff --git a/pd/src/s_freebsd.c b/pd/src/s_freebsd.c deleted file mode 100644 index 4ed4241b..00000000 --- a/pd/src/s_freebsd.c +++ /dev/null @@ -1,3072 +0,0 @@ -/* Copyright (c) 1997-1999 Guenter Geiger, Miller Puckette, Larry Troxler, -* Winfried Ritsch, Karl MacMillan, and others. -* For information on usage and redistribution, and for a DISCLAIMER OF ALL -* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ - -/* this file implements the sys_ functions profiled in m_imp.h for - audio and MIDI I/O. In Linux there might be several APIs for doing the - audio part; right now there are three (OSS, ALSA, RME); the third is - for the RME 9652 driver by Ritsch (but not for the OSS compatible - one by Geiger; for that one, OSS should work.) - - FUNCTION PREFIXES. - sys_ -- functions which must be exported to Pd on all platforms - linux_ -- linux-specific objects which don't depend on API, - mostly static but some exported. - oss_, alsa_, rme_ -- API-specific functions, all of which are - static. - - ALSA SUPPORT. If ALSA99 is defined we support ALSA 0.5x; if ALSA01, - ALSA 0.9x. (the naming scheme reflects the possibility of further API - changes in the future...) We define "ALSA" for code relevant to both - APIs. - - For MIDI, we only offer the OSS API; ALSA has to emulate OSS for us. -*/ - -/* OSS include (whether we're doing OSS audio or not we need this for MIDI) */ - - -/* IOhannes::: - * hacked this to add advanced multidevice-support - * 1311:forum::für::umläute:2001 - */ - -#include - -#if (defined(ALSA01) || defined(ALSA99)) -#define ALSA -#endif - -#ifdef ALSA99 -#include -#endif -#ifdef ALSA01 -#include -#endif - -#include "m_imp.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* local function prototypes */ - -static void linux_close_midi( void); - -static int oss_open_audio(int naudioindev, int *audioindev, int nchindev, - int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev, - int *choutdev, int rate); /* IOhannes */ - -static void oss_close_audio(void); -static int oss_send_dacs(void); -static void oss_reportidle(void); - -#ifdef ALSA -typedef int16_t t_alsa_sample16; -typedef int32_t t_alsa_sample32; -#define ALSA_SAMPLEWIDTH_16 sizeof(t_alsa_sample16) -#define ALSA_SAMPLEWIDTH_32 sizeof(t_alsa_sample32) -#define ALSA_XFERSIZE16 (signed int)(sizeof(t_alsa_sample16) * DACBLKSIZE) -#define ALSA_XFERSIZE32 (signed int)(sizeof(t_alsa_sample32) * DACBLKSIZE) -#define ALSA_MAXDEV 1 -#define ALSA_JITTER 1024 -#define ALSA_EXTRABUFFER 2048 -#define ALSA_DEFFRAGSIZE 64 -#define ALSA_DEFNFRAG 12 - -#ifdef ALSA99 -typedef struct _alsa_dev -{ - snd_pcm_t *handle; - snd_pcm_channel_info_t info; - snd_pcm_channel_setup_t setup; -} t_alsa_dev; - -t_alsa_dev alsa_device[ALSA_MAXDEV]; -static int n_alsa_dev; -static char *alsa_buf; -static int alsa_samplewidth; -#endif /* ALSA99 */ - -#ifdef ALSA01 -typedef struct _alsa_dev -{ - snd_pcm_t *inhandle; - snd_pcm_t *outhandle; -} t_alsa_dev; - -t_alsa_dev alsa_device; -static short *alsa_buf; -static int alsa_samplewidth; -static snd_pcm_status_t* in_status; -static snd_pcm_status_t* out_status; -#endif /* ALSA01 */ - -#if 0 /* early alsa 0.9 beta dists had different names for these: */ -#define SND_PCM_ACCESS_RW_INTERLEAVED SNDRV_PCM_ACCESS_RW_INTERLEAVED -#define SND_PCM_FORMAT_S32 SNDRV_PCM_FORMAT_S32 -#define SND_PCM_FORMAT_S16 SNDRV_PCM_FORMAT_S16 -#define SND_PCM_SUBFORMAT_STD SNDRV_PCM_SUBFORMAT_STD -#endif - -static int alsa_mode; -static int alsa_open_audio(int inchans, int outchans, int rate); -static void alsa_close_audio(void); -static int alsa_send_dacs(void); -static void alsa_set_params(t_alsa_dev *dev, int dir, int rate, int voices); -static void alsa_reportidle(void); -#endif /* ALSA */ - -#ifdef RME_HAMMERFALL -static int rme9652_open_audio(int inchans, int outchans, int rate); -static void rme9652_close_audio(void); -static int rme9652_send_dacs(void); -static void rme9652_reportidle(void); -#endif /* RME_HAMMERFALL */ - -/* Defines */ -#define DEBUG(x) x -#define DEBUG2(x) {x;} - -#define OSS_MAXCHPERDEV 32 /* max channels per OSS device */ -#define OSS_MAXDEV 4 /* maximum number of input or output devices */ -#define OSS_DEFFRAGSIZE 256 /* default log fragment size (frames) */ -#define OSS_DEFAUDIOBUF 40000 /* default audiobuffer, microseconds */ -#define OSS_DEFAULTCH 2 -#define RME_DEFAULTCH 8 /* need this even if RME undefined */ -typedef int16_t t_oss_int16; -typedef int32_t t_oss_int32; -#define OSS_MAXSAMPLEWIDTH sizeof(t_oss_int32) -#define OSS_BYTESPERCHAN(width) (DACBLKSIZE * (width)) -#define OSS_XFERSAMPS(chans) (DACBLKSIZE* (chans)) -#define OSS_XFERSIZE(chans, width) (DACBLKSIZE * (chans) * (width)) - -#ifdef RME_HAMMERFALL -typedef int32_t t_rme_sample; -#define RME_SAMPLEWIDTH sizeof(t_rme_sample) -#define RME_BYTESPERCHAN (DACBLKSIZE * RME_SAMPLEWIDTH) -#endif /* RME_HAMMERFALL */ - -/* GLOBALS */ -static int linux_whichapi = API_OSS; -static int linux_inchannels; -static int linux_outchannels; -static int linux_advance_samples; /* scheduler advance in samples */ -static int linux_meters; /* true if we're metering */ -static float linux_inmax; /* max input amplitude */ -static float linux_outmax; /* max output amplitude */ -static int linux_fragsize = 0; /* for block mode; block size (sample frames) */ -static int linux_nfragment = 0; /* ... and number of blocks. */ - -#ifdef ALSA99 -static int alsa_devno = 1; -#endif -#ifdef ALSA01 -static char alsa_devname[512] = "hw:0,0"; -static int alsa_use_plugin = 0; -#endif - -/* our device handles */ - -typedef struct _oss_dev -{ - int d_fd; - unsigned int d_space; /* bytes available for writing/reading */ - int d_bufsize; /* total buffer size in blocks for this device */ - int d_dropcount; /* # of buffers to drop for resync (output only) */ - unsigned int d_nchannels; /* number of channels for this device */ - unsigned int d_bytespersamp; /* bytes per sample (2 for 16 bit, 4 for 32) */ -} t_oss_dev; - -static t_oss_dev linux_dacs[OSS_MAXDEV]; -static t_oss_dev linux_adcs[OSS_MAXDEV]; -static int linux_noutdevs = 0; -static int linux_nindevs = 0; - - /* exported variables */ -int sys_schedadvance = OSS_DEFAUDIOBUF; /* scheduler advance in microsecs */ -float sys_dacsr; -int sys_hipriority = 0; -t_sample *sys_soundout; -t_sample *sys_soundin; - - /* OSS-specific private variables */ -static int oss_blockmode = 1; /* flag to use "blockmode" */ -static char ossdsp[] = "/dev/dsp%d"; - -#ifndef INT32_MAX -#define INT32_MAX 0x7fffffff -#endif -#define CLIP32(x) (((x)>INT32_MAX)?INT32_MAX:((x) < -INT32_MAX)?-INT32_MAX:(x)) - - -/* ------------- private routines for all APIS ------------------- */ - -static void linux_flush_all_underflows_to_zero(void) -{ -/* - TODO: Implement similar thing for linux (GGeiger) - - One day we will figure this out, I hope, because it - costs CPU time dearly on Intel - LT - */ - /* union fpc_csr f; - f.fc_word = get_fpc_csr(); - f.fc_struct.flush = 1; - set_fpc_csr(f.fc_word); - */ -} - - /* set sample rate and channels. Must set sample rate before "configuring" - any devices so we know scheduler advance in samples. */ - -static void linux_setsr(int sr) -{ - sys_dacsr = sr; - linux_advance_samples = (sys_schedadvance * sys_dacsr) / (1000000.); - if (linux_advance_samples < 3 * DACBLKSIZE) - linux_advance_samples = 3 * DACBLKSIZE; -} - -static void linux_setch(int chin, int chout) -{ - int nblk; - int inbytes = chin * (DACBLKSIZE*sizeof(float)); - int outbytes = chout * (DACBLKSIZE*sizeof(float)); - - linux_inchannels = chin; - linux_outchannels = chout; - if (sys_soundin) - free(sys_soundin); - sys_soundin = (t_float *)malloc(inbytes); - memset(sys_soundin, 0, inbytes); - - if (sys_soundout) - free(sys_soundout); - sys_soundout = (t_float *)malloc(outbytes); - memset(sys_soundout, 0, outbytes); - - if (sys_verbose) - post("input channels = %d, output channels = %d", - linux_inchannels, linux_outchannels); -} - -/* ---------------- MIDI routines -------------------------- */ - -static int oss_nmidiin; -static int oss_midiinfd[MAXMIDIINDEV]; -static int oss_nmidiout; -static int oss_midioutfd[MAXMIDIOUTDEV]; - -static void oss_midiout(int fd, int n) -{ - char b = n; - if ((write(fd, (char *) &b, 1)) != 1) - perror("midi write"); -} - -#define O_MIDIFLAG O_NDELAY - -void linux_open_midi(int nmidiin, int *midiinvec, int nmidiout, int *midioutvec) -{ - int i; - for (i = 0; i < nmidiout; i++) - oss_midioutfd[i] = -1; - for (i = 0, oss_nmidiin = 0; i < nmidiin; i++) - { - int fd = -1, j, outdevindex = -1; - char namebuf[80]; - int devno = midiinvec[i]; - - for (j = 0; j < nmidiout; j++) - if (midioutvec[j] == midiinvec[i]) - outdevindex = j; - - /* try to open the device for read/write. */ - if (devno == 1 && fd < 0 && outdevindex >= 0) - { - sys_setalarm(1000000); - fd = open("/dev/midi", O_RDWR | O_MIDIFLAG); - if (sys_verbose) - fprintf(stderr, - "device 1: tried /dev/midi READ/WRITE; returned %d\n", fd); - if (outdevindex >= 0 && fd >= 0) - oss_midioutfd[outdevindex] = fd; - } - if (fd < 0 && outdevindex >= 0) - { - sys_setalarm(1000000); - sprintf(namebuf, "/dev/midi%2.2d", devno-1); - fd = open(namebuf, O_RDWR | O_MIDIFLAG); - if (sys_verbose) - fprintf(stderr, - "device %d: tried %s READ/WRITE; returned %d\n", - devno, namebuf, fd); - if (outdevindex >= 0 && fd >= 0) - oss_midioutfd[outdevindex] = fd; - } - if (fd < 0 && outdevindex >= 0) - { - sys_setalarm(1000000); - sprintf(namebuf, "/dev/midi%d", devno-1); - fd = open(namebuf, O_RDWR | O_MIDIFLAG); - if (sys_verbose) - fprintf(stderr, "device %d: tried %s READ/WRITE; returned %d\n", - devno, namebuf, fd); - if (outdevindex >= 0 && fd >= 0) - oss_midioutfd[outdevindex] = fd; - } - if (devno == 1 && fd < 0) - { - sys_setalarm(1000000); - fd = open("/dev/midi", O_RDONLY | O_MIDIFLAG); - if (sys_verbose) - fprintf(stderr, - "device 1: tried /dev/midi READONLY; returned %d\n", fd); - } - if (fd < 0) - { - sys_setalarm(1000000); - sprintf(namebuf, "/dev/midi%2.2d", devno-1); - fd = open(namebuf, O_RDONLY | O_MIDIFLAG); - if (sys_verbose) - fprintf(stderr, "device %d: tried %s READONLY; returned %d\n", - devno, namebuf, fd); - } - if (fd < 0) - { - sys_setalarm(1000000); - sprintf(namebuf, "/dev/midi%d", devno-1); - fd = open(namebuf, O_RDONLY | O_MIDIFLAG); - if (sys_verbose) - fprintf(stderr, "device %d: tried %s READONLY; returned %d\n", - devno, namebuf, fd); - } - if (fd >= 0) - oss_midiinfd[oss_nmidiin++] = fd; - else post("couldn't open MIDI input device %d", devno); - } - for (i = 0, oss_nmidiout = 0; i < nmidiout; i++) - { - int fd = oss_midioutfd[i]; - char namebuf[80]; - int devno = midioutvec[i]; - if (devno == 1 && fd < 0) - { - sys_setalarm(1000000); - fd = open("/dev/midi", O_WRONLY | O_MIDIFLAG); - if (sys_verbose) - fprintf(stderr, - "device 1: tried /dev/midi WRITEONLY; returned %d\n", fd); - } - if (fd < 0) - { - sys_setalarm(1000000); - sprintf(namebuf, "/dev/midi%2.2d", devno-1); - fd = open(namebuf, O_WRONLY | O_MIDIFLAG); - if (sys_verbose) - fprintf(stderr, "device %d: tried %s WRITEONLY; returned %d\n", - devno, namebuf, fd); - } - if (fd < 0) - { - sys_setalarm(1000000); - sprintf(namebuf, "/dev/midi%d", devno-1); - fd = open(namebuf, O_WRONLY | O_MIDIFLAG); - if (sys_verbose) - fprintf(stderr, "device %d: tried %s WRITEONLY; returned %d\n", - devno, namebuf, fd); - } - if (fd >= 0) - oss_midioutfd[oss_nmidiout++] = fd; - else post("couldn't open MIDI output device %d", devno); - } - - if (oss_nmidiin < nmidiin || oss_nmidiout < nmidiout || sys_verbose) - post("opened %d MIDI input device(s) and %d MIDI output device(s).", - oss_nmidiin, oss_nmidiout); -} - -#define md_msglen(x) (((x)<0xC0)?2:((x)<0xE0)?1:((x)<0xF0)?2:\ - ((x)==0xF2)?2:((x)<0xF4)?1:0) - -void sys_putmidimess(int portno, int a, int b, int c) -{ - if (portno >= 0 && portno < oss_nmidiout) - { - switch (md_msglen(a)) - { - case 2: - oss_midiout(oss_midioutfd[portno],a); - oss_midiout(oss_midioutfd[portno],b); - oss_midiout(oss_midioutfd[portno],c); - return; - case 1: - oss_midiout(oss_midioutfd[portno],a); - oss_midiout(oss_midioutfd[portno],b); - return; - case 0: - oss_midiout(oss_midioutfd[portno],a); - return; - }; - } -} - -void sys_putmidibyte(int portno, int byte) -{ - if (portno >= 0 && portno < oss_nmidiout) - oss_midiout(oss_midioutfd[portno], byte); -} - -#if 0 /* this is the "select" version which doesn't work with OSS - driver for emu10k1 (it doesn't implement select.) */ -void sys_poll_midi(void) -{ - int i, throttle = 100; - struct timeval timout; - int did = 1, maxfd = 0; - while (did) - { - fd_set readset, writeset, exceptset; - did = 0; - if (throttle-- < 0) - break; - timout.tv_sec = 0; - timout.tv_usec = 0; - - FD_ZERO(&writeset); - FD_ZERO(&readset); - FD_ZERO(&exceptset); - for (i = 0; i < oss_nmidiin; i++) - { - if (oss_midiinfd[i] > maxfd) - maxfd = oss_midiinfd[i]; - FD_SET(oss_midiinfd[i], &readset); - } - select(maxfd+1, &readset, &writeset, &exceptset, &timout); - for (i = 0; i < oss_nmidiin; i++) - if (FD_ISSET(oss_midiinfd[i], &readset)) - { - char c; - int ret = read(oss_midiinfd[i], &c, 1); - if (ret <= 0) - fprintf(stderr, "Midi read error\n"); - else sys_midibytein(i, (c & 0xff)); - did = 1; - } - } -} -#else - - /* this version uses the asynchronous "read()" ... */ -void sys_poll_midi(void) -{ - int i, throttle = 100; - struct timeval timout; - int did = 1, maxfd = 0; - while (did) - { - fd_set readset, writeset, exceptset; - did = 0; - if (throttle-- < 0) - break; - for (i = 0; i < oss_nmidiin; i++) - { - char c; - int ret = read(oss_midiinfd[i], &c, 1); - if (ret < 0) - { - if (errno != EAGAIN) - perror("MIDI"); - } - else if (ret != 0) - { - sys_midibytein(i, (c & 0xff)); - did = 1; - } - } - } -} -#endif - -void linux_close_midi() -{ - int i; - for (i = 0; i < oss_nmidiin; i++) - close(oss_midiinfd[i]); - for (i = 0; i < oss_nmidiout; i++) - close(oss_midioutfd[i]); - oss_nmidiin = oss_nmidiout = 0; -} - -#define MAXAUDIODEV 4 -#define DEFAULTINDEV 1 -#define DEFAULTOUTDEV 1 - -/* ----------------------- public routines ----------------------- */ -void sys_listdevs( void) -{ - post("device listing not implemented in Linux yet\n"); -} - -void sys_open_audio(int naudioindev, int *audioindev, int nchindev, - int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev, - int *choutdev, int rate) -{ /* IOhannes */ - int i, *ip; - int defaultchannels = - (linux_whichapi == API_RME ? RME_DEFAULTCH : OSS_DEFAULTCH); - if (rate < 1) - rate=44100; - - if (naudioindev == -1) - { /* not set */ - if (nchindev==-1) - { - nchindev=1; - chindev[0]=defaultchannels; - naudioindev=1; - audioindev[0] = DEFAULTINDEV; - } - else - { - for (i = 0; i < MAXAUDIODEV; i++) - audioindev[i]=i+1; - naudioindev = nchindev; - } - } - else - { - if (nchindev == -1) - { - nchindev = naudioindev; - for (i = 0; i < naudioindev; i++) - chindev[i] = defaultchannels; - } - else if (nchindev > naudioindev) - { - for (i = naudioindev; i < nchindev; i++) - { - if (i == 0) - audioindev[0] = DEFAULTINDEV; - else audioindev[i] = audioindev[i-1] + 1; - } - naudioindev = nchindev; - } - else if (nchindev < naudioindev) - { - for (i = nchindev; i < naudioindev; i++) - { - if (i == 0) - chindev[0] = defaultchannels; - else chindev[i] = chindev[i-1]; - } - naudioindev = nchindev; - } - } - - if (naudiooutdev == -1) - { /* not set */ - if (nchoutdev==-1) - { - nchoutdev=1; - choutdev[0]=defaultchannels; - naudiooutdev=1; - audiooutdev[0] = DEFAULTOUTDEV; - } - else - { - for (i = 0; i < MAXAUDIODEV; i++) - audiooutdev[i] = i+1; - naudiooutdev = nchoutdev; - } - } - else - { - if (nchoutdev == -1) - { - nchoutdev = naudiooutdev; - for (i = 0; i < naudiooutdev; i++) - choutdev[i] = defaultchannels; - } - else if (nchoutdev > naudiooutdev) - { - for (i = naudiooutdev; i < nchoutdev; i++) - { - if (i == 0) - audiooutdev[0] = DEFAULTOUTDEV; - else audiooutdev[i] = audiooutdev[i-1] + 1; - } - naudiooutdev = nchoutdev; - } - else if (nchoutdev < naudiooutdev) - { - for (i = nchoutdev; i < naudiooutdev; i++) - { - if (i == 0) - choutdev[0] = defaultchannels; - else choutdev[i] = choutdev[i-1]; - } - naudiooutdev = nchoutdev; - } - } - - linux_flush_all_underflows_to_zero(); -#ifdef ALSA - if (linux_whichapi == API_ALSA) - alsa_open_audio((naudioindev > 0 ? chindev[0] : 0), - (naudiooutdev > 0 ? choutdev[0] : 0), rate); - else -#endif -#ifdef RME_HAMMERFALL - if (linux_whichapi == API_RME) - rme9652_open_audio((naudioindev > 0 ? chindev[0] : 0), - (naudiooutdev > 0 ? choutdev[0] : 0), rate); - else -#endif - oss_open_audio(naudioindev, audioindev, nchindev, chindev, - naudiooutdev, audiooutdev, nchoutdev, choutdev, rate); -} - -void sys_close_audio(void) -{ - /* set timeout to avoid hanging close() call */ - - sys_setalarm(1000000); - -#ifdef ALSA - if (linux_whichapi == API_ALSA) - alsa_close_audio(); - else -#endif -#ifdef RME_HAMMERFALL - if (linux_whichapi == API_RME) - rme9652_close_audio(); - else -#endif - oss_close_audio(); - - sys_setalarm(0); -} - -void sys_open_midi(int nmidiin, int *midiinvec, - int nmidiout, int *midioutvec) -{ - linux_open_midi(nmidiin, midiinvec, nmidiout, midioutvec); -} - -void sys_close_midi( void) -{ - sys_setalarm(1000000); - linux_close_midi(); - sys_setalarm(0); -} - -int sys_send_dacs(void) -{ - if (linux_meters) - { - int i, n; - float maxsamp; - for (i = 0, n = linux_inchannels * DACBLKSIZE, maxsamp = linux_inmax; - i < n; i++) - { - float f = sys_soundin[i]; - if (f > maxsamp) maxsamp = f; - else if (-f > maxsamp) maxsamp = -f; - } - linux_inmax = maxsamp; - for (i = 0, n = linux_outchannels * DACBLKSIZE, maxsamp = linux_outmax; - i < n; i++) - { - float f = sys_soundout[i]; - if (f > maxsamp) maxsamp = f; - else if (-f > maxsamp) maxsamp = -f; - } - linux_outmax = maxsamp; - } -#ifdef ALSA - if (linux_whichapi == API_ALSA) - return alsa_send_dacs(); -#endif -#ifdef RME_HAMMERFALL - if (linux_whichapi == API_RME) - return rme9652_send_dacs(); -#endif - return oss_send_dacs(); -} - -float sys_getsr(void) -{ - return (sys_dacsr); -} - -int sys_get_outchannels(void) -{ - return (linux_outchannels); -} - -int sys_get_inchannels(void) -{ - return (linux_inchannels); -} - -void sys_audiobuf(int n) -{ - /* set the size, in milliseconds, of the audio FIFO */ - if (n < 5) n = 5; - else if (n > 5000) n = 5000; - sys_schedadvance = n * 1000; -} - -void sys_getmeters(float *inmax, float *outmax) -{ - if (inmax) - { - linux_meters = 1; - *inmax = linux_inmax; - *outmax = linux_outmax; - } - else - linux_meters = 0; - linux_inmax = linux_outmax = 0; -} - -void sys_reportidle(void) -{ -} - -void sys_set_priority(int higher) -{ - struct sched_param par; - int p1 ,p2, p3; -#ifdef _POSIX_PRIORITY_SCHEDULING - - p1 = sched_get_priority_min(SCHED_FIFO); - p2 = sched_get_priority_max(SCHED_FIFO); - p3 = (higher ? p2 - 1 : p2 - 3); - par.sched_priority = p3; - - if (sched_setscheduler(0,SCHED_FIFO,&par) != -1) - fprintf(stderr, "priority %d scheduling enabled.\n", p3); -#endif - -#ifdef _POSIX_MEMLOCK - if (mlockall(MCL_FUTURE) != -1) - fprintf(stderr, "memory locking enabled.\n"); -#endif -} - -/* ------------ linux-specific command-line flags -------------- */ - -void linux_setfrags(int n) -{ - linux_nfragment = n; - oss_blockmode = 1; -} - -void linux_setfragsize(int n) -{ - if (n < 1) - n = 1; - linux_fragsize = n; - oss_blockmode = 1; -} - -void linux_streammode( void) -{ - oss_blockmode = 0; -} - -void linux_set_sound_api(int which) -{ - linux_whichapi = which; - if (sys_verbose) - post("linux_whichapi %d", linux_whichapi); -} - -#ifdef ALSA99 -void linux_alsa_devno(int devno) -{ - alsa_devno = devno; -} - -#endif - -#ifdef ALSA01 -void linux_alsa_devname(char *devname) -{ - strncpy(alsa_devname, devname, 511); -} - -void linux_alsa_use_plugin(int t) -{ - if (t == 1) - alsa_use_plugin = 1; - else - alsa_use_plugin = 0; -} - -#endif - -/* -------------- Audio I/O using the OSS API ------------------ */ - -typedef struct _multidev { - int fd; - int channels; - int format; -} t_multidev; - -int oss_reset(int fd) { - int err; - if ((err = ioctl(fd,SNDCTL_DSP_RESET)) < 0) - error("OSS: Could not reset"); - return err; -} - - /* The AFMT_S32_BLOCKED format is not defined in standard linux kernels - but is proposed by Guenter Geiger to support extending OSS to handle - 32 bit sample. This is user in Geiger's OSS driver for RME Hammerfall. - I'm not clear why this isn't called AFMT_S32_[SLN]E... */ - -#ifndef AFMT_S32_BLOCKED -#define AFMT_S32_BLOCKED 0x0000400 -#endif - -void oss_configure(t_oss_dev *dev, int srate, int dac, int skipblocksize) -{ /* IOhannes */ - int orig, param, nblk, fd = dev->d_fd, wantformat; - int nchannels = dev->d_nchannels; - int advwas = sys_schedadvance; - - audio_buf_info ainfo; - - /* IOhannes : - * pd is very likely to crash if different formats are used on - multiple soundcards - */ - - /* set resolution - first try 4 byte samples */ - if ((ioctl(fd,SNDCTL_DSP_GETFMTS,¶m) >= 0) && - (param & AFMT_S32_BLOCKED)) - { - wantformat = AFMT_S32_BLOCKED; - dev->d_bytespersamp = 4; - } - else - { -/* FreeBSD's soundcard.h does not define AFMT_S16_NE */ - wantformat = AFMT_S16_BE; - dev->d_bytespersamp = 2; - } - param = wantformat; - - if (sys_verbose) - post("bytes per sample = %d", dev->d_bytespersamp); - if (ioctl(fd, SNDCTL_DSP_SETFMT, ¶m) == -1) - fprintf(stderr,"OSS: Could not set DSP format\n"); - else if (wantformat != param) - fprintf(stderr,"OSS: DSP format: wanted %d, got %d\n", - wantformat, param); - - /* sample rate */ - orig = param = srate; - if (ioctl(fd, SNDCTL_DSP_SPEED, ¶m) == -1) - fprintf(stderr,"OSS: Could not set sampling rate for device\n"); - else if( orig != param ) - fprintf(stderr,"OSS: sampling rate: wanted %d, got %d\n", - orig, param ); - - if (oss_blockmode && !skipblocksize) - { - int fragbytes, logfragsize, nfragment; - /* setting fragment count and size. */ - if (linux_nfragment) /* if nfrags specified, take literally */ - { - nfragment = linux_nfragment; - if (!linux_fragsize) - linux_fragsize = OSS_DEFFRAGSIZE; - sys_schedadvance = ((nfragment * linux_fragsize) * 1.e6) - / (float)srate; - linux_setsr(srate); - } - else - { - if (!linux_fragsize) - { - linux_fragsize = OSS_DEFFRAGSIZE; - while (linux_fragsize > DACBLKSIZE - && linux_fragsize * 4 > linux_advance_samples) - linux_fragsize = linux_fragsize/2; - } - /* post("adv_samples %d", linux_advance_samples); */ - nfragment = (sys_schedadvance * (44100. * 1.e-6)) / linux_fragsize; - } - fragbytes = linux_fragsize * (dev->d_bytespersamp * nchannels); - logfragsize = ilog2(fragbytes); - - if (fragbytes != (1 << logfragsize)) - post("warning: OSS takes only power of 2 blocksize; using %d", - (1 << logfragsize)/(dev->d_bytespersamp * nchannels)); - if (sys_verbose) - post("setting nfrags = %d, fragsize %d\n", nfragment, fragbytes); - - param = orig = (nfragment<<16) + logfragsize; - if (ioctl(fd,SNDCTL_DSP_SETFRAGMENT, ¶m) == -1) - error("OSS: Could not set or read fragment size\n"); - if (param != orig) - { - nfragment = ((param >> 16) & 0xffff); - logfragsize = (param & 0xffff); - post("warning: actual fragments %d, blocksize %d", - nfragment, (1 << logfragsize)); - } - if (sys_verbose) - post("audiobuffer set to %d msec", (int)(0.001 * sys_schedadvance)); - } - - if (dac) - { - /* use "free space" to learn the buffer size. Normally you - should set this to your own desired value; but this seems not - to be implemented uniformly across different sound cards. LATER - we should figure out what to do if the requested scheduler advance - is greater than this buffer size; for now, we just print something - out. */ - - int defect; - if (ioctl(fd, SOUND_PCM_GETOSPACE,&ainfo) < 0) - fprintf(stderr,"OSS: ioctl on output device failed"); - dev->d_bufsize = ainfo.bytes; - - defect = linux_advance_samples * (dev->d_bytespersamp * nchannels) - - dev->d_bufsize - OSS_XFERSIZE(nchannels, dev->d_bytespersamp); - if (defect > 0) - { - if (sys_verbose || defect > (dev->d_bufsize >> 2)) - fprintf(stderr, - "OSS: requested audio buffer size %d limited to %d\n", - linux_advance_samples * (dev->d_bytespersamp * nchannels), - dev->d_bufsize); - linux_advance_samples = - (dev->d_bufsize - OSS_XFERSAMPS(nchannels)) / - (dev->d_bytespersamp *nchannels); - } - } -} - -static int oss_setchannels(int fd, int wantchannels, char *devname) -{ /* IOhannes */ - int param = wantchannels; - - while (param>1) { - int save = param; - if (ioctl(fd, SNDCTL_DSP_CHANNELS, ¶m) == -1) { - error("OSS: SNDCTL_DSP_CHANNELS failed %s",devname); - } else { - if (param == save) return (param); - } - param=save-1; - } - - return (0); -} - -int oss_open_audio(int nindev, int *indev, int nchin, int *chin, - int noutdev, int *outdev, int nchout, int *chout, int rate) -{ /* IOhannes */ - int capabilities = 0; - int inchannels = 0, outchannels = 0; - char devname[20]; - int n, i, fd; - char buf[OSS_MAXSAMPLEWIDTH * DACBLKSIZE * OSS_MAXCHPERDEV]; - int num_devs = 0; - int wantmore=0; - int spread = 0; - audio_buf_info ainfo; - - linux_nindevs = linux_noutdevs = 0; - - /* set logical sample rate amd calculate linux_advance_samples. */ - linux_setsr(rate); - - /* mark input devices unopened */ - for (i = 0; i < OSS_MAXDEV; i++) - linux_adcs[i].d_fd = -1; - - /* open output devices */ - wantmore=0; - if (noutdev < 0 || nindev < 0) - bug("linux_open_audio"); - - for (n = 0; n < noutdev; n++) - { - int gotchans, j, inindex = -1; - int thisdevice=outdev[n]; - int wantchannels = (nchout>n) ? chout[n] : wantmore; - fd = -1; - if (!wantchannels) - goto end_out_loop; - - if (thisdevice > 1) - sprintf(devname, "/dev/dsp%d", thisdevice-1); - else sprintf(devname, "/dev/dsp"); - - /* search for input request for same device. Succeed only - if the number of channels matches. */ - for (j = 0; j < nindev; j++) - if (indev[j] == thisdevice && chin[j] == wantchannels) - inindex = j; - - /* if the same device is requested for input and output, - try to open it read/write */ - if (inindex >= 0) - { - sys_setalarm(1000000); - if ((fd = open(devname, O_RDWR)) == -1) - { - post("%s (read/write): %s", devname, strerror(errno)); - post("(now will try write-only...)"); - } - else - { - if (sys_verbose) - post("opened %s for reading and writing\n", devname); - linux_adcs[inindex].d_fd = fd; - } - } - /* if that didn't happen or if it failed, try write-only */ - if (fd == -1) - { - sys_setalarm(1000000); - if ((fd = open(devname, O_WRONLY)) == -1) - { - post("%s (writeonly): %s", - devname, strerror(errno)); - break; - } - if (sys_verbose) - post("opened %s for writing only\n", devname); - } - if (ioctl(fd, SNDCTL_DSP_GETCAPS, &capabilities) == -1) - error("OSS: SNDCTL_DSP_GETCAPS failed %s", devname); - - gotchans = oss_setchannels(fd, - (wantchannels>OSS_MAXCHPERDEV)?OSS_MAXCHPERDEV:wantchannels, - devname); - - if (sys_verbose) - post("opened audio output on %s; got %d channels", - devname, gotchans); - - if (gotchans < 2) - { - /* can't even do stereo? just give up. */ - close(fd); - } - else - { - linux_dacs[linux_noutdevs].d_nchannels = gotchans; - linux_dacs[linux_noutdevs].d_fd = fd; - oss_configure(linux_dacs+linux_noutdevs, rate, 1, 0); - - linux_noutdevs++; - outchannels += gotchans; - if (inindex >= 0) - { - linux_adcs[inindex].d_nchannels = gotchans; - chin[inindex] = gotchans; - } - } - /* LATER think about spreading large numbers of channels over - various dsp's and vice-versa */ - wantmore = wantchannels - gotchans; - end_out_loop: ; - } - - /* open input devices */ - wantmore = 0; - if (nindev==-1) - nindev=4; /* spread channels over default-devices */ - for (n = 0; n < nindev; n++) - { - int gotchans=0; - int thisdevice=indev[n]; - int wantchannels = (nchin>n)?chin[n]:wantmore; - int alreadyopened = 0; - if (!wantchannels) - goto end_in_loop; - - if (thisdevice > 1) - sprintf(devname, "/dev/dsp%d", thisdevice - 1); - else sprintf(devname, "/dev/dsp"); - - sys_setalarm(1000000); - - /* perhaps it's already open from the above? */ - if (linux_dacs[n].d_fd >= 0) - { - fd = linux_dacs[n].d_fd; - alreadyopened = 1; - } - else - { - /* otherwise try to open it here. */ - if ((fd = open(devname, O_RDONLY)) == -1) - { - post("%s (readonly): %s", devname, strerror(errno)); - goto end_in_loop; - } - if (sys_verbose) - post("opened %s for reading only\n", devname); - } - linux_adcs[linux_nindevs].d_fd = fd; - gotchans = oss_setchannels(fd, - (wantchannels>OSS_MAXCHPERDEV)?OSS_MAXCHPERDEV:wantchannels, - devname); - if (sys_verbose) - post("opened audio input device %s; got %d channels", - devname, gotchans); - - if (gotchans < 1) - { - close(fd); - goto end_in_loop; - } - - linux_adcs[linux_nindevs].d_nchannels = gotchans; - - oss_configure(linux_adcs+linux_nindevs, rate, 0, alreadyopened); - - inchannels += gotchans; - linux_nindevs++; - - wantmore = wantchannels-gotchans; - /* LATER think about spreading large numbers of channels over - various dsp's and vice-versa */ - end_in_loop: ; - } - - linux_setch(inchannels, outchannels); - - /* We have to do a read to start the engine. This is - necessary because sys_send_dacs waits until the input - buffer is filled and only reads on a filled buffer. - This is good, because it's a way to make sure that we - will not block. But I wonder why we only have to read - from one of the devices and not all of them??? */ - - if (linux_nindevs) - { - if (sys_verbose) - fprintf(stderr,("OSS: issuing first ADC 'read' ... ")); - read(linux_adcs[0].d_fd, buf, - linux_adcs[0].d_bytespersamp * - linux_adcs[0].d_nchannels * DACBLKSIZE); - if (sys_verbose) - fprintf(stderr, "...done.\n"); - } - sys_setalarm(0); - return (0); -} - -void oss_close_audio( void) -{ - int i; - for (i=0;i - OSS_XFERSIZE(linux_adcs[dev].d_nchannels, - linux_adcs[dev].d_bytespersamp)) - { - linux_adcs_read(linux_adcs[dev].d_fd, buf, - OSS_XFERSIZE(linux_adcs[dev].d_nchannels, - linux_adcs[dev].d_bytespersamp)); - if (ioctl(linux_adcs[dev].d_fd, SOUND_PCM_GETISPACE, &ainfo) < 0) - { - fprintf(stderr, "OSS: ioctl on input device %d, fd %d failed", - dev, linux_adcs[dev].d_fd); - break; - } - linux_adcs[dev].d_space = ainfo.bytes; - } - } - - /* 2. if any output devices are behind, feed them zeros to catch them - up */ - for (dev = 0; dev < linux_noutdevs; dev++) - { - while (linux_dacs[dev].d_space > linux_dacs[dev].d_bufsize - - linux_advance_samples * (linux_dacs[dev].d_nchannels * - linux_dacs[dev].d_bytespersamp)) - { - if (!zeroed) - { - unsigned int i; - for (i = 0; i < OSS_XFERSAMPS(linux_dacs[dev].d_nchannels); - i++) - buf[i] = 0; - zeroed = 1; - } - linux_dacs_write(linux_dacs[dev].d_fd, buf, - OSS_XFERSIZE(linux_dacs[dev].d_nchannels, - linux_dacs[dev].d_bytespersamp)); - if (ioctl(linux_dacs[dev].d_fd, SOUND_PCM_GETOSPACE, &ainfo) < 0) - { - fprintf(stderr, "OSS: ioctl on output device %d, fd %d failed", - dev, linux_dacs[dev].d_fd); - break; - } - linux_dacs[dev].d_space = ainfo.bytes; - } - } - /* 3. if any DAC devices are too far ahead, plan to drop the - number of frames which will let the others catch up. */ - for (dev = 0; dev < linux_noutdevs; dev++) - { - if (linux_dacs[dev].d_space > linux_dacs[dev].d_bufsize - - (linux_advance_samples - 1) * linux_dacs[dev].d_nchannels * - linux_dacs[dev].d_bytespersamp) - { - linux_dacs[dev].d_dropcount = linux_advance_samples - 1 - - (linux_dacs[dev].d_space - linux_dacs[dev].d_bufsize) / - (linux_dacs[dev].d_nchannels * - linux_dacs[dev].d_bytespersamp) ; - } - else linux_dacs[dev].d_dropcount = 0; - } -} - -int oss_send_dacs(void) -{ - float *fp1, *fp2; - long fill; - int i, j, dev, rtnval = SENDDACS_YES; - char buf[OSS_MAXSAMPLEWIDTH * DACBLKSIZE * OSS_MAXCHPERDEV]; - t_oss_int16 *sp; - t_oss_int32 *lp; - /* the maximum number of samples we should have in the ADC buffer */ - int idle = 0; - int thischan; - double timeref, timenow; - - if (!linux_nindevs && !linux_noutdevs) - return (SENDDACS_NO); - - if (!oss_blockmode) - { - /* determine whether we're idle. This is true if either (1) - some input device has less than one buffer to read or (2) some - output device has fewer than (linux_advance_samples) blocks buffered - already. */ - oss_calcspace(); - - for (dev=0; dev < linux_noutdevs; dev++) - if (linux_dacs[dev].d_dropcount || - (linux_dacs[dev].d_bufsize - linux_dacs[dev].d_space > - linux_advance_samples * linux_dacs[dev].d_bytespersamp * - linux_dacs[dev].d_nchannels)) - idle = 1; - for (dev=0; dev < linux_nindevs; dev++) - if (linux_adcs[dev].d_space < - OSS_XFERSIZE(linux_adcs[dev].d_nchannels, - linux_adcs[dev].d_bytespersamp)) - idle = 1; - } - - if (idle && !oss_blockmode) - { - /* sometimes---rarely---when the ADC available-byte-count is - zero, it's genuine, but usually it's because we're so - late that the ADC has overrun its entire kernel buffer. We - distinguish between the two by waiting 2 msec and asking again. - There should be an error flag we could check instead; look for this - someday... */ - for (dev = 0;dev < linux_nindevs; dev++) - if (linux_adcs[dev].d_space == 0) - { - audio_buf_info ainfo; - sys_microsleep(2000); - oss_calcspace(); - if (linux_adcs[dev].d_space != 0) continue; - - /* here's the bad case. Give up and resync. */ - sys_log_error(ERR_DATALATE); - oss_doresync(); - return (SENDDACS_NO); - } - /* check for slippage between devices, either because - data got lost in the driver from a previous late condition, or - because the devices aren't synced. When we're idle, no - input device should have more than one buffer readable and - no output device should have less than linux_advance_samples-1 - */ - - for (dev=0; dev < linux_noutdevs; dev++) - if (!linux_dacs[dev].d_dropcount && - (linux_dacs[dev].d_bufsize - linux_dacs[dev].d_space < - (linux_advance_samples - 2) * - (linux_dacs[dev].d_bytespersamp * - linux_dacs[dev].d_nchannels))) - goto badsync; - for (dev=0; dev < linux_nindevs; dev++) - if (linux_adcs[dev].d_space > 3 * - OSS_XFERSIZE(linux_adcs[dev].d_nchannels, - linux_adcs[dev].d_bytespersamp)) - goto badsync; - - /* return zero to tell the scheduler we're idle. */ - return (SENDDACS_NO); - badsync: - sys_log_error(ERR_RESYNC); - oss_doresync(); - return (SENDDACS_NO); - - } - - /* do output */ - - timeref = sys_getrealtime(); - for (dev=0, thischan = 0; dev < linux_noutdevs; dev++) - { - int nchannels = linux_dacs[dev].d_nchannels; - if (linux_dacs[dev].d_dropcount) - linux_dacs[dev].d_dropcount--; - else - { - if (linux_dacs[dev].d_bytespersamp == 4) - { - for (i = DACBLKSIZE * nchannels, fp1 = sys_soundout + - DACBLKSIZE*thischan, - lp = (t_oss_int32 *)buf; i--; fp1++, lp++) - { - float f = *fp1 * 2147483648.; - *lp = (f >= 2147483647. ? 2147483647. : - (f < -2147483648. ? -2147483648. : f)); - } - } - else - { - for (i = DACBLKSIZE, fp1 = sys_soundout + - DACBLKSIZE*thischan, - sp = (t_oss_int16 *)buf; i--; fp1++, sp += nchannels) - { - for (j=0, fp2 = fp1; j 32767) s = 32767; - else if (s < -32767) s = -32767; - sp[j] = s; - } - } - } - linux_dacs_write(linux_dacs[dev].d_fd, buf, - OSS_XFERSIZE(nchannels, linux_dacs[dev].d_bytespersamp)); - if ((timenow = sys_getrealtime()) - timeref > 0.002) - { - if (!oss_blockmode) - sys_log_error(ERR_DACSLEPT); - else rtnval = SENDDACS_SLEPT; - } - timeref = timenow; - } - thischan += nchannels; - } - memset(sys_soundout, 0, - linux_outchannels * (sizeof(float) * DACBLKSIZE)); - - /* do input */ - - for (dev = 0, thischan = 0; dev < linux_nindevs; dev++) - { - int nchannels = linux_adcs[dev].d_nchannels; - linux_adcs_read(linux_adcs[dev].d_fd, buf, - OSS_XFERSIZE(nchannels, linux_adcs[dev].d_bytespersamp)); - - if ((timenow = sys_getrealtime()) - timeref > 0.002) - { - if (!oss_blockmode) - sys_log_error(ERR_ADCSLEPT); - else - rtnval = SENDDACS_SLEPT; - } - timeref = timenow; - - if (linux_adcs[dev].d_bytespersamp == 4) - { - for (i = DACBLKSIZE*nchannels, - fp1 = sys_soundin + thischan*DACBLKSIZE, - lp = (t_oss_int32 *)buf; i--; fp1++, lp++) - { - *fp1 = ((float)(*lp))*(float)(1./2147483648.); - } - } - else - { - for (i = DACBLKSIZE,fp1 = sys_soundin + thischan*DACBLKSIZE, - sp = (t_oss_int16 *)buf; i--; fp1++, sp += nchannels) - { - for (j=0;j channelinfo.max_voices) - post("decreasing input channels to maximum of %d\n", - wantinchans = channelinfo.max_voices); - if (alsa_samplewidth == 4 && - !(channelinfo.formats & (1< channelinfo.max_voices) - post("decreasing output channels to maximum of %d\n", - wantoutchans = channelinfo.max_voices); - if (alsa_samplewidth == 4 && - !(channelinfo.formats & (1< linux_outchannels ? linux_inchannels : - linux_outchannels) * DACBLKSIZE; - alsa_buf = malloc(bsize); - if (!alsa_buf) - return (1); - memset(alsa_buf, 0, bsize); - return 0; -} - -void alsa_set_params(t_alsa_dev *dev, int dir, int rate, int voices) -{ - int err; - struct snd_pcm_channel_params params; - - memset(&dev->info, 0, sizeof(dev->info)); - dev->info.channel = dir; - if ((err = snd_pcm_channel_info(dev->handle, &dev->info) < 0)) - { - fprintf(stderr, "PD-ALSA: error getting channel info: %s\n", - snd_strerror(err)); - } - memset(¶ms, 0, sizeof(params)); - params.format.interleave = 1; /* may do non-interleaved later */ - /* format is 2 or 4 bytes per sample depending on what was possible */ - params.format.format = - (alsa_samplewidth == 4 ? SND_PCM_SFMT_S32_LE : SND_PCM_SFMT_S16_LE); - - /*will check this further down -just try for now*/ - params.format.rate = rate; - params.format.voices = voices; - params.start_mode = SND_PCM_START_GO; /* seems most reliable */ - /*do not stop at overrun/underrun*/ - params.stop_mode = SND_PCM_STOP_ROLLOVER; - - params.channel = dir; /* playback|capture */ - params.buf.stream.queue_size = - (ALSA_EXTRABUFFER + linux_advance_samples) - * alsa_samplewidth * voices; - params.buf.stream.fill = SND_PCM_FILL_SILENCE_WHOLE; - params.mode = SND_PCM_MODE_STREAM; - - if ((err = snd_pcm_channel_params(dev->handle, ¶ms)) < 0) - { - printf("PD-ALSA: error setting parameters %s", snd_strerror(err)); - } - - /* This should clear the buffers but does not. There is often noise at - startup that sounds like crap left in the buffers - maybe in the lib - instead of the driver? Some solution needs to be found. - */ - - if ((err = snd_pcm_channel_prepare(dev->handle, dir)) < 0) - { - printf("PD-ALSA: error preparing channel %s", snd_strerror(err)); - } - dev->setup.channel = dir; - - if ((err = snd_pcm_channel_setup(dev->handle, &dev->setup)) < 0) - { - printf("PD-ALSA: error getting setup %s", snd_strerror(err)); - } - /* for some reason, if you don't writesomething before starting the - converters we get trash on startup */ - if (dir == SND_PCM_CHANNEL_PLAYBACK) - { - char foo[1024]; - int xxx = 1024 - (1024 % (linux_outchannels * alsa_samplewidth)); - int i, r; - for (i = 0; i < xxx; i++) - foo[i] = 0; - if ((r = snd_pcm_write(dev->handle, foo, xxx)) < xxx) - fprintf(stderr, "alsa_write: %s\n", snd_strerror(errno)); - } - snd_pcm_channel_go(dev->handle, dir); -} - -void alsa_close_audio(void) -{ - int i; - for(i = 0; i < n_alsa_dev; i++) - snd_pcm_close(alsa_device[i].handle); -} - -/* #define DEBUG_ALSA_XFER */ - -int alsa_send_dacs(void) -{ - static int16_t *sp; - t_sample *fp, *fp1, *fp2; - int i, j, k, err, devno = 0; - int inputcount = 0, outputcount = 0, inputlate = 0, outputlate = 0; - int result; - snd_pcm_channel_status_t stat; - static int callno = 0; - static int xferno = 0; - int countwas = 0; - double timelast; - static double timenow; - int inchannels = linux_inchannels; - int outchannels = linux_outchannels; - int inbytesperframe = inchannels * alsa_samplewidth; - int outbytesperframe = outchannels * alsa_samplewidth; - int intransfersize = DACBLKSIZE * inbytesperframe; - int outtransfersize = DACBLKSIZE * outbytesperframe; - int alsaerror; - int loggederror = 0; - - if (!inchannels && !outchannels) - return (SENDDACS_NO); - timelast = timenow; - timenow = sys_getrealtime(); - -#ifdef DEBUG_ALSA_XFER - if (timenow - timelast > 0.050) - fprintf(stderr, "(%d)", - (int)(1000 * (timenow - timelast))), fflush(stderr); -#endif - - callno++; - /* get input and output channel status */ - if (inchannels > 0) - { - devno = 0; - stat.channel = SND_PCM_CHANNEL_CAPTURE; - if (alsaerror = snd_pcm_channel_status(alsa_device[devno].handle, - &stat)) - { - fprintf(stderr, "snd_pcm_channel_status (input): %s\n", - snd_strerror(alsaerror)); - return (SENDDACS_NO); - } - inputcount = stat.count; - inputlate = (stat.underrun > 0 || stat.overrun > 0); - } - if (outchannels > 0) - { - devno = 0; - stat.channel = SND_PCM_CHANNEL_PLAYBACK; - if (alsaerror = snd_pcm_channel_status(alsa_device[devno].handle, - &stat)) - { - fprintf(stderr, "snd_pcm_channel_status (output): %s\n", - snd_strerror(alsaerror)); - return (SENDDACS_NO); - } - outputcount = stat.count; - outputlate = (stat.underrun > 0 || stat.overrun > 0); - } - - /* check if input not ready */ - if (inputcount < intransfersize) - { - /* fprintf(stderr, "no adc; count %d, free %d, call %d, xfer %d\n", - stat.count, - stat.free, - callno, xferno); */ - if (outchannels > 0) - { - /* if there's no input but output is hungry, feed output. */ - while (outputcount < (linux_advance_samples + ALSA_JITTER) - * outbytesperframe) - { - if (!loggederror) - sys_log_error(ERR_RESYNC), loggederror = 1; - memset(alsa_buf, 0, outtransfersize); - result = snd_pcm_write(alsa_device[devno].handle, - alsa_buf, outtransfersize); - if (result < outtransfersize) - { -#ifdef DEBUG_ALSA_XFER - if (result >= 0 || errno == EAGAIN) - fprintf(stderr, "ALSA: write returned %d of %d\n", - result, outtransfersize); - else fprintf(stderr, "ALSA: write: %s\n", - snd_strerror(errno)); - fprintf(stderr, - "inputcount %d, outputcount %d, outbufsize %d\n", - inputcount, outputcount, - (ALSA_EXTRABUFFER + linux_advance_samples) - * alsa_samplewidth * outchannels); -#endif - return (SENDDACS_NO); - } - stat.channel = SND_PCM_CHANNEL_PLAYBACK; - if (alsaerror = - snd_pcm_channel_status(alsa_device[devno].handle, - &stat)) - { - fprintf(stderr, "snd_pcm_channel_status (output): %s\n", - snd_strerror(alsaerror)); - return (SENDDACS_NO); - } - outputcount = stat.count; - } - } - - return SENDDACS_NO; - } - - /* if output buffer has at least linux_advance_samples in it, we're - not ready for this batch. */ - if (outputcount > linux_advance_samples * outbytesperframe) - { - if (inchannels > 0) - { - while (inputcount > (DACBLKSIZE + ALSA_JITTER) * outbytesperframe) - { - if (!loggederror) - sys_log_error(ERR_RESYNC), loggederror = 1; - devno = 0; - result = snd_pcm_read(alsa_device[devno].handle, alsa_buf, - intransfersize); - if (result < intransfersize) - { -#ifdef DEBUG_ALSA_XFER - if (result < 0) - fprintf(stderr, - "snd_pcm_read %d %d: %s\n", - callno, xferno, snd_strerror(errno)); - else fprintf(stderr, - "snd_pcm_read %d %d returned only %d\n", - callno, xferno, result); - fprintf(stderr, - "inputcount %d, outputcount %d, inbufsize %d\n", - inputcount, outputcount, - (ALSA_EXTRABUFFER + linux_advance_samples) - * alsa_samplewidth * inchannels); -#endif - return (SENDDACS_NO); - } - devno = 0; - stat.channel = SND_PCM_CHANNEL_CAPTURE; - if (alsaerror = - snd_pcm_channel_status(alsa_device[devno].handle, - &stat)) - { - fprintf(stderr, "snd_pcm_channel_status (input): %s\n", - snd_strerror(alsaerror)); - return (SENDDACS_NO); - } - inputcount = stat.count; - inputlate = (stat.underrun > 0 || stat.overrun > 0); - } - return (SENDDACS_NO); - } - } - if (sys_getrealtime() - timenow > 0.002) - { -#ifdef DEBUG_ALSA_XFER - fprintf(stderr, "check %d took %d msec\n", - callno, (int)(1000 * (timenow - timelast))), fflush(stderr); -#endif - sys_log_error(ERR_DACSLEPT); - timenow = sys_getrealtime(); - } - if (inputlate || outputlate) - sys_log_error(ERR_DATALATE); - - /* do output */ - /* this "for" loop won't work for more than one device. */ - for (devno = 0, fp = sys_soundout; devno < (outchannels > 0); devno++, - fp += 128) - { - if (alsa_samplewidth == 4) - { - for (i = 0, fp1 = fp; i < outchannels; i++, fp1 += DACBLKSIZE) - { - for (j = i, k = DACBLKSIZE, fp2 = fp1; k--; - j += outchannels, fp2++) - { - float s1 = *fp2 * INT32_MAX; - ((t_alsa_sample32 *)alsa_buf)[j] = CLIP32(s1); - } - } - } - else - { - for (i = 0, fp1 = fp; i < outchannels; i++, fp1 += DACBLKSIZE) - { - for (j = i, k = DACBLKSIZE, fp2 = fp1; k--; - j += outchannels, fp2++) - { - int s = *fp2 * 32767.; - if (s > 32767) - s = 32767; - else if (s < -32767) - s = -32767; - ((t_alsa_sample16 *)alsa_buf)[j] = s; - } - } - } - - result = snd_pcm_write(alsa_device[devno].handle, alsa_buf, - outtransfersize); - if (result < outtransfersize) - { -#ifdef DEBUG_ALSA_XFER - if (result >= 0 || errno == EAGAIN) - fprintf(stderr, "ALSA: write returned %d of %d\n", - result, outtransfersize); - else fprintf(stderr, "ALSA: write: %s\n", - snd_strerror(errno)); - fprintf(stderr, - "inputcount %d, outputcount %d, outbufsize %d\n", - inputcount, outputcount, - (ALSA_EXTRABUFFER + linux_advance_samples) - * alsa_samplewidth * outchannels); -#endif - sys_log_error(ERR_DACSLEPT); - return (SENDDACS_NO); - } - } - /* zero out the output buffer */ - memset(sys_soundout, 0, DACBLKSIZE * sizeof(*sys_soundout) * - linux_outchannels); - if (sys_getrealtime() - timenow > 0.002) - { -#if DEBUG_ALSA_XFER - fprintf(stderr, "output %d took %d msec\n", - callno, (int)(1000 * (timenow - timelast))), fflush(stderr); -#endif - timenow = sys_getrealtime(); - sys_log_error(ERR_DACSLEPT); - } - - /* do input */ - for (devno = 0, fp = sys_soundin; devno < (linux_inchannels > 0); devno++, - fp += 128) - { - result = snd_pcm_read(alsa_device[devno].handle, alsa_buf, - intransfersize); - if (result < intransfersize) - { -#ifdef DEBUG_ALSA_XFER - if (result < 0) - fprintf(stderr, - "snd_pcm_read %d %d: %s\n", - callno, xferno, snd_strerror(errno)); - else fprintf(stderr, - "snd_pcm_read %d %d returned only %d\n", - callno, xferno, result); - fprintf(stderr, - "inputcount %d, outputcount %d, inbufsize %d\n", - inputcount, outputcount, - (ALSA_EXTRABUFFER + linux_advance_samples) - * alsa_samplewidth * inchannels); -#endif - sys_log_error(ERR_ADCSLEPT); - return (SENDDACS_NO); - } - if (alsa_samplewidth == 4) - { - for (i = 0, fp1 = fp; i < inchannels; i++, fp1 += DACBLKSIZE) - { - for (j = i, k = DACBLKSIZE, fp2 = fp1; k--; - j += inchannels, fp2++) - *fp2 = (float) ((t_alsa_sample32 *)alsa_buf)[j] - * (1./ INT32_MAX); - } - } - else - { - for (i = 0, fp1 = fp; i < inchannels; i++, fp1 += DACBLKSIZE) - { - for (j = i, k = DACBLKSIZE, fp2 = fp1; k--; j += inchannels, fp2++) - *fp2 = (float) ((t_alsa_sample16 *)alsa_buf)[j] - * 3.051850e-05; - } - } - } - xferno++; - if (sys_getrealtime() - timenow > 0.002) - { -#ifdef DEBUG_ALSA_XFER - fprintf(stderr, "routine took %d msec\n", - (int)(1000 * (sys_getrealtime() - timenow))); -#endif - sys_log_error(ERR_ADCSLEPT); - } - return SENDDACS_YES; -} - -#endif /* ALSA99 */ - -/* support for ALSA pcmv2 api by Karl MacMillan */ - -#ifdef ALSA01 - -static void check_error(int err, const char *why) -{ - if (err < 0) - fprintf(stderr, "%s: %s\n", why, snd_strerror(err)); -} - -static int alsa_open_audio(int wantinchans, int wantoutchans, int srate) -{ - int err, inchans = 0, outchans = 0, subunitdir; - char devname[512]; - snd_pcm_hw_params_t* hw_params; - snd_pcm_sw_params_t* sw_params; - snd_output_t* out; - int frag_size = (linux_fragsize ? linux_fragsize : ALSA_DEFFRAGSIZE); - int nfrags, i; - short* tmp_buf; - unsigned int tmp_uint; - int advwas = sys_schedadvance; - - if (linux_nfragment) - { - nfrags = linux_nfragment; - sys_schedadvance = (frag_size * linux_nfragment * 1.0e6) / srate; - } - else nfrags = sys_schedadvance * (float)srate / (1e6 * frag_size); - - if (sys_verbose || (sys_schedadvance != advwas)) - post("audio buffer set to %d", (int)(0.001 * sys_schedadvance)); - if (wantinchans || wantoutchans) - alsa_checkversion(); - if (wantinchans) - { - err = snd_pcm_open(&alsa_device.inhandle, alsa_devname, - SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK); - - check_error(err, "snd_pcm_open (input)"); - if (err < 0) - inchans = 0; - else - { - inchans = wantinchans; - snd_pcm_nonblock(alsa_device.inhandle, 1); - } - } - if (wantoutchans) - { - err = snd_pcm_open(&alsa_device.outhandle, alsa_devname, - SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); - - check_error(err, "snd_pcm_open (output)"); - if (err < 0) - outchans = 0; - else - { - outchans = wantoutchans; - snd_pcm_nonblock(alsa_device.outhandle, 1); - } - } - if (inchans) - { - if (sys_verbose) - post("opening sound input..."); - err = snd_pcm_hw_params_malloc(&hw_params); - check_error(err, "snd_pcm_hw_params_malloc (input)"); - - // get the default params - err = snd_pcm_hw_params_any(alsa_device.inhandle, hw_params); - check_error(err, "snd_pcm_hw_params_any (input)"); - // set interleaved access - FIXME deal with other access types - err = snd_pcm_hw_params_set_access(alsa_device.inhandle, hw_params, - SND_PCM_ACCESS_RW_INTERLEAVED); - check_error(err, "snd_pcm_hw_params_set_access (input)"); - // Try to set 32 bit format first - err = snd_pcm_hw_params_set_format(alsa_device.inhandle, hw_params, - SND_PCM_FORMAT_S32); - if (err < 0) - { - /* fprintf(stderr, - "PD-ALSA: 32 bit format not available - using 16\n"); */ - err = snd_pcm_hw_params_set_format(alsa_device.inhandle, hw_params, - SND_PCM_FORMAT_S16); - check_error(err, "snd_pcm_hw_params_set_format (input)"); - alsa_samplewidth = 2; - } - else - { - alsa_samplewidth = 4; - } - post("Sample width set to %d bytes", alsa_samplewidth); - // set the subformat - err = snd_pcm_hw_params_set_subformat(alsa_device.inhandle, hw_params, - SND_PCM_SUBFORMAT_STD); - check_error(err, "snd_pcm_hw_params_set_subformat (input)"); - // set the number of channels - tmp_uint = inchans; - err = snd_pcm_hw_params_set_channels_min(alsa_device.inhandle, - hw_params, &tmp_uint); - check_error(err, "snd_pcm_hw_params_set_channels (input)"); - if (tmp_uint != (unsigned)inchans) - post("ALSA: set input channels to %d", tmp_uint); - inchans = tmp_uint; - // set the sampling rate - err = snd_pcm_hw_params_set_rate_min(alsa_device.inhandle, hw_params, - &srate, 0); - check_error(err, "snd_pcm_hw_params_set_rate_min (input)"); -#if 0 - err = snd_pcm_hw_params_get_rate(hw_params, &subunitdir); - post("input sample rate %d", err); -#endif - // set the period - ie frag size - // post("fragsize a %d", frag_size); - - /* LATER try this to get a recommended period size... - right now, it trips an assertion failure in ALSA lib */ -#if 0 - post("input period was %d, min %d, max %d\n", - snd_pcm_hw_params_get_period_size(hw_params, 0), - snd_pcm_hw_params_get_period_size_min(hw_params, 0), - snd_pcm_hw_params_get_period_size_max(hw_params, 0)); -#endif - err = snd_pcm_hw_params_set_period_size_near(alsa_device.inhandle, - hw_params, - (snd_pcm_uframes_t) - frag_size, 0); - check_error(err, "snd_pcm_hw_params_set_period_size_near (input)"); - // post("fragsize b %d", frag_size); - // set the number of periods - ie numfrags - // post("nfrags a %d", nfrags); - err = snd_pcm_hw_params_set_periods_near(alsa_device.inhandle, - hw_params, nfrags, 0); - check_error(err, "snd_pcm_hw_params_set_periods_near (input)"); - // set the buffer size - err = snd_pcm_hw_params_set_buffer_size_near(alsa_device.inhandle, - hw_params, nfrags * frag_size); - check_error(err, "snd_pcm_hw_params_set_buffer_size_near (input)"); - - err = snd_pcm_hw_params(alsa_device.inhandle, hw_params); - check_error(err, "snd_pcm_hw_params (input)"); - - snd_pcm_hw_params_free(hw_params); - - err = snd_pcm_sw_params_malloc(&sw_params); - check_error(err, "snd_pcm_sw_params_malloc (input)"); - err = snd_pcm_sw_params_current(alsa_device.inhandle, sw_params); - check_error(err, "snd_pcm_sw_params_current (input)"); -#if 1 - err = snd_pcm_sw_params_set_start_mode(alsa_device.inhandle, sw_params, - SND_PCM_START_EXPLICIT); - check_error(err, "snd_pcm_sw_params_set_start_mode (input)"); - err = snd_pcm_sw_params_set_xrun_mode(alsa_device.inhandle, sw_params, - SND_PCM_XRUN_NONE); - check_error(err, "snd_pcm_sw_params_set_xrun_mode (input)"); -#else - err = snd_pcm_sw_params_set_start_threshold(alsa_device.inhandle, - sw_params, nfrags * frag_size); - check_error(err, "snd_pcm_sw_params_set_start_threshold (input)"); - err = snd_pcm_sw_params_set_stop_threshold(alsa_device.inhandle, - sw_params, 1); - check_error(err, "snd_pcm_sw_params_set_stop_threshold (input)"); -#endif - - err = snd_pcm_sw_params_set_avail_min(alsa_device.inhandle, sw_params, - frag_size); - check_error(err, "snd_pcm_sw_params_set_avail_min (input)"); - err = snd_pcm_sw_params(alsa_device.inhandle, sw_params); - check_error(err, "snd_pcm_sw_params (input)"); - - snd_pcm_sw_params_free(sw_params); - - snd_output_stdio_attach(&out, stderr, 0); -#if 0 - if (sys_verbose) - { - snd_pcm_dump_hw_setup(alsa_device.inhandle, out); - snd_pcm_dump_sw_setup(alsa_device.inhandle, out); - } -#endif - } - - if (outchans) - { - int foo; - if (sys_verbose) - post("opening sound output..."); - err = snd_pcm_hw_params_malloc(&hw_params); - check_error(err, "snd_pcm_sw_params (output)"); - - // get the default params - err = snd_pcm_hw_params_any(alsa_device.outhandle, hw_params); - check_error(err, "snd_pcm_hw_params_any (output)"); - // set interleaved access - FIXME deal with other access types - err = snd_pcm_hw_params_set_access(alsa_device.outhandle, hw_params, - SND_PCM_ACCESS_RW_INTERLEAVED); - check_error(err, "snd_pcm_hw_params_set_access (output)"); - // Try to set 32 bit format first - err = snd_pcm_hw_params_set_format(alsa_device.outhandle, hw_params, - SND_PCM_FORMAT_S32); - if (err < 0) - { - err = snd_pcm_hw_params_set_format(alsa_device.outhandle, - hw_params,SND_PCM_FORMAT_S16); - check_error(err, "snd_pcm_hw_params_set_format (output)"); - /* fprintf(stderr, - "PD-ALSA: 32 bit format not available - using 16\n"); */ - alsa_samplewidth = 2; - } - else - { - alsa_samplewidth = 4; - } - // set the subformat - err = snd_pcm_hw_params_set_subformat(alsa_device.outhandle, hw_params, - SND_PCM_SUBFORMAT_STD); - check_error(err, "snd_pcm_hw_params_set_subformat (output)"); - // set the number of channels - tmp_uint = outchans; - err = snd_pcm_hw_params_set_channels_min(alsa_device.outhandle, - hw_params, &tmp_uint); - check_error(err, "snd_pcm_hw_params_set_channels (output)"); - if (tmp_uint != (unsigned)outchans) - post("alsa: set output channels to %d", tmp_uint); - outchans = tmp_uint; - // set the sampling rate - err = snd_pcm_hw_params_set_rate_min(alsa_device.outhandle, hw_params, - &srate, 0); - check_error(err, "snd_pcm_hw_params_set_rate_min (output)"); -#if 0 - err = snd_pcm_hw_params_get_rate(hw_params, &subunitdir); - post("output sample rate %d", err); -#endif - // set the period - ie frag size -#if 0 - post("output period was %d, min %d, max %d\n", - snd_pcm_hw_params_get_period_size(hw_params, 0), - snd_pcm_hw_params_get_period_size_min(hw_params, 0), - snd_pcm_hw_params_get_period_size_max(hw_params, 0)); -#endif - // post("fragsize c %d", frag_size); - err = snd_pcm_hw_params_set_period_size_near(alsa_device.outhandle, - hw_params, - (snd_pcm_uframes_t) - frag_size, 0); - // post("fragsize d %d", frag_size); - check_error(err, "snd_pcm_hw_params_set_period_size_near (output)"); - // set the number of periods - ie numfrags - err = snd_pcm_hw_params_set_periods_near(alsa_device.outhandle, - hw_params, nfrags, 0); - check_error(err, "snd_pcm_hw_params_set_periods_near (output)"); - // set the buffer size - err = snd_pcm_hw_params_set_buffer_size_near(alsa_device.outhandle, - hw_params, nfrags * frag_size); - - check_error(err, "snd_pcm_hw_params_set_buffer_size_near (output)"); - - err = snd_pcm_hw_params(alsa_device.outhandle, hw_params); - check_error(err, "snd_pcm_hw_params (output)"); - - snd_pcm_hw_params_free(hw_params); - - err = snd_pcm_sw_params_malloc(&sw_params); - check_error(err, "snd_pcm_sw_params_malloc (output)"); - err = snd_pcm_sw_params_current(alsa_device.outhandle, sw_params); - check_error(err, "snd_pcm_sw_params_current (output)"); -#if 1 - err = snd_pcm_sw_params_set_start_mode(alsa_device.outhandle, - sw_params, - SND_PCM_START_EXPLICIT); - check_error(err, "snd_pcm_sw_params_set_start_mode (output)"); - err = snd_pcm_sw_params_set_xrun_mode(alsa_device.outhandle, sw_params, - SND_PCM_XRUN_NONE); - check_error(err, "snd_pcm_sw_params_set_xrun_mode (output)"); -#else - err = snd_pcm_sw_params_set_start_threshold(alsa_device.inhandle, - sw_params, nfrags * frag_size); - check_error(err, "snd_pcm_sw_params_set_start_threshold (output)"); - err = snd_pcm_sw_params_set_stop_threshold(alsa_device.inhandle, - sw_params, 1); - check_error(err, "snd_pcm_sw_params_set_stop_threshold (output)"); -#endif - - err = snd_pcm_sw_params_set_avail_min(alsa_device.outhandle, sw_params, - frag_size); - check_error(err, "snd_pcm_sw_params_set_avail_min (output)"); - err = snd_pcm_sw_params(alsa_device.outhandle, sw_params); - check_error(err, "snd_pcm_sw_params (output)"); - - snd_pcm_sw_params_free(sw_params); - - snd_output_stdio_attach(&out, stderr, 0); -#if 0 - if (sys_verbose) - { - snd_pcm_dump_hw_setup(alsa_device.outhandle, out); - snd_pcm_dump_sw_setup(alsa_device.outhandle, out); - } -#endif - } - - linux_setsr(srate); - linux_setch(inchans, outchans); - - if (inchans) - snd_pcm_prepare(alsa_device.inhandle); - if (outchans) - snd_pcm_prepare(alsa_device.outhandle); - - // if duplex we can link the channels so they start together - if (inchans && outchans) - snd_pcm_link(alsa_device.inhandle, alsa_device.outhandle); - - // set up the buffer - if (outchans > inchans) - alsa_buf = (short *)calloc(sizeof(char) * alsa_samplewidth, DACBLKSIZE - * outchans); - else - alsa_buf = (short *)calloc(sizeof(char) * alsa_samplewidth, DACBLKSIZE - * inchans); - // fill the buffer with silence - if (outchans) - { - i = nfrags + 1; - while (i--) - snd_pcm_writei(alsa_device.outhandle, alsa_buf, frag_size); - } - - // set up the status variables - err = snd_pcm_status_malloc(&in_status); - check_error(err, "snd_pcm_status_malloc"); - err = snd_pcm_status_malloc(&out_status); - check_error(err, "snd_pcm_status_malloc"); - - // start the device -#if 1 - if (outchans) - { - err = snd_pcm_start(alsa_device.outhandle); - check_error(err, "snd_pcm_start"); - } - else if (inchans) - { - err = snd_pcm_start(alsa_device.inhandle); - check_error(err, "snd_pcm_start"); - } -#endif - - return 0; -} - -void alsa_close_audio(void) -{ - int err; - if (linux_inchannels) - { - err = snd_pcm_close(alsa_device.inhandle); - check_error(err, "snd_pcm_close (input)"); - } - if (linux_outchannels) - { - err = snd_pcm_close(alsa_device.outhandle); - check_error(err, "snd_pcm_close (output)"); - } -} - -// #define DEBUG_ALSA_XFER - -int alsa_send_dacs(void) -{ - static int16_t *sp; - static int xferno = 0; - static int callno = 0; - static double timenow; - double timelast; - t_sample *fp, *fp1, *fp2; - int i, j, k, err, devno = 0; - int inputcount = 0, outputcount = 0, inputlate = 0, outputlate = 0; - int result; - int inchannels = linux_inchannels; - int outchannels = linux_outchannels; - unsigned int intransfersize = DACBLKSIZE; - unsigned int outtransfersize = DACBLKSIZE; - - // get the status - if (!inchannels && !outchannels) - { - return SENDDACS_NO; - } - - timelast = timenow; - timenow = sys_getrealtime(); - -#ifdef DEBUG_ALSA_XFER - if (timenow - timelast > 0.050) - fprintf(stderr, "(%d)", - (int)(1000 * (timenow - timelast))), fflush(stderr); -#endif - - callno++; - - if (inchannels) - { - snd_pcm_status(alsa_device.inhandle, in_status); - if (snd_pcm_status_get_avail(in_status) < intransfersize) - return SENDDACS_NO; - } - if (outchannels) - { - snd_pcm_status(alsa_device.outhandle, out_status); - if (snd_pcm_status_get_avail(out_status) < outtransfersize) - return SENDDACS_NO; - } - - /* do output */ - if (outchannels) - { - fp = sys_soundout; - if (alsa_samplewidth == 4) - { - for (i = 0, fp1 = fp; i < outchannels; i++, fp1 += DACBLKSIZE) - { - for (j = i, k = DACBLKSIZE, fp2 = fp1; k--; - j += outchannels, fp2++) - { - float s1 = *fp2 * INT32_MAX; - ((t_alsa_sample32 *)alsa_buf)[j] = CLIP32(s1); - } - } - } - else - { - for (i = 0, fp1 = fp; i < outchannels; i++, fp1 += DACBLKSIZE) - { - for (j = i, k = DACBLKSIZE, fp2 = fp1; k--; - j += outchannels, fp2++) - { - int s = *fp2 * 32767.; - if (s > 32767) - s = 32767; - else if (s < -32767) - s = -32767; - ((t_alsa_sample16 *)alsa_buf)[j] = s; - } - } - } - - result = snd_pcm_writei(alsa_device.outhandle, alsa_buf, - outtransfersize); - if (result != (int)outtransfersize) - { - #ifdef DEBUG_ALSA_XFER - if (result >= 0 || errno == EAGAIN) - fprintf(stderr, "ALSA: write returned %d of %d\n", - result, outtransfersize); - else fprintf(stderr, "ALSA: write: %s\n", - snd_strerror(errno)); - fprintf(stderr, - "inputcount %d, outputcount %d, outbufsize %d\n", - inputcount, outputcount, - (ALSA_EXTRABUFFER + linux_advance_samples) - * alsa_samplewidth * outchannels); - #endif - sys_log_error(ERR_DACSLEPT); - return (SENDDACS_NO); - } - - /* zero out the output buffer */ - memset(sys_soundout, 0, DACBLKSIZE * sizeof(*sys_soundout) * - linux_outchannels); - if (sys_getrealtime() - timenow > 0.002) - { - #ifdef DEBUG_ALSA_XFER - fprintf(stderr, "output %d took %d msec\n", - callno, (int)(1000 * (timenow - timelast))), fflush(stderr); - #endif - timenow = sys_getrealtime(); - sys_log_error(ERR_DACSLEPT); - } - } - /* do input */ - if (linux_inchannels) - { - result = snd_pcm_readi(alsa_device.inhandle, alsa_buf, intransfersize); - if (result < (int)intransfersize) - { -#ifdef DEBUG_ALSA_XFER - if (result < 0) - fprintf(stderr, - "snd_pcm_read %d %d: %s\n", - callno, xferno, snd_strerror(errno)); - else fprintf(stderr, - "snd_pcm_read %d %d returned only %d\n", - callno, xferno, result); - fprintf(stderr, - "inputcount %d, outputcount %d, inbufsize %d\n", - inputcount, outputcount, - (ALSA_EXTRABUFFER + linux_advance_samples) - * alsa_samplewidth * inchannels); -#endif - sys_log_error(ERR_ADCSLEPT); - return (SENDDACS_NO); - } - fp = sys_soundin; - if (alsa_samplewidth == 4) - { - for (i = 0, fp1 = fp; i < inchannels; i++, fp1 += DACBLKSIZE) - { - for (j = i, k = DACBLKSIZE, fp2 = fp1; k--; - j += inchannels, fp2++) - *fp2 = (float) ((t_alsa_sample32 *)alsa_buf)[j] - * (1./ INT32_MAX); - } - } - else - { - for (i = 0, fp1 = fp; i < inchannels; i++, fp1 += DACBLKSIZE) - { - for (j = i, k = DACBLKSIZE, fp2 = fp1; k--; j += inchannels, - fp2++) - *fp2 = (float) ((t_alsa_sample16 *)alsa_buf)[j] - * 3.051850e-05; - } - } - } - xferno++; - if (sys_getrealtime() - timenow > 0.002) - { -#ifdef DEBUG_ALSA_XFER - fprintf(stderr, "routine took %d msec\n", - (int)(1000 * (sys_getrealtime() - timenow))); -#endif - sys_log_error(ERR_ADCSLEPT); - } - return SENDDACS_YES; -} - -void alsa_resync( void) -{ - int i, result; - memset(alsa_buf, 0, - sizeof(char) * alsa_samplewidth * DACBLKSIZE * linux_outchannels); - for (i = 0; i < 100; i++) - { - result = snd_pcm_writei(alsa_device.outhandle, alsa_buf, - DACBLKSIZE); - if (result != (int)DACBLKSIZE) - break; - } - post("%d written", i); -} - - -#endif /* ALSA01 */ - -/*************************************************** - * Code using the RME_9652 API - */ - - /* - trying native device for future use of native memory map: - because of busmaster if you dont use the dac, you dont need - CPU Power und also no nearly no CPU-Power is used in device - - since always all DAs and ADs are synced (else they wouldnt work) - we use linux_dacs[0], linux_adcs[0] - */ - -#ifdef RME_HAMMERFALL - -#define RME9652_MAX_CHANNELS 26 - -#define RME9652_CH_PER_NATIVE_DEVICE 1 - -static int rme9652_dac_devices[RME9652_MAX_CHANNELS]; -static int rme9652_adc_devices[RME9652_MAX_CHANNELS]; - -static char rme9652_dsp_dac[] = "/dev/rme9652/C0da%d"; -static char rme9652_dsp_adc[] = "/dev/rme9652/C0ad%d"; - -static int num_of_rme9652_dac = 0; -static int num_of_rme9652_adc = 0; - -static int rme_soundindevonset = 1; -static int rme_soundoutdevonset = 1; - -void rme_soundindev(int which) -{ - rme_soundindevonset = which; -} - -void rme_soundoutdev(int which) -{ - rme_soundoutdevonset = which; -} - -void rme9652_configure(int dev, int fd,int srate, int dac) { - int orig, param, nblk; - audio_buf_info ainfo; - orig = param = srate; - - /* samplerate */ - - fprintf(stderr,"RME9652: configuring %d, fd=%d, sr=%d\n, dac=%d\n", - dev,fd,srate,dac); - - if (ioctl(fd,SNDCTL_DSP_SPEED,¶m) == -1) - fprintf(stderr,"RME9652: Could not set sampling rate for device\n"); - else if( orig != param ) - fprintf(stderr,"RME9652: sampling rate: wanted %d, got %d\n", - orig, param ); - - // setting the correct samplerate (could be different than expected) - srate = param; - - - /* setting resolution */ - - /* use ctrlpanel to change, experiment, channels 1 */ - - orig = param = AFMT_S16_BE; - if (ioctl(fd,SNDCTL_DSP_SETFMT,¶m) == -1) - fprintf(stderr,"RME9652: Could not set DSP format\n"); - else if( orig != param ) - fprintf(stderr,"RME9652: DSP format: wanted %d, got %d\n",orig, param ); - - /* setting channels */ - orig = param = RME9652_CH_PER_NATIVE_DEVICE; - - if (ioctl(fd,SNDCTL_DSP_CHANNELS,¶m) == -1) - fprintf(stderr,"RME9652: Could not set channels\n"); - else if( orig != param ) - fprintf(stderr,"RME9652: num channels: wanted %d, got %d\n",orig, param ); - - if (dac) - { - - /* use "free space" to learn the buffer size. Normally you - should set this to your own desired value; but this seems not - to be implemented uniformly across different sound cards. LATER - we should figure out what to do if the requested scheduler advance - is greater than this buffer size; for now, we just print something - out. */ - - if( ioctl(linux_dacs[0].d_fd, SOUND_PCM_GETOSPACE,&ainfo) < 0 ) - fprintf(stderr,"RME: ioctl on output device %d failed",dev); - - linux_dacs[0].d_bufsize = ainfo.bytes; - - fprintf(stderr,"RME: ioctl SOUND_PCM_GETOSPACE says %d buffsize\n", - linux_dacs[0].d_bufsize); - - - if (linux_advance_samples * (RME_SAMPLEWIDTH * - RME9652_CH_PER_NATIVE_DEVICE) - > linux_dacs[0].d_bufsize - RME_BYTESPERCHAN) - { - fprintf(stderr, - "RME: requested audio buffer size %d limited to %d\n", - linux_advance_samples - * (RME_SAMPLEWIDTH * RME9652_CH_PER_NATIVE_DEVICE), - linux_dacs[0].d_bufsize); - linux_advance_samples = - (linux_dacs[0].d_bufsize - RME_BYTESPERCHAN) - / (RME_SAMPLEWIDTH *RME9652_CH_PER_NATIVE_DEVICE); - } - } -} - - -int rme9652_open_audio(int inchans, int outchans,int srate) -{ - int orig; - int tmp; - int inchannels = 0,outchannels = 0; - char devname[20]; - int i; - char buf[RME_SAMPLEWIDTH*RME9652_CH_PER_NATIVE_DEVICE*DACBLKSIZE]; - int num_devs = 0; - audio_buf_info ainfo; - - linux_nindevs = linux_noutdevs = 0; - - if (sys_verbose) - post("RME open"); - /* First check if we can */ - /* open the write ports */ - - for (num_devs=0; outchannels < outchans; num_devs++) - { - int channels = RME9652_CH_PER_NATIVE_DEVICE; - - sprintf(devname, rme9652_dsp_dac, num_devs + rme_soundoutdevonset); - if ((tmp = open(devname,O_WRONLY)) == -1) - { - DEBUG(fprintf(stderr,"RME9652: failed to open %s writeonly\n", - devname);) - break; - } - DEBUG(fprintf(stderr,"RME9652: out device Nr. %d (%d) on %s\n", - linux_noutdevs+1,tmp,devname);) - - if (outchans > outchannels) - { - rme9652_dac_devices[linux_noutdevs] = tmp; - linux_noutdevs++; - outchannels += channels; - } - else close(tmp); - } - if( linux_noutdevs > 0) - linux_dacs[0].d_fd = rme9652_dac_devices[0]; - - /* Second check if we can */ - /* open the read ports */ - - for (num_devs=0; inchannels < inchans; num_devs++) - { - int channels = RME9652_CH_PER_NATIVE_DEVICE; - - sprintf(devname, rme9652_dsp_adc, num_devs+rme_soundindevonset); - - if ((tmp = open(devname,O_RDONLY)) == -1) - { - DEBUG(fprintf(stderr,"RME9652: failed to open %s readonly\n", - devname);) - break; - } - DEBUG(fprintf(stderr,"RME9652: in device Nr. %d (%d) on %s\n", - linux_nindevs+1,tmp,devname);) - - if (inchans > inchannels) - { - rme9652_adc_devices[linux_nindevs] = tmp; - linux_nindevs++; - inchannels += channels; - } - else - close(tmp); - } - if(linux_nindevs > 0) - linux_adcs[0].d_fd = rme9652_adc_devices[0]; - - /* configure soundcards */ - - rme9652_configure(0, linux_adcs[0].d_fd,srate, 0); - rme9652_configure(0, linux_dacs[0].d_fd,srate, 1); - - /* We have to do a read to start the engine. This is - necessary because sys_send_dacs waits until the input - buffer is filled and only reads on a filled buffer. - This is good, because it's a way to make sure that we - will not block */ - - if (linux_nindevs) - { - fprintf(stderr,("RME9652: starting read engine ... ")); - - - for (num_devs=0; num_devs < linux_nindevs; num_devs++) - read(rme9652_adc_devices[num_devs], - buf, RME_SAMPLEWIDTH* RME9652_CH_PER_NATIVE_DEVICE* - DACBLKSIZE); - - - for (num_devs=0; num_devs < linux_noutdevs; num_devs++) - write(rme9652_dac_devices[num_devs], - buf, RME_SAMPLEWIDTH* RME9652_CH_PER_NATIVE_DEVICE* - DACBLKSIZE); - - if(linux_noutdevs) - ioctl(rme9652_dac_devices[0],SNDCTL_DSP_SYNC); - - fprintf(stderr,"done\n"); - } - - linux_setsr(srate); - linux_setch(linux_nindevs, linux_noutdevs); - - num_of_rme9652_dac = linux_noutdevs; - num_of_rme9652_adc = linux_nindevs; - - if(linux_noutdevs)linux_noutdevs=1; - if(linux_nindevs)linux_nindevs=1; - - /* trick RME9652 behaves as one device fromread write pointers */ - return (0); -} - -void rme9652_close_audio( void) -{ - int i; - for (i=0;i>2;i--;) - { - float s1 = *(fp1+=4) * INT32_MAX; - float s2 = *(fp2+=4) * INT32_MAX; - float s3 = *(fp3+=4) * INT32_MAX; - float s4 = *(fp4+=4) * INT32_MAX; - - *(a+=4) = CLIP32(s1); - *(b+=4) = CLIP32(s2); - *(c+=4) = CLIP32(s3); - *(d+=4) = CLIP32(s4); - } - - linux_dacs_write(rme9652_dac_devices[j],buf,RME_BYTESPERCHAN); - } - } - - if ((timenow = sys_getrealtime()) - timeref > 0.02) - sys_log_error(ERR_DACSLEPT); - timeref = timenow; - } - - memset(sys_soundout, 0, - linux_outchannels * (sizeof(float) * DACBLKSIZE)); - - /* do input */ - - if(linux_nindevs) { - - for(j=0;j 0.02) - sys_log_error(ERR_ADCSLEPT); - timeref = timenow; - { - t_rme_sample *a,*b,*c,*d; - float *fp1,*fp2,*fp3,*fp4; - - fp1 = sys_soundin + j*DACBLKSIZE-4; - fp2 = fp1 + 1; - fp3 = fp1 + 2; - fp4 = fp1 + 3; - a = buf-4; - b=a+1; - c=a+2; - d=a+3; - - for (i = (DACBLKSIZE>>2);i--;) - { - *(fp1+=4) = *(a+=4) * (float)(1./INT32_MAX); - *(fp2+=4) = *(b+=4) * (float)(1./INT32_MAX); - *(fp3+=4) = *(c+=4) * (float)(1./INT32_MAX); - *(fp4+=4) = *(d+=4) * (float)(1./INT32_MAX); - } - } - } - } - /* fprintf(stderr,"ready \n");*/ - - return (1); -} - -#endif /* RME_HAMMERFALL */ diff --git a/pd/src/s_inter.c b/pd/src/s_inter.c index 004820f6..d5beb866 100644 --- a/pd/src/s_inter.c +++ b/pd/src/s_inter.c @@ -109,7 +109,9 @@ double nt_tixtotime(LARGE_INTEGER *dumbass) #endif #endif /* MSW */ -double sys_getrealtime(void) /* get "real time" in seconds */ + /* get "real time" in seconds; take the + first time we get called as a reference time of zero. */ +double sys_getrealtime(void) { #ifdef UNIX static struct timeval then; @@ -843,6 +845,7 @@ int sys_startgui(const char *guidir) if (!sys_nogui) { + char buf[256]; if (sys_verbose) fprintf(stderr, "Waiting for connection request... \n"); if (listen(xsock, 5) < 0) sys_sockerror("listen"); @@ -861,8 +864,8 @@ int sys_startgui(const char *guidir) /* here is where we start the pinging. */ if (sys_hipriority) sys_gui("pdtk_watchdog\n"); - - sys_vgui("pdtk_pd_startup {%s}\n", pd_version); + sys_get_audio_apis(buf); + sys_vgui("pdtk_pd_startup {%s} %s\n", pd_version, buf); } return (0); @@ -894,8 +897,9 @@ void sys_bail(int n) sys_close_midi(); fprintf(stderr, "... done.\n"); #endif + exit(1); } - _exit(n); + else _exit(n); } void glob_quit(void *dummy) diff --git a/pd/src/s_linux.c b/pd/src/s_linux.c deleted file mode 100644 index 54cdb978..00000000 --- a/pd/src/s_linux.c +++ /dev/null @@ -1,3087 +0,0 @@ -/* Copyright (c) 1997-1999 Guenter Geiger, Miller Puckette, Larry Troxler, -* Winfried Ritsch, Karl MacMillan, and others. -* For information on usage and redistribution, and for a DISCLAIMER OF ALL -* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ - -/* this file implements the sys_ functions profiled in m_imp.h for - audio and MIDI I/O. In Linux there might be several APIs for doing the - audio part; right now there are three (OSS, ALSA, RME); the third is - for the RME 9652 driver by Ritsch (but not for the OSS compatible - one by Geiger; for that one, OSS should work.) - - FUNCTION PREFIXES. - sys_ -- functions which must be exported to Pd on all platforms - linux_ -- linux-specific objects which don't depend on API, - mostly static but some exported. - oss_, alsa_, rme_ -- API-specific functions, all of which are - static. - - ALSA SUPPORT. If ALSA99 is defined we support ALSA 0.5x; if ALSA01, - ALSA 0.9x. (the naming scheme reflects the possibility of further API - changes in the future...) We define "ALSA" for code relevant to both - APIs. - - For MIDI, we only offer the OSS API; ALSA has to emulate OSS for us. -*/ - -/* OSS include (whether we're doing OSS audio or not we need this for MIDI) */ - - -/* IOhannes::: - * hacked this to add advanced multidevice-support - * 1311:forum::für::umläute:2001 - */ - -#include - -#if (defined(ALSA01) || defined(ALSA99)) -#define ALSA -#endif - -#ifdef ALSA99 -#include -#endif -#ifdef ALSA01 -#include -#endif - -#include "m_imp.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* local function prototypes */ - -static void linux_close_midi( void); - -static int oss_open_audio(int naudioindev, int *audioindev, int nchindev, - int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev, - int *choutdev, int rate); /* IOhannes */ - -static void oss_close_audio(void); -static int oss_send_dacs(void); -static void oss_reportidle(void); - -#ifdef ALSA -typedef int16_t t_alsa_sample16; -typedef int32_t t_alsa_sample32; -#define ALSA_SAMPLEWIDTH_16 sizeof(t_alsa_sample16) -#define ALSA_SAMPLEWIDTH_32 sizeof(t_alsa_sample32) -#define ALSA_XFERSIZE16 (signed int)(sizeof(t_alsa_sample16) * DACBLKSIZE) -#define ALSA_XFERSIZE32 (signed int)(sizeof(t_alsa_sample32) * DACBLKSIZE) -#define ALSA_MAXDEV 1 -#define ALSA_JITTER 1024 -#define ALSA_EXTRABUFFER 2048 -#define ALSA_DEFFRAGSIZE 64 -#define ALSA_DEFNFRAG 12 - -#ifdef ALSA99 -typedef struct _alsa_dev -{ - snd_pcm_t *handle; - snd_pcm_channel_info_t info; - snd_pcm_channel_setup_t setup; -} t_alsa_dev; - -t_alsa_dev alsa_device[ALSA_MAXDEV]; -static int n_alsa_dev; -static char *alsa_buf; -static int alsa_samplewidth; -#endif /* ALSA99 */ - -#ifdef ALSA01 -typedef struct _alsa_dev -{ - snd_pcm_t *inhandle; - snd_pcm_t *outhandle; -} t_alsa_dev; - -t_alsa_dev alsa_device; -static short *alsa_buf; -static int alsa_samplewidth; -static snd_pcm_status_t* in_status; -static snd_pcm_status_t* out_status; -#endif /* ALSA01 */ - -#if 0 /* early alsa 0.9 beta dists had different names for these: */ -#define SND_PCM_ACCESS_RW_INTERLEAVED SNDRV_PCM_ACCESS_RW_INTERLEAVED -#define SND_PCM_FORMAT_S32 SNDRV_PCM_FORMAT_S32 -#define SND_PCM_FORMAT_S16 SNDRV_PCM_FORMAT_S16 -#define SND_PCM_SUBFORMAT_STD SNDRV_PCM_SUBFORMAT_STD -#endif - -static int alsa_mode; -static int alsa_open_audio(int inchans, int outchans, int rate); -static void alsa_close_audio(void); -static int alsa_send_dacs(void); -static void alsa_set_params(t_alsa_dev *dev, int dir, int rate, int voices); -static void alsa_reportidle(void); -#endif /* ALSA */ - -#ifdef RME_HAMMERFALL -static int rme9652_open_audio(int inchans, int outchans, int rate); -static void rme9652_close_audio(void); -static int rme9652_send_dacs(void); -static void rme9652_reportidle(void); -#endif /* RME_HAMMERFALL */ - -/* Defines */ -#define DEBUG(x) x -#define DEBUG2(x) {x;} - -#define OSS_MAXCHPERDEV 32 /* max channels per OSS device */ -#define OSS_MAXDEV 4 /* maximum number of input or output devices */ -#define OSS_DEFFRAGSIZE 256 /* default log fragment size (frames) */ -#define OSS_DEFAUDIOBUF 40000 /* default audiobuffer, microseconds */ -#define OSS_DEFAULTCH 2 -#define RME_DEFAULTCH 8 /* need this even if RME undefined */ -typedef int16_t t_oss_int16; -typedef int32_t t_oss_int32; -#define OSS_MAXSAMPLEWIDTH sizeof(t_oss_int32) -#define OSS_BYTESPERCHAN(width) (DACBLKSIZE * (width)) -#define OSS_XFERSAMPS(chans) (DACBLKSIZE* (chans)) -#define OSS_XFERSIZE(chans, width) (DACBLKSIZE * (chans) * (width)) - -#ifdef RME_HAMMERFALL -typedef int32_t t_rme_sample; -#define RME_SAMPLEWIDTH sizeof(t_rme_sample) -#define RME_BYTESPERCHAN (DACBLKSIZE * RME_SAMPLEWIDTH) -#endif /* RME_HAMMERFALL */ - -/* GLOBALS */ -static int linux_whichapi = API_OSS; -static int linux_inchannels; -static int linux_outchannels; -static int linux_advance_samples; /* scheduler advance in samples */ -static int linux_meters; /* true if we're metering */ -static float linux_inmax; /* max input amplitude */ -static float linux_outmax; /* max output amplitude */ -static int linux_fragsize = 0; /* for block mode; block size (sample frames) */ -static int linux_nfragment = 0; /* ... and number of blocks. */ - -#ifdef ALSA99 -static int alsa_devno = 1; -#endif -#ifdef ALSA01 -static char alsa_devname[512] = "hw:0,0"; -static int alsa_use_plugin = 0; -#endif - -/* our device handles */ - -typedef struct _oss_dev -{ - int d_fd; - unsigned int d_space; /* bytes available for writing/reading */ - int d_bufsize; /* total buffer size in blocks for this device */ - int d_dropcount; /* # of buffers to drop for resync (output only) */ - unsigned int d_nchannels; /* number of channels for this device */ - unsigned int d_bytespersamp; /* bytes per sample (2 for 16 bit, 4 for 32) */ -} t_oss_dev; - -static t_oss_dev linux_dacs[OSS_MAXDEV]; -static t_oss_dev linux_adcs[OSS_MAXDEV]; -static int linux_noutdevs = 0; -static int linux_nindevs = 0; - - /* exported variables */ -int sys_schedadvance = OSS_DEFAUDIOBUF; /* scheduler advance in microsecs */ -float sys_dacsr; -int sys_hipriority = 0; -t_sample *sys_soundout; -t_sample *sys_soundin; - - /* OSS-specific private variables */ -static int oss_blockmode = 1; /* flag to use "blockmode" */ -static int oss_32bit = 0; /* allow 23 bit transfers in OSS */ -static char ossdsp[] = "/dev/dsp%d"; - -#ifndef INT32_MAX -#define INT32_MAX 0x7fffffff -#endif - /* don't assume we can turn all 31 bits when doing float-to-fix; - otherwise some audio drivers (e.g. Midiman/ALSA) wrap around. */ -#define FMAX 0x7ffff000 -#define CLIP32(x) (((x)>FMAX)?FMAX:((x) < -FMAX)?-FMAX:(x)) - - -/* ------------- private routines for all APIS ------------------- */ - -static void linux_flush_all_underflows_to_zero(void) -{ -/* - TODO: Implement similar thing for linux (GGeiger) - - One day we will figure this out, I hope, because it - costs CPU time dearly on Intel - LT - */ - /* union fpc_csr f; - f.fc_word = get_fpc_csr(); - f.fc_struct.flush = 1; - set_fpc_csr(f.fc_word); - */ -} - - /* set sample rate and channels. Must set sample rate before "configuring" - any devices so we know scheduler advance in samples. */ - -static void linux_setsr(int sr) -{ - sys_dacsr = sr; - linux_advance_samples = (sys_schedadvance * sys_dacsr) / (1000000.); - if (linux_advance_samples < 3 * DACBLKSIZE) - linux_advance_samples = 3 * DACBLKSIZE; -} - -static void linux_setch(int chin, int chout) -{ - int nblk; - int inbytes = chin * (DACBLKSIZE*sizeof(float)); - int outbytes = chout * (DACBLKSIZE*sizeof(float)); - - linux_inchannels = chin; - linux_outchannels = chout; - if (sys_soundin) - free(sys_soundin); - sys_soundin = (t_float *)malloc(inbytes); - memset(sys_soundin, 0, inbytes); - - if (sys_soundout) - free(sys_soundout); - sys_soundout = (t_float *)malloc(outbytes); - memset(sys_soundout, 0, outbytes); - - if (sys_verbose) - post("input channels = %d, output channels = %d", - linux_inchannels, linux_outchannels); -} - -/* ---------------- MIDI routines -------------------------- */ - -static int oss_nmidiin; -static int oss_midiinfd[MAXMIDIINDEV]; -static int oss_nmidiout; -static int oss_midioutfd[MAXMIDIOUTDEV]; - -static void oss_midiout(int fd, int n) -{ - char b = n; - if ((write(fd, (char *) &b, 1)) != 1) - perror("midi write"); -} - -#define O_MIDIFLAG O_NDELAY - -void linux_open_midi(int nmidiin, int *midiinvec, int nmidiout, int *midioutvec) -{ - int i; - for (i = 0; i < nmidiout; i++) - oss_midioutfd[i] = -1; - for (i = 0, oss_nmidiin = 0; i < nmidiin; i++) - { - int fd = -1, j, outdevindex = -1; - char namebuf[80]; - int devno = midiinvec[i]; - - for (j = 0; j < nmidiout; j++) - if (midioutvec[j] == midiinvec[i]) - outdevindex = j; - - /* try to open the device for read/write. */ - if (devno == 1 && fd < 0 && outdevindex >= 0) - { - sys_setalarm(1000000); - fd = open("/dev/midi", O_RDWR | O_MIDIFLAG); - if (sys_verbose) - fprintf(stderr, - "device 1: tried /dev/midi READ/WRITE; returned %d\n", fd); - if (outdevindex >= 0 && fd >= 0) - oss_midioutfd[outdevindex] = fd; - } - if (fd < 0 && outdevindex >= 0) - { - sys_setalarm(1000000); - sprintf(namebuf, "/dev/midi%2.2d", devno-1); - fd = open(namebuf, O_RDWR | O_MIDIFLAG); - if (sys_verbose) - fprintf(stderr, - "device %d: tried %s READ/WRITE; returned %d\n", - devno, namebuf, fd); - if (outdevindex >= 0 && fd >= 0) - oss_midioutfd[outdevindex] = fd; - } - if (fd < 0 && outdevindex >= 0) - { - sys_setalarm(1000000); - sprintf(namebuf, "/dev/midi%d", devno-1); - fd = open(namebuf, O_RDWR | O_MIDIFLAG); - if (sys_verbose) - fprintf(stderr, "device %d: tried %s READ/WRITE; returned %d\n", - devno, namebuf, fd); - if (outdevindex >= 0 && fd >= 0) - oss_midioutfd[outdevindex] = fd; - } - if (devno == 1 && fd < 0) - { - sys_setalarm(1000000); - fd = open("/dev/midi", O_RDONLY | O_MIDIFLAG); - if (sys_verbose) - fprintf(stderr, - "device 1: tried /dev/midi READONLY; returned %d\n", fd); - } - if (fd < 0) - { - sys_setalarm(1000000); - sprintf(namebuf, "/dev/midi%2.2d", devno-1); - fd = open(namebuf, O_RDONLY | O_MIDIFLAG); - if (sys_verbose) - fprintf(stderr, "device %d: tried %s READONLY; returned %d\n", - devno, namebuf, fd); - } - if (fd < 0) - { - sys_setalarm(1000000); - sprintf(namebuf, "/dev/midi%d", devno-1); - fd = open(namebuf, O_RDONLY | O_MIDIFLAG); - if (sys_verbose) - fprintf(stderr, "device %d: tried %s READONLY; returned %d\n", - devno, namebuf, fd); - } - if (fd >= 0) - oss_midiinfd[oss_nmidiin++] = fd; - else post("couldn't open MIDI input device %d", devno); - } - for (i = 0, oss_nmidiout = 0; i < nmidiout; i++) - { - int fd = oss_midioutfd[i]; - char namebuf[80]; - int devno = midioutvec[i]; - if (devno == 1 && fd < 0) - { - sys_setalarm(1000000); - fd = open("/dev/midi", O_WRONLY | O_MIDIFLAG); - if (sys_verbose) - fprintf(stderr, - "device 1: tried /dev/midi WRITEONLY; returned %d\n", fd); - } - if (fd < 0) - { - sys_setalarm(1000000); - sprintf(namebuf, "/dev/midi%2.2d", devno-1); - fd = open(namebuf, O_WRONLY | O_MIDIFLAG); - if (sys_verbose) - fprintf(stderr, "device %d: tried %s WRITEONLY; returned %d\n", - devno, namebuf, fd); - } - if (fd < 0) - { - sys_setalarm(1000000); - sprintf(namebuf, "/dev/midi%d", devno-1); - fd = open(namebuf, O_WRONLY | O_MIDIFLAG); - if (sys_verbose) - fprintf(stderr, "device %d: tried %s WRITEONLY; returned %d\n", - devno, namebuf, fd); - } - if (fd >= 0) - oss_midioutfd[oss_nmidiout++] = fd; - else post("couldn't open MIDI output device %d", devno); - } - - if (oss_nmidiin < nmidiin || oss_nmidiout < nmidiout || sys_verbose) - post("opened %d MIDI input device(s) and %d MIDI output device(s).", - oss_nmidiin, oss_nmidiout); -} - -#define md_msglen(x) (((x)<0xC0)?2:((x)<0xE0)?1:((x)<0xF0)?2:\ - ((x)==0xF2)?2:((x)<0xF4)?1:0) - -void sys_putmidimess(int portno, int a, int b, int c) -{ - if (portno >= 0 && portno < oss_nmidiout) - { - switch (md_msglen(a)) - { - case 2: - oss_midiout(oss_midioutfd[portno],a); - oss_midiout(oss_midioutfd[portno],b); - oss_midiout(oss_midioutfd[portno],c); - return; - case 1: - oss_midiout(oss_midioutfd[portno],a); - oss_midiout(oss_midioutfd[portno],b); - return; - case 0: - oss_midiout(oss_midioutfd[portno],a); - return; - }; - } -} - -void sys_putmidibyte(int portno, int byte) -{ - if (portno >= 0 && portno < oss_nmidiout) - oss_midiout(oss_midioutfd[portno], byte); -} - -#if 0 /* this is the "select" version which doesn't work with OSS - driver for emu10k1 (it doesn't implement select.) */ -void sys_poll_midi(void) -{ - int i, throttle = 100; - struct timeval timout; - int did = 1, maxfd = 0; - while (did) - { - fd_set readset, writeset, exceptset; - did = 0; - if (throttle-- < 0) - break; - timout.tv_sec = 0; - timout.tv_usec = 0; - - FD_ZERO(&writeset); - FD_ZERO(&readset); - FD_ZERO(&exceptset); - for (i = 0; i < oss_nmidiin; i++) - { - if (oss_midiinfd[i] > maxfd) - maxfd = oss_midiinfd[i]; - FD_SET(oss_midiinfd[i], &readset); - } - select(maxfd+1, &readset, &writeset, &exceptset, &timout); - for (i = 0; i < oss_nmidiin; i++) - if (FD_ISSET(oss_midiinfd[i], &readset)) - { - char c; - int ret = read(oss_midiinfd[i], &c, 1); - if (ret <= 0) - fprintf(stderr, "Midi read error\n"); - else sys_midibytein(i, (c & 0xff)); - did = 1; - } - } -} -#else - - /* this version uses the asynchronous "read()" ... */ -void sys_poll_midi(void) -{ - int i, throttle = 100; - struct timeval timout; - int did = 1, maxfd = 0; - while (did) - { - fd_set readset, writeset, exceptset; - did = 0; - if (throttle-- < 0) - break; - for (i = 0; i < oss_nmidiin; i++) - { - char c; - int ret = read(oss_midiinfd[i], &c, 1); - if (ret < 0) - { - if (errno != EAGAIN) - perror("MIDI"); - } - else if (ret != 0) - { - sys_midibytein(i, (c & 0xff)); - did = 1; - } - } - } -} -#endif - -void linux_close_midi() -{ - int i; - for (i = 0; i < oss_nmidiin; i++) - close(oss_midiinfd[i]); - for (i = 0; i < oss_nmidiout; i++) - close(oss_midioutfd[i]); - oss_nmidiin = oss_nmidiout = 0; -} - -#define MAXAUDIODEV 4 -#define DEFAULTINDEV 1 -#define DEFAULTOUTDEV 1 - -/* ----------------------- public routines ----------------------- */ -void sys_listdevs( void) -{ - post("device listing not implemented in Linux yet\n"); -} - -void sys_open_audio(int naudioindev, int *audioindev, int nchindev, - int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev, - int *choutdev, int rate) -{ /* IOhannes */ - int i, *ip; - int defaultchannels = - (linux_whichapi == API_RME ? RME_DEFAULTCH : OSS_DEFAULTCH); - if (rate < 1) - rate=44100; - - if (naudioindev == -1) - { /* not set */ - if (nchindev==-1) - { - nchindev=1; - chindev[0]=defaultchannels; - naudioindev=1; - audioindev[0] = DEFAULTINDEV; - } - else - { - for (i = 0; i < MAXAUDIODEV; i++) - audioindev[i]=i+1; - naudioindev = nchindev; - } - } - else - { - if (nchindev == -1) - { - nchindev = naudioindev; - for (i = 0; i < naudioindev; i++) - chindev[i] = defaultchannels; - } - else if (nchindev > naudioindev) - { - for (i = naudioindev; i < nchindev; i++) - { - if (i == 0) - audioindev[0] = DEFAULTINDEV; - else audioindev[i] = audioindev[i-1] + 1; - } - naudioindev = nchindev; - } - else if (nchindev < naudioindev) - { - for (i = nchindev; i < naudioindev; i++) - { - if (i == 0) - chindev[0] = defaultchannels; - else chindev[i] = chindev[i-1]; - } - naudioindev = nchindev; - } - } - - if (naudiooutdev == -1) - { /* not set */ - if (nchoutdev==-1) - { - nchoutdev=1; - choutdev[0]=defaultchannels; - naudiooutdev=1; - audiooutdev[0] = DEFAULTOUTDEV; - } - else - { - for (i = 0; i < MAXAUDIODEV; i++) - audiooutdev[i] = i+1; - naudiooutdev = nchoutdev; - } - } - else - { - if (nchoutdev == -1) - { - nchoutdev = naudiooutdev; - for (i = 0; i < naudiooutdev; i++) - choutdev[i] = defaultchannels; - } - else if (nchoutdev > naudiooutdev) - { - for (i = naudiooutdev; i < nchoutdev; i++) - { - if (i == 0) - audiooutdev[0] = DEFAULTOUTDEV; - else audiooutdev[i] = audiooutdev[i-1] + 1; - } - naudiooutdev = nchoutdev; - } - else if (nchoutdev < naudiooutdev) - { - for (i = nchoutdev; i < naudiooutdev; i++) - { - if (i == 0) - choutdev[0] = defaultchannels; - else choutdev[i] = choutdev[i-1]; - } - naudiooutdev = nchoutdev; - } - } - - linux_flush_all_underflows_to_zero(); -#ifdef ALSA - if (linux_whichapi == API_ALSA) - alsa_open_audio((naudioindev > 0 ? chindev[0] : 0), - (naudiooutdev > 0 ? choutdev[0] : 0), rate); - else -#endif -#ifdef RME_HAMMERFALL - if (linux_whichapi == API_RME) - rme9652_open_audio((naudioindev > 0 ? chindev[0] : 0), - (naudiooutdev > 0 ? choutdev[0] : 0), rate); - else -#endif - oss_open_audio(naudioindev, audioindev, nchindev, chindev, - naudiooutdev, audiooutdev, nchoutdev, choutdev, rate); -} - -void sys_close_audio(void) -{ - /* set timeout to avoid hanging close() call */ - - sys_setalarm(1000000); - -#ifdef ALSA - if (linux_whichapi == API_ALSA) - alsa_close_audio(); - else -#endif -#ifdef RME_HAMMERFALL - if (linux_whichapi == API_RME) - rme9652_close_audio(); - else -#endif - oss_close_audio(); - - sys_setalarm(0); -} - -void sys_open_midi(int nmidiin, int *midiinvec, - int nmidiout, int *midioutvec) -{ - linux_open_midi(nmidiin, midiinvec, nmidiout, midioutvec); -} - -void sys_close_midi( void) -{ - sys_setalarm(1000000); - linux_close_midi(); - sys_setalarm(0); -} - -int sys_send_dacs(void) -{ - if (linux_meters) - { - int i, n; - float maxsamp; - for (i = 0, n = linux_inchannels * DACBLKSIZE, maxsamp = linux_inmax; - i < n; i++) - { - float f = sys_soundin[i]; - if (f > maxsamp) maxsamp = f; - else if (-f > maxsamp) maxsamp = -f; - } - linux_inmax = maxsamp; - for (i = 0, n = linux_outchannels * DACBLKSIZE, maxsamp = linux_outmax; - i < n; i++) - { - float f = sys_soundout[i]; - if (f > maxsamp) maxsamp = f; - else if (-f > maxsamp) maxsamp = -f; - } - linux_outmax = maxsamp; - } -#ifdef ALSA - if (linux_whichapi == API_ALSA) - return alsa_send_dacs(); -#endif -#ifdef RME_HAMMERFALL - if (linux_whichapi == API_RME) - return rme9652_send_dacs(); -#endif - return oss_send_dacs(); -} - -float sys_getsr(void) -{ - return (sys_dacsr); -} - -int sys_get_outchannels(void) -{ - return (linux_outchannels); -} - -int sys_get_inchannels(void) -{ - return (linux_inchannels); -} - -void sys_audiobuf(int n) -{ - /* set the size, in milliseconds, of the audio FIFO */ - if (n < 5) n = 5; - else if (n > 5000) n = 5000; - sys_schedadvance = n * 1000; -} - -void sys_getmeters(float *inmax, float *outmax) -{ - if (inmax) - { - linux_meters = 1; - *inmax = linux_inmax; - *outmax = linux_outmax; - } - else - linux_meters = 0; - linux_inmax = linux_outmax = 0; -} - -void sys_reportidle(void) -{ -} - -void sys_set_priority(int higher) -{ - struct sched_param par; - int p1 ,p2, p3; -#ifdef _POSIX_PRIORITY_SCHEDULING - - p1 = sched_get_priority_min(SCHED_FIFO); - p2 = sched_get_priority_max(SCHED_FIFO); - p3 = (higher ? p2 - 1 : p2 - 3); - par.sched_priority = p3; - - if (sched_setscheduler(0,SCHED_FIFO,&par) != -1) - fprintf(stderr, "priority %d scheduling enabled.\n", p3); -#endif - -#ifdef _POSIX_MEMLOCK - if (mlockall(MCL_FUTURE) != -1) - fprintf(stderr, "memory locking enabled.\n"); -#endif -} - -void sys_setblocksize(int n) -{ - if (n < 1) - n = 1; - linux_fragsize = n; - oss_blockmode = 1; -} - -/* ------------ linux-specific command-line flags -------------- */ - -void linux_setfrags(int n) -{ - linux_nfragment = n; - oss_blockmode = 1; -} - -void linux_streammode( void) -{ - oss_blockmode = 0; -} - -void linux_32bit( void) -{ - oss_32bit = 1; -} - -void linux_set_sound_api(int which) -{ - linux_whichapi = which; - if (sys_verbose) - post("linux_whichapi %d", linux_whichapi); -} - -#ifdef ALSA99 -void linux_alsa_devno(int devno) -{ - alsa_devno = devno; -} - -#endif - -#ifdef ALSA01 -void linux_alsa_devname(char *devname) -{ - strncpy(alsa_devname, devname, 511); -} - -void linux_alsa_use_plugin(int t) -{ - if (t == 1) - alsa_use_plugin = 1; - else - alsa_use_plugin = 0; -} - -#endif - -/* -------------- Audio I/O using the OSS API ------------------ */ - -typedef struct _multidev { - int fd; - int channels; - int format; -} t_multidev; - -int oss_reset(int fd) { - int err; - if ((err = ioctl(fd,SNDCTL_DSP_RESET)) < 0) - error("OSS: Could not reset"); - return err; -} - - /* The AFMT_S32_BLOCKED format is not defined in standard linux kernels - but is proposed by Guenter Geiger to support extending OSS to handle - 32 bit sample. This is user in Geiger's OSS driver for RME Hammerfall. - I'm not clear why this isn't called AFMT_S32_[SLN]E... */ - -#ifndef AFMT_S32_BLOCKED -#define AFMT_S32_BLOCKED 0x0000400 -#endif - -void oss_configure(t_oss_dev *dev, int srate, int dac, int skipblocksize) -{ /* IOhannes */ - int orig, param, nblk, fd = dev->d_fd, wantformat; - int nchannels = dev->d_nchannels; - int advwas = sys_schedadvance; - - audio_buf_info ainfo; - - /* IOhannes : - * pd is very likely to crash if different formats are used on - multiple soundcards - */ - - /* set resolution - first try 4 byte samples */ - if (oss_32bit && (ioctl(fd,SNDCTL_DSP_GETFMTS,¶m) >= 0) && - (param & AFMT_S32_BLOCKED)) - { - wantformat = AFMT_S32_BLOCKED; - dev->d_bytespersamp = 4; - } - else - { - wantformat = AFMT_S16_NE; - dev->d_bytespersamp = 2; - } - param = wantformat; - - if (sys_verbose) - post("bytes per sample = %d", dev->d_bytespersamp); - if (ioctl(fd, SNDCTL_DSP_SETFMT, ¶m) == -1) - fprintf(stderr,"OSS: Could not set DSP format\n"); - else if (wantformat != param) - fprintf(stderr,"OSS: DSP format: wanted %d, got %d\n", - wantformat, param); - - /* sample rate */ - orig = param = srate; - if (ioctl(fd, SNDCTL_DSP_SPEED, ¶m) == -1) - fprintf(stderr,"OSS: Could not set sampling rate for device\n"); - else if( orig != param ) - fprintf(stderr,"OSS: sampling rate: wanted %d, got %d\n", - orig, param ); - - if (oss_blockmode && !skipblocksize) - { - int fragbytes, logfragsize, nfragment; - /* setting fragment count and size. */ - if (linux_nfragment) /* if nfrags specified, take literally */ - { - nfragment = linux_nfragment; - if (!linux_fragsize) - linux_fragsize = OSS_DEFFRAGSIZE; - sys_schedadvance = ((nfragment * linux_fragsize) * 1.e6) - / (float)srate; - linux_setsr(srate); - } - else - { - if (!linux_fragsize) - { - linux_fragsize = OSS_DEFFRAGSIZE; - while (linux_fragsize > DACBLKSIZE - && linux_fragsize * 4 > linux_advance_samples) - linux_fragsize = linux_fragsize/2; - } - /* post("adv_samples %d", linux_advance_samples); */ - nfragment = (sys_schedadvance * (44100. * 1.e-6)) / linux_fragsize; - } - fragbytes = linux_fragsize * (dev->d_bytespersamp * nchannels); - logfragsize = ilog2(fragbytes); - - if (fragbytes != (1 << logfragsize)) - post("warning: OSS takes only power of 2 blocksize; using %d", - (1 << logfragsize)/(dev->d_bytespersamp * nchannels)); - if (sys_verbose) - post("setting nfrags = %d, fragsize %d\n", nfragment, fragbytes); - - param = orig = (nfragment<<16) + logfragsize; - if (ioctl(fd,SNDCTL_DSP_SETFRAGMENT, ¶m) == -1) - error("OSS: Could not set or read fragment size\n"); - if (param != orig) - { - nfragment = ((param >> 16) & 0xffff); - logfragsize = (param & 0xffff); - post("warning: actual fragments %d, blocksize %d", - nfragment, (1 << logfragsize)); - } - if (sys_verbose) - post("audiobuffer set to %d msec", (int)(0.001 * sys_schedadvance)); - } - - if (dac) - { - /* use "free space" to learn the buffer size. Normally you - should set this to your own desired value; but this seems not - to be implemented uniformly across different sound cards. LATER - we should figure out what to do if the requested scheduler advance - is greater than this buffer size; for now, we just print something - out. */ - - int defect; - if (ioctl(fd, SOUND_PCM_GETOSPACE,&ainfo) < 0) - fprintf(stderr,"OSS: ioctl on output device failed"); - dev->d_bufsize = ainfo.bytes; - - defect = linux_advance_samples * (dev->d_bytespersamp * nchannels) - - dev->d_bufsize - OSS_XFERSIZE(nchannels, dev->d_bytespersamp); - if (defect > 0) - { - if (sys_verbose || defect > (dev->d_bufsize >> 2)) - fprintf(stderr, - "OSS: requested audio buffer size %d limited to %d\n", - linux_advance_samples * (dev->d_bytespersamp * nchannels), - dev->d_bufsize); - linux_advance_samples = - (dev->d_bufsize - OSS_XFERSAMPS(nchannels)) / - (dev->d_bytespersamp *nchannels); - } - } -} - -static int oss_setchannels(int fd, int wantchannels, char *devname) -{ /* IOhannes */ - int param = wantchannels; - - while (param>1) { - int save = param; - if (ioctl(fd, SNDCTL_DSP_CHANNELS, ¶m) == -1) { - error("OSS: SNDCTL_DSP_CHANNELS failed %s",devname); - } else { - if (param == save) return (param); - } - param=save-1; - } - - return (0); -} - -#define O_AUDIOFLAG 0 /* O_NDELAY */ - -int oss_open_audio(int nindev, int *indev, int nchin, int *chin, - int noutdev, int *outdev, int nchout, int *chout, int rate) -{ /* IOhannes */ - int capabilities = 0; - int inchannels = 0, outchannels = 0; - char devname[20]; - int n, i, fd; - char buf[OSS_MAXSAMPLEWIDTH * DACBLKSIZE * OSS_MAXCHPERDEV]; - int num_devs = 0; - int wantmore=0; - int spread = 0; - audio_buf_info ainfo; - - linux_nindevs = linux_noutdevs = 0; - - /* set logical sample rate amd calculate linux_advance_samples. */ - linux_setsr(rate); - - /* mark input devices unopened */ - for (i = 0; i < OSS_MAXDEV; i++) - linux_adcs[i].d_fd = -1; - - /* open output devices */ - wantmore=0; - if (noutdev < 0 || nindev < 0) - bug("linux_open_audio"); - - for (n = 0; n < noutdev; n++) - { - int gotchans, j, inindex = -1; - int thisdevice=outdev[n]; - int wantchannels = (nchout>n) ? chout[n] : wantmore; - fd = -1; - if (!wantchannels) - goto end_out_loop; - - if (thisdevice > 1) - sprintf(devname, "/dev/dsp%d", thisdevice-1); - else sprintf(devname, "/dev/dsp"); - - /* search for input request for same device. Succeed only - if the number of channels matches. */ - for (j = 0; j < nindev; j++) - if (indev[j] == thisdevice && chin[j] == wantchannels) - inindex = j; - - /* if the same device is requested for input and output, - try to open it read/write */ - if (inindex >= 0) - { - sys_setalarm(1000000); - if ((fd = open(devname, O_RDWR | O_AUDIOFLAG)) == -1) - { - post("%s (read/write): %s", devname, strerror(errno)); - post("(now will try write-only...)"); - } - else - { - if (sys_verbose) - post("opened %s for reading and writing\n", devname); - linux_adcs[inindex].d_fd = fd; - } - } - /* if that didn't happen or if it failed, try write-only */ - if (fd == -1) - { - sys_setalarm(1000000); - if ((fd = open(devname, O_WRONLY | O_AUDIOFLAG)) == -1) - { - post("%s (writeonly): %s", - devname, strerror(errno)); - break; - } - if (sys_verbose) - post("opened %s for writing only\n", devname); - } - if (ioctl(fd, SNDCTL_DSP_GETCAPS, &capabilities) == -1) - error("OSS: SNDCTL_DSP_GETCAPS failed %s", devname); - - gotchans = oss_setchannels(fd, - (wantchannels>OSS_MAXCHPERDEV)?OSS_MAXCHPERDEV:wantchannels, - devname); - - if (sys_verbose) - post("opened audio output on %s; got %d channels", - devname, gotchans); - - if (gotchans < 2) - { - /* can't even do stereo? just give up. */ - close(fd); - } - else - { - linux_dacs[linux_noutdevs].d_nchannels = gotchans; - linux_dacs[linux_noutdevs].d_fd = fd; - oss_configure(linux_dacs+linux_noutdevs, rate, 1, 0); - - linux_noutdevs++; - outchannels += gotchans; - if (inindex >= 0) - { - linux_adcs[inindex].d_nchannels = gotchans; - chin[inindex] = gotchans; - } - } - /* LATER think about spreading large numbers of channels over - various dsp's and vice-versa */ - wantmore = wantchannels - gotchans; - end_out_loop: ; - } - - /* open input devices */ - wantmore = 0; - if (nindev==-1) - nindev=4; /* spread channels over default-devices */ - for (n = 0; n < nindev; n++) - { - int gotchans=0; - int thisdevice=indev[n]; - int wantchannels = (nchin>n)?chin[n]:wantmore; - int alreadyopened = 0; - if (!wantchannels) - goto end_in_loop; - - if (thisdevice > 1) - sprintf(devname, "/dev/dsp%d", thisdevice - 1); - else sprintf(devname, "/dev/dsp"); - - sys_setalarm(1000000); - - /* perhaps it's already open from the above? */ - if (linux_dacs[n].d_fd >= 0) - { - fd = linux_dacs[n].d_fd; - alreadyopened = 1; - } - else - { - /* otherwise try to open it here. */ - if ((fd = open(devname, O_RDONLY | O_AUDIOFLAG)) == -1) - { - post("%s (readonly): %s", devname, strerror(errno)); - goto end_in_loop; - } - if (sys_verbose) - post("opened %s for reading only\n", devname); - } - linux_adcs[linux_nindevs].d_fd = fd; - gotchans = oss_setchannels(fd, - (wantchannels>OSS_MAXCHPERDEV)?OSS_MAXCHPERDEV:wantchannels, - devname); - if (sys_verbose) - post("opened audio input device %s; got %d channels", - devname, gotchans); - - if (gotchans < 1) - { - close(fd); - goto end_in_loop; - } - - linux_adcs[linux_nindevs].d_nchannels = gotchans; - - oss_configure(linux_adcs+linux_nindevs, rate, 0, alreadyopened); - - inchannels += gotchans; - linux_nindevs++; - - wantmore = wantchannels-gotchans; - /* LATER think about spreading large numbers of channels over - various dsp's and vice-versa */ - end_in_loop: ; - } - - linux_setch(inchannels, outchannels); - - /* We have to do a read to start the engine. This is - necessary because sys_send_dacs waits until the input - buffer is filled and only reads on a filled buffer. - This is good, because it's a way to make sure that we - will not block. But I wonder why we only have to read - from one of the devices and not all of them??? */ - - if (linux_nindevs) - { - if (sys_verbose) - fprintf(stderr,("OSS: issuing first ADC 'read' ... ")); - read(linux_adcs[0].d_fd, buf, - linux_adcs[0].d_bytespersamp * - linux_adcs[0].d_nchannels * DACBLKSIZE); - if (sys_verbose) - fprintf(stderr, "...done.\n"); - } - sys_setalarm(0); - return (0); -} - -void oss_close_audio( void) -{ - int i; - for (i=0;i - OSS_XFERSIZE(linux_adcs[dev].d_nchannels, - linux_adcs[dev].d_bytespersamp)) - { - linux_adcs_read(linux_adcs[dev].d_fd, buf, - OSS_XFERSIZE(linux_adcs[dev].d_nchannels, - linux_adcs[dev].d_bytespersamp)); - if (ioctl(linux_adcs[dev].d_fd, SOUND_PCM_GETISPACE, &ainfo) < 0) - { - fprintf(stderr, "OSS: ioctl on input device %d, fd %d failed", - dev, linux_adcs[dev].d_fd); - break; - } - linux_adcs[dev].d_space = ainfo.bytes; - } - } - - /* 2. if any output devices are behind, feed them zeros to catch them - up */ - for (dev = 0; dev < linux_noutdevs; dev++) - { - while (linux_dacs[dev].d_space > linux_dacs[dev].d_bufsize - - linux_advance_samples * (linux_dacs[dev].d_nchannels * - linux_dacs[dev].d_bytespersamp)) - { - if (!zeroed) - { - unsigned int i; - for (i = 0; i < OSS_XFERSAMPS(linux_dacs[dev].d_nchannels); - i++) - buf[i] = 0; - zeroed = 1; - } - linux_dacs_write(linux_dacs[dev].d_fd, buf, - OSS_XFERSIZE(linux_dacs[dev].d_nchannels, - linux_dacs[dev].d_bytespersamp)); - if (ioctl(linux_dacs[dev].d_fd, SOUND_PCM_GETOSPACE, &ainfo) < 0) - { - fprintf(stderr, "OSS: ioctl on output device %d, fd %d failed", - dev, linux_dacs[dev].d_fd); - break; - } - linux_dacs[dev].d_space = ainfo.bytes; - } - } - /* 3. if any DAC devices are too far ahead, plan to drop the - number of frames which will let the others catch up. */ - for (dev = 0; dev < linux_noutdevs; dev++) - { - if (linux_dacs[dev].d_space > linux_dacs[dev].d_bufsize - - (linux_advance_samples - 1) * linux_dacs[dev].d_nchannels * - linux_dacs[dev].d_bytespersamp) - { - linux_dacs[dev].d_dropcount = linux_advance_samples - 1 - - (linux_dacs[dev].d_space - linux_dacs[dev].d_bufsize) / - (linux_dacs[dev].d_nchannels * - linux_dacs[dev].d_bytespersamp) ; - } - else linux_dacs[dev].d_dropcount = 0; - } -} - -int oss_send_dacs(void) -{ - float *fp1, *fp2; - long fill; - int i, j, dev, rtnval = SENDDACS_YES; - char buf[OSS_MAXSAMPLEWIDTH * DACBLKSIZE * OSS_MAXCHPERDEV]; - t_oss_int16 *sp; - t_oss_int32 *lp; - /* the maximum number of samples we should have in the ADC buffer */ - int idle = 0; - int thischan; - double timeref, timenow; - - if (!linux_nindevs && !linux_noutdevs) - return (SENDDACS_NO); - - if (!oss_blockmode) - { - /* determine whether we're idle. This is true if either (1) - some input device has less than one buffer to read or (2) some - output device has fewer than (linux_advance_samples) blocks buffered - already. */ - oss_calcspace(); - - for (dev=0; dev < linux_noutdevs; dev++) - if (linux_dacs[dev].d_dropcount || - (linux_dacs[dev].d_bufsize - linux_dacs[dev].d_space > - linux_advance_samples * linux_dacs[dev].d_bytespersamp * - linux_dacs[dev].d_nchannels)) - idle = 1; - for (dev=0; dev < linux_nindevs; dev++) - if (linux_adcs[dev].d_space < - OSS_XFERSIZE(linux_adcs[dev].d_nchannels, - linux_adcs[dev].d_bytespersamp)) - idle = 1; - } - - if (idle && !oss_blockmode) - { - /* sometimes---rarely---when the ADC available-byte-count is - zero, it's genuine, but usually it's because we're so - late that the ADC has overrun its entire kernel buffer. We - distinguish between the two by waiting 2 msec and asking again. - There should be an error flag we could check instead; look for this - someday... */ - for (dev = 0;dev < linux_nindevs; dev++) - if (linux_adcs[dev].d_space == 0) - { - audio_buf_info ainfo; - sys_microsleep(2000); - oss_calcspace(); - if (linux_adcs[dev].d_space != 0) continue; - - /* here's the bad case. Give up and resync. */ - sys_log_error(ERR_DATALATE); - oss_doresync(); - return (SENDDACS_NO); - } - /* check for slippage between devices, either because - data got lost in the driver from a previous late condition, or - because the devices aren't synced. When we're idle, no - input device should have more than one buffer readable and - no output device should have less than linux_advance_samples-1 - */ - - for (dev=0; dev < linux_noutdevs; dev++) - if (!linux_dacs[dev].d_dropcount && - (linux_dacs[dev].d_bufsize - linux_dacs[dev].d_space < - (linux_advance_samples - 2) * - (linux_dacs[dev].d_bytespersamp * - linux_dacs[dev].d_nchannels))) - goto badsync; - for (dev=0; dev < linux_nindevs; dev++) - if (linux_adcs[dev].d_space > 3 * - OSS_XFERSIZE(linux_adcs[dev].d_nchannels, - linux_adcs[dev].d_bytespersamp)) - goto badsync; - - /* return zero to tell the scheduler we're idle. */ - return (SENDDACS_NO); - badsync: - sys_log_error(ERR_RESYNC); - oss_doresync(); - return (SENDDACS_NO); - - } - - /* do output */ - - timeref = sys_getrealtime(); - for (dev=0, thischan = 0; dev < linux_noutdevs; dev++) - { - int nchannels = linux_dacs[dev].d_nchannels; - if (linux_dacs[dev].d_dropcount) - linux_dacs[dev].d_dropcount--; - else - { - if (linux_dacs[dev].d_bytespersamp == 4) - { - for (i = DACBLKSIZE * nchannels, fp1 = sys_soundout + - DACBLKSIZE*thischan, - lp = (t_oss_int32 *)buf; i--; fp1++, lp++) - { - float f = *fp1 * 2147483648.; - *lp = (f >= 2147483647. ? 2147483647. : - (f < -2147483648. ? -2147483648. : f)); - } - } - else - { - for (i = DACBLKSIZE, fp1 = sys_soundout + - DACBLKSIZE*thischan, - sp = (t_oss_int16 *)buf; i--; fp1++, sp += nchannels) - { - for (j=0, fp2 = fp1; j 32767) s = 32767; - else if (s < -32767) s = -32767; - sp[j] = s; - } - } - } - linux_dacs_write(linux_dacs[dev].d_fd, buf, - OSS_XFERSIZE(nchannels, linux_dacs[dev].d_bytespersamp)); - if ((timenow = sys_getrealtime()) - timeref > 0.002) - { - if (!oss_blockmode) - sys_log_error(ERR_DACSLEPT); - else rtnval = SENDDACS_SLEPT; - } - timeref = timenow; - } - thischan += nchannels; - } - memset(sys_soundout, 0, - linux_outchannels * (sizeof(float) * DACBLKSIZE)); - - /* do input */ - - for (dev = 0, thischan = 0; dev < linux_nindevs; dev++) - { - int nchannels = linux_adcs[dev].d_nchannels; - linux_adcs_read(linux_adcs[dev].d_fd, buf, - OSS_XFERSIZE(nchannels, linux_adcs[dev].d_bytespersamp)); - - if ((timenow = sys_getrealtime()) - timeref > 0.002) - { - if (!oss_blockmode) - sys_log_error(ERR_ADCSLEPT); - else - rtnval = SENDDACS_SLEPT; - } - timeref = timenow; - - if (linux_adcs[dev].d_bytespersamp == 4) - { - for (i = DACBLKSIZE*nchannels, - fp1 = sys_soundin + thischan*DACBLKSIZE, - lp = (t_oss_int32 *)buf; i--; fp1++, lp++) - { - *fp1 = ((float)(*lp))*(float)(1./2147483648.); - } - } - else - { - for (i = DACBLKSIZE,fp1 = sys_soundin + thischan*DACBLKSIZE, - sp = (t_oss_int16 *)buf; i--; fp1++, sp += nchannels) - { - for (j=0;j channelinfo.max_voices) - post("decreasing input channels to maximum of %d\n", - wantinchans = channelinfo.max_voices); - if (alsa_samplewidth == 4 && - !(channelinfo.formats & (1< channelinfo.max_voices) - post("decreasing output channels to maximum of %d\n", - wantoutchans = channelinfo.max_voices); - if (alsa_samplewidth == 4 && - !(channelinfo.formats & (1< linux_outchannels ? linux_inchannels : - linux_outchannels) * DACBLKSIZE; - alsa_buf = malloc(bsize); - if (!alsa_buf) - return (1); - memset(alsa_buf, 0, bsize); - return 0; -} - -void alsa_set_params(t_alsa_dev *dev, int dir, int rate, int voices) -{ - int err; - struct snd_pcm_channel_params params; - - memset(&dev->info, 0, sizeof(dev->info)); - dev->info.channel = dir; - if ((err = snd_pcm_channel_info(dev->handle, &dev->info) < 0)) - { - fprintf(stderr, "PD-ALSA: error getting channel info: %s\n", - snd_strerror(err)); - } - memset(¶ms, 0, sizeof(params)); - params.format.interleave = 1; /* may do non-interleaved later */ - /* format is 2 or 4 bytes per sample depending on what was possible */ - params.format.format = - (alsa_samplewidth == 4 ? SND_PCM_SFMT_S32_LE : SND_PCM_SFMT_S16_LE); - - /*will check this further down -just try for now*/ - params.format.rate = rate; - params.format.voices = voices; - params.start_mode = SND_PCM_START_GO; /* seems most reliable */ - /*do not stop at overrun/underrun*/ - params.stop_mode = SND_PCM_STOP_ROLLOVER; - - params.channel = dir; /* playback|capture */ - params.buf.stream.queue_size = - (ALSA_EXTRABUFFER + linux_advance_samples) - * alsa_samplewidth * voices; - params.buf.stream.fill = SND_PCM_FILL_SILENCE_WHOLE; - params.mode = SND_PCM_MODE_STREAM; - - if ((err = snd_pcm_channel_params(dev->handle, ¶ms)) < 0) - { - printf("PD-ALSA: error setting parameters %s", snd_strerror(err)); - } - - /* This should clear the buffers but does not. There is often noise at - startup that sounds like crap left in the buffers - maybe in the lib - instead of the driver? Some solution needs to be found. - */ - - if ((err = snd_pcm_channel_prepare(dev->handle, dir)) < 0) - { - printf("PD-ALSA: error preparing channel %s", snd_strerror(err)); - } - dev->setup.channel = dir; - - if ((err = snd_pcm_channel_setup(dev->handle, &dev->setup)) < 0) - { - printf("PD-ALSA: error getting setup %s", snd_strerror(err)); - } - /* for some reason, if you don't writesomething before starting the - converters we get trash on startup */ - if (dir == SND_PCM_CHANNEL_PLAYBACK) - { - char foo[1024]; - int xxx = 1024 - (1024 % (linux_outchannels * alsa_samplewidth)); - int i, r; - for (i = 0; i < xxx; i++) - foo[i] = 0; - if ((r = snd_pcm_write(dev->handle, foo, xxx)) < xxx) - fprintf(stderr, "alsa_write: %s\n", snd_strerror(errno)); - } - snd_pcm_channel_go(dev->handle, dir); -} - -void alsa_close_audio(void) -{ - int i; - for(i = 0; i < n_alsa_dev; i++) - snd_pcm_close(alsa_device[i].handle); -} - -/* #define DEBUG_ALSA_XFER */ - -int alsa_send_dacs(void) -{ - static int16_t *sp; - t_sample *fp, *fp1, *fp2; - int i, j, k, err, devno = 0; - int inputcount = 0, outputcount = 0, inputlate = 0, outputlate = 0; - int result; - snd_pcm_channel_status_t stat; - static int callno = 0; - static int xferno = 0; - int countwas = 0; - double timelast; - static double timenow; - int inchannels = linux_inchannels; - int outchannels = linux_outchannels; - int inbytesperframe = inchannels * alsa_samplewidth; - int outbytesperframe = outchannels * alsa_samplewidth; - int intransfersize = DACBLKSIZE * inbytesperframe; - int outtransfersize = DACBLKSIZE * outbytesperframe; - int alsaerror; - int loggederror = 0; - - if (!inchannels && !outchannels) - return (SENDDACS_NO); - timelast = timenow; - timenow = sys_getrealtime(); - -#ifdef DEBUG_ALSA_XFER - if (timenow - timelast > 0.050) - fprintf(stderr, "(%d)", - (int)(1000 * (timenow - timelast))), fflush(stderr); -#endif - - callno++; - /* get input and output channel status */ - if (inchannels > 0) - { - devno = 0; - stat.channel = SND_PCM_CHANNEL_CAPTURE; - if (alsaerror = snd_pcm_channel_status(alsa_device[devno].handle, - &stat)) - { - fprintf(stderr, "snd_pcm_channel_status (input): %s\n", - snd_strerror(alsaerror)); - return (SENDDACS_NO); - } - inputcount = stat.count; - inputlate = (stat.underrun > 0 || stat.overrun > 0); - } - if (outchannels > 0) - { - devno = 0; - stat.channel = SND_PCM_CHANNEL_PLAYBACK; - if (alsaerror = snd_pcm_channel_status(alsa_device[devno].handle, - &stat)) - { - fprintf(stderr, "snd_pcm_channel_status (output): %s\n", - snd_strerror(alsaerror)); - return (SENDDACS_NO); - } - outputcount = stat.count; - outputlate = (stat.underrun > 0 || stat.overrun > 0); - } - - /* check if input not ready */ - if (inputcount < intransfersize) - { - /* fprintf(stderr, "no adc; count %d, free %d, call %d, xfer %d\n", - stat.count, - stat.free, - callno, xferno); */ - if (outchannels > 0) - { - /* if there's no input but output is hungry, feed output. */ - while (outputcount < (linux_advance_samples + ALSA_JITTER) - * outbytesperframe) - { - if (!loggederror) - sys_log_error(ERR_RESYNC), loggederror = 1; - memset(alsa_buf, 0, outtransfersize); - result = snd_pcm_write(alsa_device[devno].handle, - alsa_buf, outtransfersize); - if (result < outtransfersize) - { -#ifdef DEBUG_ALSA_XFER - if (result >= 0 || errno == EAGAIN) - fprintf(stderr, "ALSA: write returned %d of %d\n", - result, outtransfersize); - else fprintf(stderr, "ALSA: write: %s\n", - snd_strerror(errno)); - fprintf(stderr, - "inputcount %d, outputcount %d, outbufsize %d\n", - inputcount, outputcount, - (ALSA_EXTRABUFFER + linux_advance_samples) - * alsa_samplewidth * outchannels); -#endif - return (SENDDACS_NO); - } - stat.channel = SND_PCM_CHANNEL_PLAYBACK; - if (alsaerror = - snd_pcm_channel_status(alsa_device[devno].handle, - &stat)) - { - fprintf(stderr, "snd_pcm_channel_status (output): %s\n", - snd_strerror(alsaerror)); - return (SENDDACS_NO); - } - outputcount = stat.count; - } - } - - return SENDDACS_NO; - } - - /* if output buffer has at least linux_advance_samples in it, we're - not ready for this batch. */ - if (outputcount > linux_advance_samples * outbytesperframe) - { - if (inchannels > 0) - { - while (inputcount > (DACBLKSIZE + ALSA_JITTER) * outbytesperframe) - { - if (!loggederror) - sys_log_error(ERR_RESYNC), loggederror = 1; - devno = 0; - result = snd_pcm_read(alsa_device[devno].handle, alsa_buf, - intransfersize); - if (result < intransfersize) - { -#ifdef DEBUG_ALSA_XFER - if (result < 0) - fprintf(stderr, - "snd_pcm_read %d %d: %s\n", - callno, xferno, snd_strerror(errno)); - else fprintf(stderr, - "snd_pcm_read %d %d returned only %d\n", - callno, xferno, result); - fprintf(stderr, - "inputcount %d, outputcount %d, inbufsize %d\n", - inputcount, outputcount, - (ALSA_EXTRABUFFER + linux_advance_samples) - * alsa_samplewidth * inchannels); -#endif - return (SENDDACS_NO); - } - devno = 0; - stat.channel = SND_PCM_CHANNEL_CAPTURE; - if (alsaerror = - snd_pcm_channel_status(alsa_device[devno].handle, - &stat)) - { - fprintf(stderr, "snd_pcm_channel_status (input): %s\n", - snd_strerror(alsaerror)); - return (SENDDACS_NO); - } - inputcount = stat.count; - inputlate = (stat.underrun > 0 || stat.overrun > 0); - } - return (SENDDACS_NO); - } - } - if (sys_getrealtime() - timenow > 0.002) - { -#ifdef DEBUG_ALSA_XFER - fprintf(stderr, "check %d took %d msec\n", - callno, (int)(1000 * (timenow - timelast))), fflush(stderr); -#endif - sys_log_error(ERR_DACSLEPT); - timenow = sys_getrealtime(); - } - if (inputlate || outputlate) - sys_log_error(ERR_DATALATE); - - /* do output */ - /* this "for" loop won't work for more than one device. */ - for (devno = 0, fp = sys_soundout; devno < (outchannels > 0); devno++, - fp += 128) - { - if (alsa_samplewidth == 4) - { - for (i = 0, fp1 = fp; i < outchannels; i++, fp1 += DACBLKSIZE) - { - for (j = i, k = DACBLKSIZE, fp2 = fp1; k--; - j += outchannels, fp2++) - { - float s1 = *fp2 * INT32_MAX; - ((t_alsa_sample32 *)alsa_buf)[j] = CLIP32(s1); - } - } - } - else - { - for (i = 0, fp1 = fp; i < outchannels; i++, fp1 += DACBLKSIZE) - { - for (j = i, k = DACBLKSIZE, fp2 = fp1; k--; - j += outchannels, fp2++) - { - int s = *fp2 * 32767.; - if (s > 32767) - s = 32767; - else if (s < -32767) - s = -32767; - ((t_alsa_sample16 *)alsa_buf)[j] = s; - } - } - } - - result = snd_pcm_write(alsa_device[devno].handle, alsa_buf, - outtransfersize); - if (result < outtransfersize) - { -#ifdef DEBUG_ALSA_XFER - if (result >= 0 || errno == EAGAIN) - fprintf(stderr, "ALSA: write returned %d of %d\n", - result, outtransfersize); - else fprintf(stderr, "ALSA: write: %s\n", - snd_strerror(errno)); - fprintf(stderr, - "inputcount %d, outputcount %d, outbufsize %d\n", - inputcount, outputcount, - (ALSA_EXTRABUFFER + linux_advance_samples) - * alsa_samplewidth * outchannels); -#endif - sys_log_error(ERR_DACSLEPT); - return (SENDDACS_NO); - } - } - /* zero out the output buffer */ - memset(sys_soundout, 0, DACBLKSIZE * sizeof(*sys_soundout) * - linux_outchannels); - if (sys_getrealtime() - timenow > 0.002) - { -#if DEBUG_ALSA_XFER - fprintf(stderr, "output %d took %d msec\n", - callno, (int)(1000 * (timenow - timelast))), fflush(stderr); -#endif - timenow = sys_getrealtime(); - sys_log_error(ERR_DACSLEPT); - } - - /* do input */ - for (devno = 0, fp = sys_soundin; devno < (linux_inchannels > 0); devno++, - fp += 128) - { - result = snd_pcm_read(alsa_device[devno].handle, alsa_buf, - intransfersize); - if (result < intransfersize) - { -#ifdef DEBUG_ALSA_XFER - if (result < 0) - fprintf(stderr, - "snd_pcm_read %d %d: %s\n", - callno, xferno, snd_strerror(errno)); - else fprintf(stderr, - "snd_pcm_read %d %d returned only %d\n", - callno, xferno, result); - fprintf(stderr, - "inputcount %d, outputcount %d, inbufsize %d\n", - inputcount, outputcount, - (ALSA_EXTRABUFFER + linux_advance_samples) - * alsa_samplewidth * inchannels); -#endif - sys_log_error(ERR_ADCSLEPT); - return (SENDDACS_NO); - } - if (alsa_samplewidth == 4) - { - for (i = 0, fp1 = fp; i < inchannels; i++, fp1 += DACBLKSIZE) - { - for (j = i, k = DACBLKSIZE, fp2 = fp1; k--; - j += inchannels, fp2++) - *fp2 = (float) ((t_alsa_sample32 *)alsa_buf)[j] - * (1./ INT32_MAX); - } - } - else - { - for (i = 0, fp1 = fp; i < inchannels; i++, fp1 += DACBLKSIZE) - { - for (j = i, k = DACBLKSIZE, fp2 = fp1; k--; j += inchannels, fp2++) - *fp2 = (float) ((t_alsa_sample16 *)alsa_buf)[j] - * 3.051850e-05; - } - } - } - xferno++; - if (sys_getrealtime() - timenow > 0.002) - { -#ifdef DEBUG_ALSA_XFER - fprintf(stderr, "routine took %d msec\n", - (int)(1000 * (sys_getrealtime() - timenow))); -#endif - sys_log_error(ERR_ADCSLEPT); - } - return SENDDACS_YES; -} - -#endif /* ALSA99 */ - -/* support for ALSA pcmv2 api by Karl MacMillan */ - -#ifdef ALSA01 - -static void check_error(int err, const char *why) -{ - if (err < 0) - fprintf(stderr, "%s: %s\n", why, snd_strerror(err)); -} - -static int alsa_open_audio(int wantinchans, int wantoutchans, int srate) -{ - int err, inchans = 0, outchans = 0, subunitdir; - char devname[512]; - snd_pcm_hw_params_t* hw_params; - snd_pcm_sw_params_t* sw_params; - snd_output_t* out; - int frag_size = (linux_fragsize ? linux_fragsize : ALSA_DEFFRAGSIZE); - int nfrags, i; - short* tmp_buf; - unsigned int tmp_uint; - int advwas = sys_schedadvance; - - if (linux_nfragment) - { - nfrags = linux_nfragment; - sys_schedadvance = (frag_size * linux_nfragment * 1.0e6) / srate; - } - else nfrags = sys_schedadvance * (float)srate / (1e6 * frag_size); - - if (sys_verbose || (sys_schedadvance != advwas)) - post("audio buffer set to %d", (int)(0.001 * sys_schedadvance)); - if (wantinchans || wantoutchans) - alsa_checkversion(); - if (wantinchans) - { - err = snd_pcm_open(&alsa_device.inhandle, alsa_devname, - SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK); - - check_error(err, "snd_pcm_open (input)"); - if (err < 0) - inchans = 0; - else - { - inchans = wantinchans; - snd_pcm_nonblock(alsa_device.inhandle, 1); - } - } - if (wantoutchans) - { - err = snd_pcm_open(&alsa_device.outhandle, alsa_devname, - SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); - - check_error(err, "snd_pcm_open (output)"); - if (err < 0) - outchans = 0; - else - { - outchans = wantoutchans; - snd_pcm_nonblock(alsa_device.outhandle, 1); - } - } - if (inchans) - { - if (sys_verbose) - post("opening sound input..."); - err = snd_pcm_hw_params_malloc(&hw_params); - check_error(err, "snd_pcm_hw_params_malloc (input)"); - - // get the default params - err = snd_pcm_hw_params_any(alsa_device.inhandle, hw_params); - check_error(err, "snd_pcm_hw_params_any (input)"); - // set interleaved access - FIXME deal with other access types - err = snd_pcm_hw_params_set_access(alsa_device.inhandle, hw_params, - SND_PCM_ACCESS_RW_INTERLEAVED); - check_error(err, "snd_pcm_hw_params_set_access (input)"); - // Try to set 32 bit format first - err = snd_pcm_hw_params_set_format(alsa_device.inhandle, hw_params, - SND_PCM_FORMAT_S32); - if (err < 0) - { - /* fprintf(stderr, - "PD-ALSA: 32 bit format not available - using 16\n"); */ - err = snd_pcm_hw_params_set_format(alsa_device.inhandle, hw_params, - SND_PCM_FORMAT_S16); - check_error(err, "snd_pcm_hw_params_set_format (input)"); - alsa_samplewidth = 2; - } - else - { - alsa_samplewidth = 4; - } - post("Sample width set to %d bytes", alsa_samplewidth); - // set the subformat - err = snd_pcm_hw_params_set_subformat(alsa_device.inhandle, hw_params, - SND_PCM_SUBFORMAT_STD); - check_error(err, "snd_pcm_hw_params_set_subformat (input)"); - // set the number of channels - tmp_uint = inchans; - err = snd_pcm_hw_params_set_channels_min(alsa_device.inhandle, - hw_params, &tmp_uint); - check_error(err, "snd_pcm_hw_params_set_channels (input)"); - if (tmp_uint != (unsigned)inchans) - post("ALSA: set input channels to %d", tmp_uint); - inchans = tmp_uint; - // set the sampling rate - err = snd_pcm_hw_params_set_rate_min(alsa_device.inhandle, hw_params, - &srate, 0); - check_error(err, "snd_pcm_hw_params_set_rate_min (input)"); -#if 0 - err = snd_pcm_hw_params_get_rate(hw_params, &subunitdir); - post("input sample rate %d", err); -#endif - // set the period - ie frag size - // post("fragsize a %d", frag_size); - - /* LATER try this to get a recommended period size... - right now, it trips an assertion failure in ALSA lib */ -#if 0 - post("input period was %d, min %d, max %d\n", - snd_pcm_hw_params_get_period_size(hw_params, 0), - snd_pcm_hw_params_get_period_size_min(hw_params, 0), - snd_pcm_hw_params_get_period_size_max(hw_params, 0)); -#endif - err = snd_pcm_hw_params_set_period_size_near(alsa_device.inhandle, - hw_params, - (snd_pcm_uframes_t) - frag_size, 0); - check_error(err, "snd_pcm_hw_params_set_period_size_near (input)"); - // post("fragsize b %d", frag_size); - // set the number of periods - ie numfrags - // post("nfrags a %d", nfrags); - err = snd_pcm_hw_params_set_periods_near(alsa_device.inhandle, - hw_params, nfrags, 0); - check_error(err, "snd_pcm_hw_params_set_periods_near (input)"); - // set the buffer size - err = snd_pcm_hw_params_set_buffer_size_near(alsa_device.inhandle, - hw_params, nfrags * frag_size); - check_error(err, "snd_pcm_hw_params_set_buffer_size_near (input)"); - - err = snd_pcm_hw_params(alsa_device.inhandle, hw_params); - check_error(err, "snd_pcm_hw_params (input)"); - - snd_pcm_hw_params_free(hw_params); - - err = snd_pcm_sw_params_malloc(&sw_params); - check_error(err, "snd_pcm_sw_params_malloc (input)"); - err = snd_pcm_sw_params_current(alsa_device.inhandle, sw_params); - check_error(err, "snd_pcm_sw_params_current (input)"); -#if 1 - err = snd_pcm_sw_params_set_start_mode(alsa_device.inhandle, sw_params, - SND_PCM_START_EXPLICIT); - check_error(err, "snd_pcm_sw_params_set_start_mode (input)"); - err = snd_pcm_sw_params_set_xrun_mode(alsa_device.inhandle, sw_params, - SND_PCM_XRUN_NONE); - check_error(err, "snd_pcm_sw_params_set_xrun_mode (input)"); -#else - err = snd_pcm_sw_params_set_start_threshold(alsa_device.inhandle, - sw_params, nfrags * frag_size); - check_error(err, "snd_pcm_sw_params_set_start_threshold (input)"); - err = snd_pcm_sw_params_set_stop_threshold(alsa_device.inhandle, - sw_params, 1); - check_error(err, "snd_pcm_sw_params_set_stop_threshold (input)"); -#endif - - err = snd_pcm_sw_params_set_avail_min(alsa_device.inhandle, sw_params, - frag_size); - check_error(err, "snd_pcm_sw_params_set_avail_min (input)"); - err = snd_pcm_sw_params(alsa_device.inhandle, sw_params); - check_error(err, "snd_pcm_sw_params (input)"); - - snd_pcm_sw_params_free(sw_params); - - snd_output_stdio_attach(&out, stderr, 0); -#if 0 - if (sys_verbose) - { - snd_pcm_dump_hw_setup(alsa_device.inhandle, out); - snd_pcm_dump_sw_setup(alsa_device.inhandle, out); - } -#endif - } - - if (outchans) - { - int foo; - if (sys_verbose) - post("opening sound output..."); - err = snd_pcm_hw_params_malloc(&hw_params); - check_error(err, "snd_pcm_sw_params (output)"); - - // get the default params - err = snd_pcm_hw_params_any(alsa_device.outhandle, hw_params); - check_error(err, "snd_pcm_hw_params_any (output)"); - // set interleaved access - FIXME deal with other access types - err = snd_pcm_hw_params_set_access(alsa_device.outhandle, hw_params, - SND_PCM_ACCESS_RW_INTERLEAVED); - check_error(err, "snd_pcm_hw_params_set_access (output)"); - // Try to set 32 bit format first - err = snd_pcm_hw_params_set_format(alsa_device.outhandle, hw_params, - SND_PCM_FORMAT_S32); - if (err < 0) - { - err = snd_pcm_hw_params_set_format(alsa_device.outhandle, - hw_params,SND_PCM_FORMAT_S16); - check_error(err, "snd_pcm_hw_params_set_format (output)"); - /* fprintf(stderr, - "PD-ALSA: 32 bit format not available - using 16\n"); */ - alsa_samplewidth = 2; - } - else - { - alsa_samplewidth = 4; - } - // set the subformat - err = snd_pcm_hw_params_set_subformat(alsa_device.outhandle, hw_params, - SND_PCM_SUBFORMAT_STD); - check_error(err, "snd_pcm_hw_params_set_subformat (output)"); - // set the number of channels - tmp_uint = outchans; - err = snd_pcm_hw_params_set_channels_min(alsa_device.outhandle, - hw_params, &tmp_uint); - check_error(err, "snd_pcm_hw_params_set_channels (output)"); - if (tmp_uint != (unsigned)outchans) - post("alsa: set output channels to %d", tmp_uint); - outchans = tmp_uint; - // set the sampling rate - err = snd_pcm_hw_params_set_rate_min(alsa_device.outhandle, hw_params, - &srate, 0); - check_error(err, "snd_pcm_hw_params_set_rate_min (output)"); -#if 0 - err = snd_pcm_hw_params_get_rate(hw_params, &subunitdir); - post("output sample rate %d", err); -#endif - // set the period - ie frag size -#if 0 - post("output period was %d, min %d, max %d\n", - snd_pcm_hw_params_get_period_size(hw_params, 0), - snd_pcm_hw_params_get_period_size_min(hw_params, 0), - snd_pcm_hw_params_get_period_size_max(hw_params, 0)); -#endif - // post("fragsize c %d", frag_size); - err = snd_pcm_hw_params_set_period_size_near(alsa_device.outhandle, - hw_params, - (snd_pcm_uframes_t) - frag_size, 0); - // post("fragsize d %d", frag_size); - check_error(err, "snd_pcm_hw_params_set_period_size_near (output)"); - // set the number of periods - ie numfrags - err = snd_pcm_hw_params_set_periods_near(alsa_device.outhandle, - hw_params, nfrags, 0); - check_error(err, "snd_pcm_hw_params_set_periods_near (output)"); - // set the buffer size - err = snd_pcm_hw_params_set_buffer_size_near(alsa_device.outhandle, - hw_params, nfrags * frag_size); - - check_error(err, "snd_pcm_hw_params_set_buffer_size_near (output)"); - - err = snd_pcm_hw_params(alsa_device.outhandle, hw_params); - check_error(err, "snd_pcm_hw_params (output)"); - - snd_pcm_hw_params_free(hw_params); - - err = snd_pcm_sw_params_malloc(&sw_params); - check_error(err, "snd_pcm_sw_params_malloc (output)"); - err = snd_pcm_sw_params_current(alsa_device.outhandle, sw_params); - check_error(err, "snd_pcm_sw_params_current (output)"); -#if 1 - err = snd_pcm_sw_params_set_start_mode(alsa_device.outhandle, - sw_params, - SND_PCM_START_EXPLICIT); - check_error(err, "snd_pcm_sw_params_set_start_mode (output)"); - err = snd_pcm_sw_params_set_xrun_mode(alsa_device.outhandle, sw_params, - SND_PCM_XRUN_NONE); - check_error(err, "snd_pcm_sw_params_set_xrun_mode (output)"); -#else - err = snd_pcm_sw_params_set_start_threshold(alsa_device.inhandle, - sw_params, nfrags * frag_size); - check_error(err, "snd_pcm_sw_params_set_start_threshold (output)"); - err = snd_pcm_sw_params_set_stop_threshold(alsa_device.inhandle, - sw_params, 1); - check_error(err, "snd_pcm_sw_params_set_stop_threshold (output)"); -#endif - - err = snd_pcm_sw_params_set_avail_min(alsa_device.outhandle, sw_params, - frag_size); - check_error(err, "snd_pcm_sw_params_set_avail_min (output)"); - err = snd_pcm_sw_params(alsa_device.outhandle, sw_params); - check_error(err, "snd_pcm_sw_params (output)"); - - snd_pcm_sw_params_free(sw_params); - - snd_output_stdio_attach(&out, stderr, 0); -#if 0 - if (sys_verbose) - { - snd_pcm_dump_hw_setup(alsa_device.outhandle, out); - snd_pcm_dump_sw_setup(alsa_device.outhandle, out); - } -#endif - } - - linux_setsr(srate); - linux_setch(inchans, outchans); - - if (inchans) - snd_pcm_prepare(alsa_device.inhandle); - if (outchans) - snd_pcm_prepare(alsa_device.outhandle); - - // if duplex we can link the channels so they start together - if (inchans && outchans) - snd_pcm_link(alsa_device.inhandle, alsa_device.outhandle); - - // set up the buffer - if (outchans > inchans) - alsa_buf = (short *)calloc(sizeof(char) * alsa_samplewidth, DACBLKSIZE - * outchans); - else - alsa_buf = (short *)calloc(sizeof(char) * alsa_samplewidth, DACBLKSIZE - * inchans); - // fill the buffer with silence - if (outchans) - { - i = nfrags + 1; - while (i--) - snd_pcm_writei(alsa_device.outhandle, alsa_buf, frag_size); - } - - // set up the status variables - err = snd_pcm_status_malloc(&in_status); - check_error(err, "snd_pcm_status_malloc"); - err = snd_pcm_status_malloc(&out_status); - check_error(err, "snd_pcm_status_malloc"); - - // start the device -#if 1 - if (outchans) - { - err = snd_pcm_start(alsa_device.outhandle); - check_error(err, "snd_pcm_start"); - } - else if (inchans) - { - err = snd_pcm_start(alsa_device.inhandle); - check_error(err, "snd_pcm_start"); - } -#endif - - return 0; -} - -void alsa_close_audio(void) -{ - int err; - if (linux_inchannels) - { - err = snd_pcm_close(alsa_device.inhandle); - check_error(err, "snd_pcm_close (input)"); - } - if (linux_outchannels) - { - err = snd_pcm_close(alsa_device.outhandle); - check_error(err, "snd_pcm_close (output)"); - } -} - -// #define DEBUG_ALSA_XFER - -int alsa_send_dacs(void) -{ - static int16_t *sp; - static int xferno = 0; - static int callno = 0; - static double timenow; - double timelast; - t_sample *fp, *fp1, *fp2; - int i, j, k, err, devno = 0; - int inputcount = 0, outputcount = 0, inputlate = 0, outputlate = 0; - int result; - int inchannels = linux_inchannels; - int outchannels = linux_outchannels; - unsigned int intransfersize = DACBLKSIZE; - unsigned int outtransfersize = DACBLKSIZE; - - // get the status - if (!inchannels && !outchannels) - { - return SENDDACS_NO; - } - - timelast = timenow; - timenow = sys_getrealtime(); - -#ifdef DEBUG_ALSA_XFER - if (timenow - timelast > 0.050) - fprintf(stderr, "(%d)", - (int)(1000 * (timenow - timelast))), fflush(stderr); -#endif - - callno++; - - if (inchannels) - { - snd_pcm_status(alsa_device.inhandle, in_status); - if (snd_pcm_status_get_avail(in_status) < intransfersize) - return SENDDACS_NO; - } - if (outchannels) - { - snd_pcm_status(alsa_device.outhandle, out_status); - if (snd_pcm_status_get_avail(out_status) < outtransfersize) - return SENDDACS_NO; - } - - /* do output */ - if (outchannels) - { - fp = sys_soundout; - if (alsa_samplewidth == 4) - { - for (i = 0, fp1 = fp; i < outchannels; i++, fp1 += DACBLKSIZE) - { - for (j = i, k = DACBLKSIZE, fp2 = fp1; k--; - j += outchannels, fp2++) - { - float s1 = *fp2 * INT32_MAX; - ((t_alsa_sample32 *)alsa_buf)[j] = CLIP32(s1); - } - } - } - else - { - for (i = 0, fp1 = fp; i < outchannels; i++, fp1 += DACBLKSIZE) - { - for (j = i, k = DACBLKSIZE, fp2 = fp1; k--; - j += outchannels, fp2++) - { - int s = *fp2 * 32767.; - if (s > 32767) - s = 32767; - else if (s < -32767) - s = -32767; - ((t_alsa_sample16 *)alsa_buf)[j] = s; - } - } - } - - result = snd_pcm_writei(alsa_device.outhandle, alsa_buf, - outtransfersize); - if (result != (int)outtransfersize) - { - #ifdef DEBUG_ALSA_XFER - if (result >= 0 || errno == EAGAIN) - fprintf(stderr, "ALSA: write returned %d of %d\n", - result, outtransfersize); - else fprintf(stderr, "ALSA: write: %s\n", - snd_strerror(errno)); - fprintf(stderr, - "inputcount %d, outputcount %d, outbufsize %d\n", - inputcount, outputcount, - (ALSA_EXTRABUFFER + linux_advance_samples) - * alsa_samplewidth * outchannels); - #endif - sys_log_error(ERR_DACSLEPT); - return (SENDDACS_NO); - } - - /* zero out the output buffer */ - memset(sys_soundout, 0, DACBLKSIZE * sizeof(*sys_soundout) * - linux_outchannels); - if (sys_getrealtime() - timenow > 0.002) - { - #ifdef DEBUG_ALSA_XFER - fprintf(stderr, "output %d took %d msec\n", - callno, (int)(1000 * (timenow - timelast))), fflush(stderr); - #endif - timenow = sys_getrealtime(); - sys_log_error(ERR_DACSLEPT); - } - } - /* do input */ - if (linux_inchannels) - { - result = snd_pcm_readi(alsa_device.inhandle, alsa_buf, intransfersize); - if (result < (int)intransfersize) - { -#ifdef DEBUG_ALSA_XFER - if (result < 0) - fprintf(stderr, - "snd_pcm_read %d %d: %s\n", - callno, xferno, snd_strerror(errno)); - else fprintf(stderr, - "snd_pcm_read %d %d returned only %d\n", - callno, xferno, result); - fprintf(stderr, - "inputcount %d, outputcount %d, inbufsize %d\n", - inputcount, outputcount, - (ALSA_EXTRABUFFER + linux_advance_samples) - * alsa_samplewidth * inchannels); -#endif - sys_log_error(ERR_ADCSLEPT); - return (SENDDACS_NO); - } - fp = sys_soundin; - if (alsa_samplewidth == 4) - { - for (i = 0, fp1 = fp; i < inchannels; i++, fp1 += DACBLKSIZE) - { - for (j = i, k = DACBLKSIZE, fp2 = fp1; k--; - j += inchannels, fp2++) - *fp2 = (float) ((t_alsa_sample32 *)alsa_buf)[j] - * (1./ INT32_MAX); - } - } - else - { - for (i = 0, fp1 = fp; i < inchannels; i++, fp1 += DACBLKSIZE) - { - for (j = i, k = DACBLKSIZE, fp2 = fp1; k--; j += inchannels, - fp2++) - *fp2 = (float) ((t_alsa_sample16 *)alsa_buf)[j] - * 3.051850e-05; - } - } - } - xferno++; - if (sys_getrealtime() - timenow > 0.002) - { -#ifdef DEBUG_ALSA_XFER - fprintf(stderr, "routine took %d msec\n", - (int)(1000 * (sys_getrealtime() - timenow))); -#endif - sys_log_error(ERR_ADCSLEPT); - } - return SENDDACS_YES; -} - -void alsa_resync( void) -{ - int i, result; - if (linux_whichapi != API_ALSA) - { - error("restart-audio: implemented for ALSA only."); - return; - } - memset(alsa_buf, 0, - sizeof(char) * alsa_samplewidth * DACBLKSIZE * linux_outchannels); - for (i = 0; i < 1000000; i++) - { - result = snd_pcm_writei(alsa_device.outhandle, alsa_buf, - DACBLKSIZE); - if (result != (int)DACBLKSIZE) - break; - } - post("%d written", i); -} - - -#endif /* ALSA01 */ - -/*************************************************** - * Code using the RME_9652 API - */ - - /* - trying native device for future use of native memory map: - because of busmaster if you dont use the dac, you dont need - CPU Power und also no nearly no CPU-Power is used in device - - since always all DAs and ADs are synced (else they wouldnt work) - we use linux_dacs[0], linux_adcs[0] - */ - -#ifdef RME_HAMMERFALL - -#define RME9652_MAX_CHANNELS 26 - -#define RME9652_CH_PER_NATIVE_DEVICE 1 - -static int rme9652_dac_devices[RME9652_MAX_CHANNELS]; -static int rme9652_adc_devices[RME9652_MAX_CHANNELS]; - -static char rme9652_dsp_dac[] = "/dev/rme9652/C0da%d"; -static char rme9652_dsp_adc[] = "/dev/rme9652/C0ad%d"; - -static int num_of_rme9652_dac = 0; -static int num_of_rme9652_adc = 0; - -static int rme_soundindevonset = 1; -static int rme_soundoutdevonset = 1; - -void rme_soundindev(int which) -{ - rme_soundindevonset = which; -} - -void rme_soundoutdev(int which) -{ - rme_soundoutdevonset = which; -} - -void rme9652_configure(int dev, int fd,int srate, int dac) { - int orig, param, nblk; - audio_buf_info ainfo; - orig = param = srate; - - /* samplerate */ - - fprintf(stderr,"RME9652: configuring %d, fd=%d, sr=%d\n, dac=%d\n", - dev,fd,srate,dac); - - if (ioctl(fd,SNDCTL_DSP_SPEED,¶m) == -1) - fprintf(stderr,"RME9652: Could not set sampling rate for device\n"); - else if( orig != param ) - fprintf(stderr,"RME9652: sampling rate: wanted %d, got %d\n", - orig, param ); - - // setting the correct samplerate (could be different than expected) - srate = param; - - - /* setting resolution */ - - /* use ctrlpanel to change, experiment, channels 1 */ - - orig = param = AFMT_S16_NE; - if (ioctl(fd,SNDCTL_DSP_SETFMT,¶m) == -1) - fprintf(stderr,"RME9652: Could not set DSP format\n"); - else if( orig != param ) - fprintf(stderr,"RME9652: DSP format: wanted %d, got %d\n",orig, param ); - - /* setting channels */ - orig = param = RME9652_CH_PER_NATIVE_DEVICE; - - if (ioctl(fd,SNDCTL_DSP_CHANNELS,¶m) == -1) - fprintf(stderr,"RME9652: Could not set channels\n"); - else if( orig != param ) - fprintf(stderr,"RME9652: num channels: wanted %d, got %d\n",orig, param ); - - if (dac) - { - - /* use "free space" to learn the buffer size. Normally you - should set this to your own desired value; but this seems not - to be implemented uniformly across different sound cards. LATER - we should figure out what to do if the requested scheduler advance - is greater than this buffer size; for now, we just print something - out. */ - - if( ioctl(linux_dacs[0].d_fd, SOUND_PCM_GETOSPACE,&ainfo) < 0 ) - fprintf(stderr,"RME: ioctl on output device %d failed",dev); - - linux_dacs[0].d_bufsize = ainfo.bytes; - - fprintf(stderr,"RME: ioctl SOUND_PCM_GETOSPACE says %d buffsize\n", - linux_dacs[0].d_bufsize); - - - if (linux_advance_samples * (RME_SAMPLEWIDTH * - RME9652_CH_PER_NATIVE_DEVICE) - > linux_dacs[0].d_bufsize - RME_BYTESPERCHAN) - { - fprintf(stderr, - "RME: requested audio buffer size %d limited to %d\n", - linux_advance_samples - * (RME_SAMPLEWIDTH * RME9652_CH_PER_NATIVE_DEVICE), - linux_dacs[0].d_bufsize); - linux_advance_samples = - (linux_dacs[0].d_bufsize - RME_BYTESPERCHAN) - / (RME_SAMPLEWIDTH *RME9652_CH_PER_NATIVE_DEVICE); - } - } -} - - -int rme9652_open_audio(int inchans, int outchans,int srate) -{ - int orig; - int tmp; - int inchannels = 0,outchannels = 0; - char devname[20]; - int i; - char buf[RME_SAMPLEWIDTH*RME9652_CH_PER_NATIVE_DEVICE*DACBLKSIZE]; - int num_devs = 0; - audio_buf_info ainfo; - - linux_nindevs = linux_noutdevs = 0; - - if (sys_verbose) - post("RME open"); - /* First check if we can */ - /* open the write ports */ - - for (num_devs=0; outchannels < outchans; num_devs++) - { - int channels = RME9652_CH_PER_NATIVE_DEVICE; - - sprintf(devname, rme9652_dsp_dac, num_devs + rme_soundoutdevonset); - if ((tmp = open(devname,O_WRONLY)) == -1) - { - DEBUG(fprintf(stderr,"RME9652: failed to open %s writeonly\n", - devname);) - break; - } - DEBUG(fprintf(stderr,"RME9652: out device Nr. %d (%d) on %s\n", - linux_noutdevs+1,tmp,devname);) - - if (outchans > outchannels) - { - rme9652_dac_devices[linux_noutdevs] = tmp; - linux_noutdevs++; - outchannels += channels; - } - else close(tmp); - } - if( linux_noutdevs > 0) - linux_dacs[0].d_fd = rme9652_dac_devices[0]; - - /* Second check if we can */ - /* open the read ports */ - - for (num_devs=0; inchannels < inchans; num_devs++) - { - int channels = RME9652_CH_PER_NATIVE_DEVICE; - - sprintf(devname, rme9652_dsp_adc, num_devs+rme_soundindevonset); - - if ((tmp = open(devname,O_RDONLY)) == -1) - { - DEBUG(fprintf(stderr,"RME9652: failed to open %s readonly\n", - devname);) - break; - } - DEBUG(fprintf(stderr,"RME9652: in device Nr. %d (%d) on %s\n", - linux_nindevs+1,tmp,devname);) - - if (inchans > inchannels) - { - rme9652_adc_devices[linux_nindevs] = tmp; - linux_nindevs++; - inchannels += channels; - } - else - close(tmp); - } - if(linux_nindevs > 0) - linux_adcs[0].d_fd = rme9652_adc_devices[0]; - - /* configure soundcards */ - - rme9652_configure(0, linux_adcs[0].d_fd,srate, 0); - rme9652_configure(0, linux_dacs[0].d_fd,srate, 1); - - /* We have to do a read to start the engine. This is - necessary because sys_send_dacs waits until the input - buffer is filled and only reads on a filled buffer. - This is good, because it's a way to make sure that we - will not block */ - - if (linux_nindevs) - { - fprintf(stderr,("RME9652: starting read engine ... ")); - - - for (num_devs=0; num_devs < linux_nindevs; num_devs++) - read(rme9652_adc_devices[num_devs], - buf, RME_SAMPLEWIDTH* RME9652_CH_PER_NATIVE_DEVICE* - DACBLKSIZE); - - - for (num_devs=0; num_devs < linux_noutdevs; num_devs++) - write(rme9652_dac_devices[num_devs], - buf, RME_SAMPLEWIDTH* RME9652_CH_PER_NATIVE_DEVICE* - DACBLKSIZE); - - if(linux_noutdevs) - ioctl(rme9652_dac_devices[0],SNDCTL_DSP_SYNC); - - fprintf(stderr,"done\n"); - } - - linux_setsr(srate); - linux_setch(linux_nindevs, linux_noutdevs); - - num_of_rme9652_dac = linux_noutdevs; - num_of_rme9652_adc = linux_nindevs; - - if(linux_noutdevs)linux_noutdevs=1; - if(linux_nindevs)linux_nindevs=1; - - /* trick RME9652 behaves as one device fromread write pointers */ - return (0); -} - -void rme9652_close_audio( void) -{ - int i; - for (i=0;i>2;i--;) - { - float s1 = *(fp1+=4) * INT32_MAX; - float s2 = *(fp2+=4) * INT32_MAX; - float s3 = *(fp3+=4) * INT32_MAX; - float s4 = *(fp4+=4) * INT32_MAX; - - *(a+=4) = CLIP32(s1); - *(b+=4) = CLIP32(s2); - *(c+=4) = CLIP32(s3); - *(d+=4) = CLIP32(s4); - } - - linux_dacs_write(rme9652_dac_devices[j],buf,RME_BYTESPERCHAN); - } - } - - if ((timenow = sys_getrealtime()) - timeref > 0.02) - sys_log_error(ERR_DACSLEPT); - timeref = timenow; - } - - memset(sys_soundout, 0, - linux_outchannels * (sizeof(float) * DACBLKSIZE)); - - /* do input */ - - if(linux_nindevs) { - - for(j=0;j 0.02) - sys_log_error(ERR_ADCSLEPT); - timeref = timenow; - { - t_rme_sample *a,*b,*c,*d; - float *fp1,*fp2,*fp3,*fp4; - - fp1 = sys_soundin + j*DACBLKSIZE-4; - fp2 = fp1 + 1; - fp3 = fp1 + 2; - fp4 = fp1 + 3; - a = buf-4; - b=a+1; - c=a+2; - d=a+3; - - for (i = (DACBLKSIZE>>2);i--;) - { - *(fp1+=4) = *(a+=4) * (float)(1./INT32_MAX); - *(fp2+=4) = *(b+=4) * (float)(1./INT32_MAX); - *(fp3+=4) = *(c+=4) * (float)(1./INT32_MAX); - *(fp4+=4) = *(d+=4) * (float)(1./INT32_MAX); - } - } - } - } - /* fprintf(stderr,"ready \n");*/ - - return (1); -} - -#endif /* RME_HAMMERFALL */ diff --git a/pd/src/s_mac.c b/pd/src/s_mac.c deleted file mode 100644 index 941fa93c..00000000 --- a/pd/src/s_mac.c +++ /dev/null @@ -1,377 +0,0 @@ -/* Copyright (c) 1997-2001 Guenter Geiger, Miller Puckette, Larry Troxler, -* Winfried Ritsch, Karl MacMillan, and others. -* For information on usage and redistribution, and for a DISCLAIMER OF ALL -* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ - -/* this file implements the sys_ functions profiled in m_imp.h for - audio and MIDI I/O on Macintosh OS X. - - Audio simply calls routines in s_portaudio.c, which in turn call the - portaudio package. s_portaudio.c is also intended for use from NT. - - MIDI is handled by "portmidi". -*/ - - -#include "m_imp.h" -#include -#ifdef UNIX -#include -#endif -#ifndef MACOSX -#include -#else -#include -#include "portaudio.h" -#include "portmidi.h" -#include "porttime.h" -#include "pminternal.h" -#endif -#include -#include -#include -#include - -/* Defines */ -#define DEBUG(x) x -#define DEBUG2(x) {x;} - -#define PA_DEFAULTCH 2 /* portaudio specific? */ -#define PA_MAXCH 100 -#define PA_DEFAULTSRATE 44100 -typedef short t_pa_sample; -#define PA_SAMPLEWIDTH sizeof(t_pa_sample) -#define PA_BYTESPERCHAN (DACBLKSIZE * PA_SAMPLEWIDTH) -#define PA_XFERSAMPS (PA_DEFAULTCH*DACBLKSIZE) -#define PA_XFERSIZE (PA_SAMPLEWIDTH * PA_XFERSAMPS) - -static int mac_whichapi = API_PORTAUDIO; -static int mac_inchannels; -static int mac_outchannels; -static int mac_advance_samples; /* scheduler advance in samples */ -static int mac_meters; /* true if we're metering */ -static float mac_inmax; /* max input amplitude */ -static float mac_outmax; /* max output amplitude */ -static int mac_blocksize = 256; /* audio I/O block size in sample frames */ - - /* exported variables */ -int sys_schedadvance = 50000; /* scheduler advance in microseconds */ -float sys_dacsr; -int sys_hipriority = 0; -t_sample *sys_soundout; -t_sample *sys_soundin; - -static PmStream *mac_midiindevlist[MAXMIDIINDEV]; -static PmStream *mac_midioutdevlist[MAXMIDIOUTDEV]; -static int mac_nmidiindev; -static int mac_nmidioutdev; - - /* set channels and sample rate. */ - -static void mac_setchsr(int chin, int chout, int sr) -{ - int nblk; - int inbytes = chin * (DACBLKSIZE*sizeof(float)); - int outbytes = chout * (DACBLKSIZE*sizeof(float)); - - mac_inchannels = chin; - mac_outchannels = chout; - sys_dacsr = sr; - mac_advance_samples = (sys_schedadvance * sys_dacsr) / (1000000.); - if (mac_advance_samples < 3 * DACBLKSIZE) - mac_advance_samples = 3 * DACBLKSIZE; - - if (sys_soundin) - free(sys_soundin); - sys_soundin = (t_float *)malloc(inbytes); - memset(sys_soundin, 0, inbytes); - - if (sys_soundout) - free(sys_soundout); - sys_soundout = (t_float *)malloc(outbytes); - memset(sys_soundout, 0, outbytes); - - if (sys_verbose) - post("input channels = %d, output channels = %d", - mac_inchannels, mac_outchannels); -} - -/* ----------------------- public routines ----------------------- */ - -void sys_open_audio(int naudioindev, int *audioindev, int nchindev, - int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev, - int *choutdev, int rate) /* IOhannes */ -{ - int inchans= - (nchindev > 0 ? chindev[0] : (nchindev == 0 ? 0 : PA_DEFAULTCH)); - int outchans= - (nchoutdev > 0 ? choutdev[0] : (nchoutdev == 0 ? 0 : PA_DEFAULTCH)); - int soundindev = (naudioindev <= 0 ? -1 : (audioindev[0]-1)); - int soundoutdev = (naudiooutdev <= 0 ? -1 : (audiooutdev[0]-1)); - int sounddev = (inchans > 0 ? soundindev : soundoutdev); - if (naudioindev > 1 || nchindev > 1 || naudiooutdev > 1 || nchoutdev > 1) - post("sorry, only one portaudio device can be open at once.\n"); - /* post("nindev %d, noutdev %d", naudioindev, naudiooutdev); - post("soundindev %d, soundoutdev %d", soundindev, soundoutdev); */ - if (sys_verbose) - post("channels in %d, out %d", inchans, outchans); - if (rate < 1) - rate = PA_DEFAULTSRATE; - mac_setchsr(inchans, outchans, rate); - pa_open_audio(inchans, outchans, rate, sys_soundin, sys_soundout, - mac_blocksize, mac_advance_samples/mac_blocksize, - soundindev, soundoutdev); -} - -void sys_close_audio(void) -{ - pa_close_audio(); -} - - -int sys_send_dacs(void) -{ - if (mac_meters) - { - int i, n; - float maxsamp; - for (i = 0, n = mac_inchannels * DACBLKSIZE, maxsamp = mac_inmax; - i < n; i++) - { - float f = sys_soundin[i]; - if (f > maxsamp) maxsamp = f; - else if (-f > maxsamp) maxsamp = -f; - } - mac_inmax = maxsamp; - for (i = 0, n = mac_outchannels * DACBLKSIZE, maxsamp = mac_outmax; - i < n; i++) - { - float f = sys_soundout[i]; - if (f > maxsamp) maxsamp = f; - else if (-f > maxsamp) maxsamp = -f; - } - mac_outmax = maxsamp; - } - return pa_send_dacs(); -} - -float sys_getsr(void) -{ - return (sys_dacsr); -} - -int sys_get_outchannels(void) -{ - return (mac_outchannels); -} - -int sys_get_inchannels(void) -{ - return (mac_inchannels); -} - -void sys_audiobuf(int n) -{ - /* set the size, in milliseconds, of the audio FIFO */ - if (n < 5) n = 5; - else if (n > 5000) n = 5000; - sys_schedadvance = n * 1000; -} - -void sys_getmeters(float *inmax, float *outmax) -{ - if (inmax) - { - mac_meters = 1; - *inmax = mac_inmax; - *outmax = mac_outmax; - } - else - mac_meters = 0; - mac_inmax = mac_outmax = 0; -} - -void sys_reportidle(void) -{ -} - -void sys_open_midi(int nmidiin, int *midiinvec, - int nmidiout, int *midioutvec) -{ - int i = 0; - int n = 0; - PmError err; - - Pt_Start(1, 0, 0); /* start a timer with millisecond accuracy */ - mac_nmidiindev = 0; - - for (i = 0; i < nmidiin; i++) - { - err = Pm_OpenInput(&mac_midiindevlist[mac_nmidiindev], midiinvec[i], - NULL, 100, NULL, NULL, NULL); - if (err) - post("could not open midi input device number %d: %s", - midiinvec[i], Pm_GetErrorText(err)); - else - { - if (sys_verbose) - post("Midi Input opened.\n"); - mac_nmidiindev++; - } - } - - mac_nmidioutdev = 0; - for (i = 0; i < nmidiout; i++) - { - err = Pm_OpenOutput(&mac_midioutdevlist[mac_nmidioutdev], midioutvec[i], - NULL, 0, NULL, NULL, 0); - if (err) - post("could not open midi output device number %d: %s", - midioutvec[i], Pm_GetErrorText(err)); - else - { - if (sys_verbose) - post("Midi Output opened.\n"); - mac_nmidioutdev++; - } - } -} - -void sys_close_midi( void) -{ - int i; - for (i = 0; i < mac_nmidiindev; i++) - Pm_Close(mac_midiindevlist[mac_nmidiindev]); - mac_nmidiindev = 0; - for (i = 0; i < mac_nmidioutdev; i++) - Pm_Close(mac_midioutdevlist[mac_nmidioutdev]); - mac_nmidioutdev = 0; -} - -void sys_putmidimess(int portno, int a, int b, int c) -{ - PmEvent buffer; - fprintf(stderr, "put 1 msg %d %d\n", portno, mac_nmidioutdev); - if (portno >= 0 && portno < mac_nmidioutdev) - { - buffer.message = Pm_Message(a, b, c); - buffer.timestamp = 0; - fprintf(stderr, "put msg\n"); - Pm_Write(mac_midioutdevlist[portno], &buffer, 1); - } -} - -void sys_putmidibyte(int portno, int byte) -{ - post("sorry, no byte-by-byte MIDI output implemented in MAC OSX"); -} - -void sys_poll_midi(void) -{ - int i, nmess; - PmEvent buffer; - for (i = 0; i < mac_nmidiindev; i++) - { - int nmess = Pm_Read(mac_midiindevlist[i], &buffer, 1); - if (nmess > 0) - { - int status = Pm_MessageStatus(buffer.message); - int data1 = Pm_MessageData1(buffer.message); - int data2 = Pm_MessageData2(buffer.message); - int msgtype = (status >> 4) - 8; - switch (msgtype) - { - case 0: - case 1: - case 2: - case 3: - case 6: - sys_midibytein(i, status); - sys_midibytein(i, data1); - sys_midibytein(i, data2); - break; - case 4: - case 5: - sys_midibytein(i, status); - sys_midibytein(i, data1); - break; - case 7: - sys_midibytein(i, status); - break; - } - } - } -} - -#if defined(_POSIX_PRIORITY_SCHEDULING) || defined(_POSIX_MEMLOCK) -#include -#endif - -void sys_set_priority(int higher) -{ -#ifdef _POSIX_PRIORITY_SCHEDULING - struct sched_param par; - int p1 ,p2, p3; - p1 = sched_get_priority_min(SCHED_FIFO); - p2 = sched_get_priority_max(SCHED_FIFO); - p3 = (higher ? p2 - 1 : p2 - 3); - par.sched_priority = p3; - if (sched_setscheduler(0,SCHED_FIFO,&par) != -1) - fprintf(stderr, "priority %d scheduling enabled.\n", p3); -#else /* no priority scheduling, so renice and wish for something better */ - int retval; - errno = 0; - retval = setpriority(PRIO_PROCESS, 0, (higher? 0 : -20)); - if (retval == -1 & errno != 0) - { - perror("setpriority"); - fprintf(stderr, "priority boost faled.\n"); - } -#endif - -#ifdef _POSIX_MEMLOCK - if (mlockall(MCL_FUTURE) != -1) - fprintf(stderr, "memory locking enabled.\n"); -#endif - -} - -void sys_listdevs(void ) -{ - pa_listdevs(); -} - -void sys_setblocksize(int n) -{ - if (n < 1) - n = 1; - if (n != (1 << ilog2(n))) - warn("blocksize adjusted to power of 2: %d", - (n = (1 << ilog2(n)))); - mac_blocksize = n; -} - - /* dummy stuff that shouldn't he here */ -void nt_soundindev(int which) -{ -} - -void nt_soundoutdev(int which) -{ -} - -void nt_midiindev(int which) -{ -} - -void nt_midioutdev(int which) -{ -} - -void nt_noresync(void ) -{ -} - -void glob_audio(void *dummy, t_floatarg fadc, t_floatarg fdac) -{ -} diff --git a/pd/src/s_main.c b/pd/src/s_main.c index f969f27e..a7820026 100644 --- a/pd/src/s_main.c +++ b/pd/src/s_main.c @@ -7,7 +7,7 @@ * 1311:forum::für::umläute:2001 */ -char pd_version[] = "Pd version 0.37 TEST 4\n"; +char pd_version[] = "Pd version 0.37.0\n"; char pd_compiletime[] = __TIME__; char pd_compiledate[] = __DATE__; @@ -36,8 +36,7 @@ int sys_argparse(int argc, char **argv); void sys_findprogdir(char *progname); int sys_startgui(const char *guipath); int sys_rcfile(void); -int m_scheduler(int nodacs); -void m_schedsetsr( void); +int m_scheduler(void); void sys_addhelppath(char *p); int sys_debuglevel; @@ -58,8 +57,28 @@ int sys_nmidiin = 0; #else int sys_nmidiin = 1; #endif -int sys_midiindevlist[MAXMIDIINDEV] = {DEFMIDIDEV}; -int sys_midioutdevlist[MAXMIDIOUTDEV] = {DEFMIDIDEV}; +int sys_midiindevlist[MAXMIDIINDEV] = {1}; +int sys_midioutdevlist[MAXMIDIOUTDEV] = {1}; + +static int sys_main_srate = DEFAULTSRATE; +static int sys_main_advance = DEFAULTADVANCE; + +/* IOhannes { */ + + /* here the "-1" counts signify that the corresponding vector hasn't been + specified in command line arguments; sys_open_audio will detect this + and fill things in. */ +int sys_nsoundin = -1; +int sys_nsoundout = -1; +int sys_soundindevlist[MAXAUDIOINDEV]; +int sys_soundoutdevlist[MAXAUDIOOUTDEV]; + +int sys_nchin = -1; +int sys_nchout = -1; +int sys_chinlist[MAXAUDIOINDEV]; +int sys_choutlist[MAXAUDIOOUTDEV]; +/* } IOhannes */ + typedef struct _fontinfo { @@ -133,25 +152,6 @@ int sys_defaultfont; #define DEFAULTFONT 10 #endif - -static int inchannels = -1, outchannels = -1; -static int srate = 44100; - -/* IOhannes { */ -#define MAXSOUNDINDEV 4 -#define MAXSOUNDOUTDEV 4 - -int sys_nsoundin = -1; -int sys_nsoundout = -1; -int sys_soundindevlist[MAXSOUNDINDEV] = {-1}; -int sys_soundoutdevlist[MAXSOUNDOUTDEV] = {-1}; - -int sys_nchin = -1; -int sys_nchout = -1; -int sys_chinlist[MAXSOUNDINDEV] = {-1}; -int sys_choutlist[MAXSOUNDOUTDEV] = {-1}; -/* } IOhannes */ - static void openit(const char *dirname, const char *filename) { char dirbuf[MAXPDSTRING], *nameptr; @@ -248,19 +248,17 @@ int sys_main(int argc, char **argv) pd_version, pd_compiletime, pd_compiledate); if (sys_version) /* if we were just asked our version, exit here. */ return (0); + if (sys_startgui(sys_guidir->s_name)) /* start the gui */ + return(1); /* open audio and MIDI */ sys_open_midi(sys_nmidiin, sys_midiindevlist, sys_nmidiout, sys_midioutdevlist); sys_open_audio(sys_nsoundin, sys_soundindevlist, sys_nchin, sys_chinlist, - sys_nsoundout, sys_soundoutdevlist, sys_nchout, sys_choutlist, srate); - - /* tell scheduler the sample rate */ - m_schedsetsr(); - if (sys_startgui(sys_guidir->s_name)) /* start the gui */ - return(1); + sys_nsoundout, sys_soundoutdevlist, sys_nchout, sys_choutlist, + sys_main_srate, sys_main_advance, 1); /* run scheduler until it quits */ - return (m_scheduler(!(inchannels || outchannels))); + return (m_scheduler()); } static char *(usagemessage[]) = { @@ -288,19 +286,24 @@ static char *(usagemessage[]) = { #ifdef USEAPI_ALSA "-alsa -- use ALSA audio API\n", -"-alsadev ----- ALSA device # (count from 1) or name: default hw:0,0\n", +"-alsadev ----- obsolete: use -audiodev\n", +#endif + +#ifdef USEAPI_JACK +"-jack -- use JACK audio API\n", #endif #ifdef USEAPI_PORTAUDIO #ifdef MSW -"-pa -- use Portaudio API (for ASIO)\n", +"-asio -- use ASIO audio driver (via Portaudio)\n", +"-pa -- synonym for -asio\n", #else "-pa -- use Portaudio API\n", #endif #endif #ifdef USEAPI_MMIO -"-mmio -- use MMIO audio API\n", +"-mmio -- use MMIO audio API (default for Windows)\n", #endif " (default audio API for this platform: ", API_DEFSTRING, ")\n\n", @@ -329,7 +332,7 @@ static char *(usagemessage[]) = { "-rt or -realtime -- use real-time priority (needs root privilege)\n", #endif }; - + static void sys_parsedevlist(int *np, int *vecp, int max, char *str) { int n = 0; @@ -363,7 +366,7 @@ static int sys_getmultidevchannels(int n, int *devlist) /* this routine tries to figure out where to find the auxilliary files Pd will need to run. This is either done by looking at the command line - invokation for Pd, or if htat fails, by consulting the variable + invokation for Pd, or if that fails, by consulting the variable INSTALL_PREFIX. In MSW, we don't try to use INSTALL_PREFIX. */ void sys_findprogdir(char *progname) { @@ -458,19 +461,25 @@ void sys_findprogdir(char *progname) int sys_argparse(int argc, char **argv) { char sbuf[MAXPDSTRING]; + int i; +#ifdef MSW + int mmio = 1; +#else + int mmio = 0; +#endif argc--; argv++; while ((argc > 0) && **argv == '-') { if (!strcmp(*argv, "-r") && argc > 1 && - sscanf(argv[1], "%d", &srate) >= 1) + sscanf(argv[1], "%d", &sys_main_srate) >= 1) { argc -= 2; argv += 2; } else if (!strcmp(*argv, "-inchannels")) - { /* IOhannes */ - sys_parsedevlist(&sys_nchin, sys_chinlist, MAXSOUNDINDEV, argv[1]); - inchannels=sys_getmultidevchannels(sys_nchin, sys_chinlist); + { /* IOhannes */ + sys_parsedevlist(&sys_nchin, + sys_chinlist, MAXAUDIOINDEV, argv[1]); if (!sys_nchin) goto usage; @@ -478,9 +487,9 @@ int sys_argparse(int argc, char **argv) argc -= 2; argv += 2; } else if (!strcmp(*argv, "-outchannels")) - { /* IOhannes */ - sys_parsedevlist(&sys_nchout, sys_choutlist,MAXSOUNDOUTDEV, argv[1]); - outchannels=sys_getmultidevchannels(sys_nchout, sys_choutlist); + { /* IOhannes */ + sys_parsedevlist(&sys_nchout, sys_choutlist, + MAXAUDIOOUTDEV, argv[1]); if (!sys_nchout) goto usage; @@ -489,12 +498,10 @@ int sys_argparse(int argc, char **argv) } else if (!strcmp(*argv, "-channels")) { - sys_parsedevlist(&sys_nchin, sys_chinlist,MAXSOUNDINDEV, + sys_parsedevlist(&sys_nchin, sys_chinlist,MAXAUDIOINDEV, argv[1]); - inchannels = sys_getmultidevchannels(sys_nchin, sys_chinlist); - sys_parsedevlist(&sys_nchout, sys_choutlist,MAXSOUNDOUTDEV, + sys_parsedevlist(&sys_nchout, sys_choutlist,MAXAUDIOOUTDEV, argv[1]); - outchannels = sys_getmultidevchannels(sys_nchout, sys_choutlist); if (!sys_nchout) goto usage; @@ -503,7 +510,7 @@ int sys_argparse(int argc, char **argv) } else if (!strcmp(*argv, "-soundbuf") || !strcmp(*argv, "-audiobuf")) { - sys_audiobuf(atoi(argv[1])); + sys_main_advance = atoi(argv[1]); argc -= 2; argv += 2; } else if (!strcmp(*argv, "-blocksize")) @@ -520,32 +527,29 @@ int sys_argparse(int argc, char **argv) { /* IOhannes */ sys_nsoundout=0; sys_nchout = 0; - outchannels =0; argc--; argv++; } else if (!strcmp(*argv, "-noadc")) { /* IOhannes */ sys_nsoundin=0; sys_nchin = 0; - inchannels =0; argc--; argv++; } else if (!strcmp(*argv, "-nosound") || !strcmp(*argv, "-noaudio")) { /* IOhannes */ sys_nsoundin=sys_nsoundout = 0; sys_nchin = sys_nchout = 0; - inchannels =outchannels =0; argc--; argv++; } #ifdef USEAPI_OSS else if (!strcmp(*argv, "-oss")) { - sys_set_sound_api(API_OSS); + sys_set_audio_api(API_OSS); argc--; argv++; } else if (!strcmp(*argv, "-32bit")) { - sys_set_sound_api(API_OSS); + sys_set_audio_api(API_OSS); oss_set32bit(); argc--; argv++; } @@ -553,33 +557,51 @@ int sys_argparse(int argc, char **argv) #ifdef USEAPI_ALSA else if (!strcmp(*argv, "-alsa")) { - sys_set_sound_api(API_ALSA); + sys_set_audio_api(API_ALSA); argc--; argv++; } + /* obsolete flag for setting ALSA device number or name */ else if (!strcmp(*argv, "-alsadev")) { + int devno = 0; if (argv[1][0] >= '1' && argv[1][0] <= '9') - { - char buf[80]; - sprintf(buf, "hw:%d,0", atoi(argv[1]) - 1); - linux_alsa_devname(buf); - } - else linux_alsa_devname(argv[1]); - sys_set_sound_api(API_ALSA); + devno = 1 + 2 * (atoi(argv[1]) - 1); + else if (!strncmp(argv[1], "hw:", 3)) + devno = 1 + 2 * atoi(argv[1]+3); + else if (!strncmp(argv[1], "plughw:", 7)) + devno = 2 + 2 * atoi(argv[1]+7); + else goto usage; + post("devno %d", devno); + sys_nsoundin = sys_nsoundout = 1; + sys_soundindevlist[0] = sys_soundoutdevlist[0] = devno; + sys_set_audio_api(API_ALSA); argc -= 2; argv +=2; } #endif +#ifdef USEAPI_JACK + else if (!strcmp(*argv, "-jack")) + { + sys_set_audio_api(API_JACK); + argc--; argv++; + } +#endif #ifdef USEAPI_PORTAUDIO - else if (!strcmp(*argv, "-pa") || !strcmp(*argv, "-portaudio")) + else if (!strcmp(*argv, "-pa") || !strcmp(*argv, "-portaudio") +#ifdef MSW + || !strcmp(*argv, "-asio") +#endif + ) { - sys_set_sound_api(API_PORTAUDIO); + sys_set_audio_api(API_PORTAUDIO); + mmio = 0; argc--; argv++; } #endif #ifdef USEAPI_MMIO else if (!strcmp(*argv, "-mmio")) { - sys_set_sound_api(API_MMIO); + sys_set_audio_api(API_MMIO); + mmio = 1; argc--; argv++; } #endif @@ -702,7 +724,7 @@ int sys_argparse(int argc, char **argv) !strcmp(*argv, "-audioindev")) { /* IOhannes */ sys_parsedevlist(&sys_nsoundin, sys_soundindevlist, - MAXSOUNDINDEV, argv[1]); + MAXAUDIOINDEV, argv[1]); if (!sys_nsoundin) goto usage; argc -= 2; argv += 2; @@ -711,7 +733,7 @@ int sys_argparse(int argc, char **argv) !strcmp(*argv, "-audiooutdev")) { /* IOhannes */ sys_parsedevlist(&sys_nsoundout, sys_soundoutdevlist, - MAXSOUNDOUTDEV, argv[1]); + MAXAUDIOOUTDEV, argv[1]); if (!sys_nsoundout) goto usage; argc -= 2; argv += 2; @@ -719,9 +741,9 @@ int sys_argparse(int argc, char **argv) else if (!strcmp(*argv, "-sounddev") || !strcmp(*argv, "-audiodev")) { sys_parsedevlist(&sys_nsoundin, sys_soundindevlist, - MAXSOUNDINDEV, argv[1]); + MAXAUDIOINDEV, argv[1]); sys_parsedevlist(&sys_nsoundout, sys_soundoutdevlist, - MAXSOUNDOUTDEV, argv[1]); + MAXAUDIOOUTDEV, argv[1]); if (!sys_nsoundout) goto usage; argc -= 2; argv += 2; @@ -740,6 +762,22 @@ int sys_argparse(int argc, char **argv) for (; argc > 0; argc--, argv++) sys_openlist = namelist_append(sys_openlist, *argv); + /* correct to make audio and MIDI device lists zero based. On + MMIO, however, "1" really means the second device (the first one + is "mapper" which is was not included when the command args were + set up, so we leave it that way for compatibility. */ + if (!mmio) + { + for (i = 0; i < sys_nsoundin; i++) + sys_soundindevlist[i]--; + for (i = 0; i < sys_nsoundout; i++) + sys_soundoutdevlist[i]--; + } + for (i = 0; i < sys_nmidiin; i++) + sys_midiindevlist[i]--; + for (i = 0; i < sys_nmidiout; i++) + sys_midioutdevlist[i]--; + return (0); } diff --git a/pd/src/s_midi.c b/pd/src/s_midi.c index 2bba9a45..0382d0b0 100644 --- a/pd/src/s_midi.c +++ b/pd/src/s_midi.c @@ -403,3 +403,197 @@ void sys_pollmidiqueue( void) sys_pollmidioutqueue(); sys_pollmidiinqueue(); } + +/******************** dialog window and device listing ********************/ + +#ifdef USEAPI_OSS +void midi_oss_init( void); +#endif + + /* last requested parameters */ +static int midi_nmidiindev; +static int midi_midiindev[MAXMIDIINDEV]; +static int midi_nmidioutdev; +static int midi_midioutdev[MAXMIDIOUTDEV]; + +static void sys_get_midi_params(int *pnmidiindev, int *pmidiindev, + int *pnmidioutdev, int *pmidioutdev) +{ + int i; + *pnmidiindev = midi_nmidiindev; + for (i = 0; i < MAXMIDIINDEV; i++) + pmidiindev[i] = midi_midiindev[i]; + *pnmidioutdev = midi_nmidioutdev; + for (i = 0; i < MAXMIDIOUTDEV; i++) + pmidioutdev[i] = midi_midioutdev[i]; +} + +static void sys_save_midi_params( + int nmidiindev, int *midiindev, + int nmidioutdev, int *midioutdev) +{ + int i; + midi_nmidiindev = nmidiindev; + for (i = 0; i < MAXMIDIINDEV; i++) + midi_midiindev[i] = midiindev[i]; + midi_nmidioutdev = nmidioutdev; + for (i = 0; i < MAXMIDIOUTDEV; i++) + midi_midioutdev[i] = midioutdev[i]; +} + +void sys_open_midi(int nmidiindev, int *midiindev, + int nmidioutdev, int *midioutdev) +{ +#ifdef USEAPI_OSS + midi_oss_init(); +#endif + sys_do_open_midi(nmidiindev, midiindev, nmidioutdev, midioutdev); + sys_save_midi_params(nmidiindev, midiindev, + nmidioutdev, midioutdev); +} + + /* open midi using whatever parameters were last used */ +void sys_reopen_midi( void) +{ + int nmidiindev, midiindev[MAXMIDIINDEV]; + int nmidioutdev, midioutdev[MAXMIDIOUTDEV]; + sys_get_midi_params(&nmidiindev, midiindev, &nmidioutdev, midioutdev); + sys_open_midi(nmidiindev, midiindev, nmidioutdev, midioutdev); +} + +#define MAXNDEV 20 +#define DEVDESCSIZE 80 + +#ifdef MSW +#define DEVONSET 0 /* microsoft device list starts at 0 (the "mapper"). */ +#else /* (see also MSW ifdef in sys_parsedevlist(), s_main.c) */ +#define DEVONSET 1 /* To agree with command line flags, normally start at 1 */ +#endif + +void sys_listmididevs(void ) +{ + char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE]; + int nindevs = 0, noutdevs = 0, i; + + midi_getdevs(indevlist, &nindevs, outdevlist, &noutdevs, + MAXNDEV, DEVDESCSIZE); + + if (!nindevs) + post("no midi input devices found"); + else + { + post("input devices:"); + for (i = 0; i < nindevs; i++) + post("%d. %s", i+1, indevlist + i * DEVDESCSIZE); + } + if (!noutdevs) + post("no midi output devices found"); + else + { + post("output devices:"); + for (i = 0; i < noutdevs; i++) + post("%d. %s", i+DEVONSET, outdevlist + i * DEVDESCSIZE); + } +} + +extern t_class *glob_pdobject; + + /* start an midi settings dialog window */ +void glob_midi_properties(t_pd *dummy, t_floatarg flongform) +{ + char buf[1024 + 2 * MAXNDEV*(DEVDESCSIZE+4)]; + /* these are the devices you're using: */ + int nindev, midiindev[MAXMIDIINDEV]; + int noutdev, midioutdev[MAXMIDIOUTDEV]; + int midiindev1, midiindev2, midiindev3, midiindev4, + midioutdev1, midioutdev2, midioutdev3, midioutdev4; + + /* these are all the devices on your system: */ + char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE]; + int nindevs = 0, noutdevs = 0, i; + + char indevliststring[MAXNDEV*(DEVDESCSIZE+4)+80], + outdevliststring[MAXNDEV*(DEVDESCSIZE+4)+80]; + + midi_getdevs(indevlist, &nindevs, outdevlist, &noutdevs, + MAXNDEV, DEVDESCSIZE); + + strcpy(indevliststring, "{ {none} "); + for (i = 0; i < nindevs; i++) + { + strcat(indevliststring, "\""); + strcat(indevliststring, indevlist + i * DEVDESCSIZE); + strcat(indevliststring, "\" "); + } + strcat(indevliststring, "}"); + + strcpy(outdevliststring, "{ {none} "); + for (i = 0; i < noutdevs; i++) + { + strcat(outdevliststring, "\""); + strcat(outdevliststring, outdevlist + i * DEVDESCSIZE); + strcat(outdevliststring, "\" "); + } + strcat(outdevliststring, "}"); + + sys_get_midi_params(&nindev, midiindev, &noutdev, midioutdev); + + if (nindev > 1 || noutdev > 1) + flongform = 1; + + midiindev1 = (nindev > 0 && midiindev[0]>= 0 ? midiindev[0]+1 : 0); + midiindev2 = (nindev > 1 && midiindev[1]>= 0 ? midiindev[1]+1 : 0); + midiindev3 = (nindev > 2 && midiindev[2]>= 0 ? midiindev[2]+1 : 0); + midiindev4 = (nindev > 3 && midiindev[3]>= 0 ? midiindev[3]+1 : 0); + midioutdev1 = (noutdev > 0 && midioutdev[0]>=0 ? midioutdev[0]+1 : 0); + midioutdev2 = (noutdev > 1 && midioutdev[1]>=0 ? midioutdev[1]+1 : 0); + midioutdev3 = (noutdev > 2 && midioutdev[2]>=0 ? midioutdev[2]+1 : 0); + midioutdev4 = (noutdev > 3 && midioutdev[3]>=0 ? midioutdev[3]+1 : 0); + + sprintf(buf, +"pdtk_midi_dialog %%s \ +%s %d %d %d %d %s %d %d %d %d \ +%d\n", + indevliststring, + midiindev1, midiindev2, midiindev3, midiindev4, + outdevliststring, + midioutdev1, midioutdev2, midioutdev3, midioutdev4, + (flongform != 0)); + gfxstub_deleteforkey(0); + gfxstub_new(&glob_pdobject, glob_midi_properties, buf); +} + + /* new values from dialog window */ +void glob_midi_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv) +{ + int nmidiindev, midiindev[MAXMIDIINDEV]; + int nmidioutdev, midioutdev[MAXMIDIOUTDEV]; + int i, nindev, noutdev; + int newmidiindev[4], newmidioutdev[4]; + + for (i = 0; i < 4; i++) + { + newmidiindev[i] = atom_getintarg(i, argc, argv); + newmidioutdev[i] = atom_getintarg(i+4, argc, argv); + } + + for (i = 0, nindev = 0; i < 4; i++) + { + if (newmidiindev[i] > 0) + { + newmidiindev[nindev] = newmidiindev[i]-1; + nindev++; + } + } + for (i = 0, noutdev = 0; i < 4; i++) + { + if (newmidioutdev[i] > 0) + { + newmidioutdev[noutdev] = newmidioutdev[i]-1; + noutdev++; + } + } + + sys_close_midi(); + sys_open_midi(nindev, newmidiindev, noutdev, newmidioutdev); +} diff --git a/pd/src/s_midi_mmio.c b/pd/src/s_midi_mmio.c new file mode 100644 index 00000000..ec1a75ee --- /dev/null +++ b/pd/src/s_midi_mmio.c @@ -0,0 +1,715 @@ +/* Copyright (c) 1997-1999 Miller Puckette. +* For information on usage and redistribution, and for a DISCLAIMER OF ALL +* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ + +#include "m_pd.h" +#include "s_stuff.h" +#include + +#include +#include + + /* ------------- MIDI time stamping from audio clock ------------ */ + +#ifdef MIDI_TIMESTAMP + +static double msw_hibuftime; +static double initsystime = -1; + + /* call this whenever we reset audio */ +static void msw_resetmidisync(void) +{ + initsystime = clock_getsystime(); + msw_hibuftime = sys_getrealtime(); +} + + /* call this whenever we're idled waiting for audio to be ready. + The routine maintains a high and low water point for the difference + between real and DAC time. */ + +static void msw_midisync(void) +{ + double jittersec, diff; + + if (initsystime == -1) msw_resetmidisync(); + jittersec = (msw_dacjitterbufsallowed > msw_adcjitterbufsallowed ? + msw_dacjitterbufsallowed : msw_adcjitterbufsallowed) + * REALDACBLKSIZE / sys_getsr(); + diff = sys_getrealtime() - 0.001 * clock_gettimesince(initsystime); + if (diff > msw_hibuftime) msw_hibuftime = diff; + if (diff < msw_hibuftime - jittersec) + { + post("jitter excess %d %f", dac, diff); + msw_resetmidisync(); + } +} + +static double msw_midigettimefor(LARGE_INTEGER timestamp) +{ + /* this is broken now... used to work when "timestamp" was derived from + QueryPerformanceCounter() instead of the gates approved + timeGetSystemTime() call in the MIDI callback routine below. */ + return (msw_tixtotime(timestamp) - msw_hibuftime); +} +#endif /* MIDI_TIMESTAMP */ + + +/* ------------------------- MIDI output -------------------------- */ +static void msw_midiouterror(char *s, int err) +{ + char t[256]; + midiOutGetErrorText(err, t, 256); + fprintf(stderr, s, t); +} + +static HMIDIOUT hMidiOut[MAXMIDIOUTDEV]; /* output device */ +static int msw_nmidiout; /* number of devices */ + +static void msw_open_midiout(int nmidiout, int *midioutvec) +{ + UINT result, wRtn; + int i; + int dev; + MIDIOUTCAPS midioutcaps; + if (nmidiout > MAXMIDIOUTDEV) + nmidiout = MAXMIDIOUTDEV; + + dev = 0; + + for (i = 0; i < nmidiout; i++) + { + MIDIOUTCAPS mocap; + int devno = (midioutvec[i] == DEFMIDIDEV ? + MIDI_MAPPER : midioutvec[i]-1); + result = midiOutOpen(&hMidiOut[dev], devno, 0, 0, + CALLBACK_NULL); + wRtn = midiOutGetDevCaps(i, (LPMIDIOUTCAPS) &mocap, + sizeof(mocap)); + if (result != MMSYSERR_NOERROR) + { + fprintf(stderr,"midiOutOpen: %s\n",midioutcaps.szPname); + msw_midiouterror("midiOutOpen: %s\n", result); + } + else + { + if (sys_verbose) + fprintf(stderr,"midiOutOpen: Open %s as Port %d\n", + midioutcaps.szPname, dev); + dev++; + } + } + msw_nmidiout = dev; +} + +static void msw_close_midiout(void) +{ + int i; + for (i = 0; i < msw_nmidiout; i++) + { + midiOutReset(hMidiOut[i]); + midiOutClose(hMidiOut[i]); + } + msw_nmidiout = 0; +} + +/* -------------------------- MIDI input ---------------------------- */ + +#define INPUT_BUFFER_SIZE 1000 // size of input buffer in events + +static void msw_midiinerror(char *s, int err) +{ + char t[256]; + midiInGetErrorText(err, t, 256); + fprintf(stderr, s, t); +} + + +/* Structure to represent a single MIDI event. + */ + +#define EVNT_F_ERROR 0x00000001L + +typedef struct evemsw_tag +{ + DWORD fdwEvent; + DWORD dwDevice; + LARGE_INTEGER timestamp; + DWORD data; +} EVENT; +typedef EVENT FAR *LPEVENT; + +/* Structure to manage the circular input buffer. + */ +typedef struct circularBuffer_tag +{ + HANDLE hSelf; /* handle to this structure */ + HANDLE hBuffer; /* buffer handle */ + WORD wError; /* error flags */ + DWORD dwSize; /* buffer size (in EVENTS) */ + DWORD dwCount; /* byte count (in EVENTS) */ + LPEVENT lpStart; /* ptr to start of buffer */ + LPEVENT lpEnd; /* ptr to end of buffer (last byte + 1) */ + LPEVENT lpHead; /* ptr to head (next location to fill) */ + LPEVENT lpTail; /* ptr to tail (next location to empty) */ +} CIRCULARBUFFER; +typedef CIRCULARBUFFER FAR *LPCIRCULARBUFFER; + + +/* Structure to pass instance data from the application + to the low-level callback function. + */ +typedef struct callbackInstance_tag +{ + HANDLE hSelf; + DWORD dwDevice; + LPCIRCULARBUFFER lpBuf; +} CALLBACKINSTANCEDATA; +typedef CALLBACKINSTANCEDATA FAR *LPCALLBACKINSTANCEDATA; + +/* Function prototypes + */ +LPCALLBACKINSTANCEDATA FAR PASCAL AllocCallbackInstanceData(void); +void FAR PASCAL FreeCallbackInstanceData(LPCALLBACKINSTANCEDATA lpBuf); + +LPCIRCULARBUFFER AllocCircularBuffer(DWORD dwSize); +void FreeCircularBuffer(LPCIRCULARBUFFER lpBuf); +WORD FAR PASCAL GetEvent(LPCIRCULARBUFFER lpBuf, LPEVENT lpEvent); + +// Callback instance data pointers +LPCALLBACKINSTANCEDATA lpCallbackInstanceData[MAXMIDIINDEV]; + +UINT wNumDevices = 0; // Number of MIDI input devices opened +BOOL bRecordingEnabled = 1; // Enable/disable recording flag +int nNumBufferLines = 0; // Number of lines in display buffer +RECT rectScrollClip; // Clipping rectangle for scrolling + +LPCIRCULARBUFFER lpInputBuffer; // Input buffer structure +EVENT incomingEvent; // Incoming MIDI event structure + +MIDIINCAPS midiInCaps[MAXMIDIINDEV]; // Device capabilities structures +HMIDIIN hMidiIn[MAXMIDIINDEV]; // MIDI input device handles + + +/* AllocCallbackInstanceData - Allocates a CALLBACKINSTANCEDATA + * structure. This structure is used to pass information to the + * low-level callback function, each time it receives a message. + * + * Because this structure is accessed by the low-level callback + * function, it must be allocated using GlobalAlloc() with the + * GMEM_SHARE and GMEM_MOVEABLE flags and page-locked with + * GlobalPageLock(). + * + * Params: void + * + * Return: A pointer to the allocated CALLBACKINSTANCE data structure. + */ +LPCALLBACKINSTANCEDATA FAR PASCAL AllocCallbackInstanceData(void) +{ + HANDLE hMem; + LPCALLBACKINSTANCEDATA lpBuf; + + /* Allocate and lock global memory. + */ + hMem = GlobalAlloc(GMEM_SHARE | GMEM_MOVEABLE, + (DWORD)sizeof(CALLBACKINSTANCEDATA)); + if(hMem == NULL) + return NULL; + + lpBuf = (LPCALLBACKINSTANCEDATA)GlobalLock(hMem); + if(lpBuf == NULL){ + GlobalFree(hMem); + return NULL; + } + + /* Page lock the memory. + */ + //GlobalPageLock((HGLOBAL)HIWORD(lpBuf)); + + /* Save the handle. + */ + lpBuf->hSelf = hMem; + + return lpBuf; +} + +/* FreeCallbackInstanceData - Frees the given CALLBACKINSTANCEDATA structure. + * + * Params: lpBuf - Points to the CALLBACKINSTANCEDATA structure to be freed. + * + * Return: void + */ +void FAR PASCAL FreeCallbackInstanceData(LPCALLBACKINSTANCEDATA lpBuf) +{ + HANDLE hMem; + + /* Save the handle until we're through here. + */ + hMem = lpBuf->hSelf; + + /* Free the structure. + */ + //GlobalPageUnlock((HGLOBAL)HIWORD(lpBuf)); + GlobalUnlock(hMem); + GlobalFree(hMem); +} + + +/* + * AllocCircularBuffer - Allocates memory for a CIRCULARBUFFER structure + * and a buffer of the specified size. Each memory block is allocated + * with GlobalAlloc() using GMEM_SHARE and GMEM_MOVEABLE flags, locked + * with GlobalLock(), and page-locked with GlobalPageLock(). + * + * Params: dwSize - The size of the buffer, in events. + * + * Return: A pointer to a CIRCULARBUFFER structure identifying the + * allocated display buffer. NULL if the buffer could not be allocated. + */ + + +LPCIRCULARBUFFER AllocCircularBuffer(DWORD dwSize) +{ + HANDLE hMem; + LPCIRCULARBUFFER lpBuf; + LPEVENT lpMem; + + /* Allocate and lock a CIRCULARBUFFER structure. + */ + hMem = GlobalAlloc(GMEM_SHARE | GMEM_MOVEABLE, + (DWORD)sizeof(CIRCULARBUFFER)); + if(hMem == NULL) + return NULL; + + lpBuf = (LPCIRCULARBUFFER)GlobalLock(hMem); + if(lpBuf == NULL) + { + GlobalFree(hMem); + return NULL; + } + + /* Page lock the memory. Global memory blocks accessed by + * low-level callback functions must be page locked. + */ +#ifndef _WIN32 + GlobalSmartPageLock((HGLOBAL)HIWORD(lpBuf)); +#endif + + /* Save the memory handle. + */ + lpBuf->hSelf = hMem; + + /* Allocate and lock memory for the actual buffer. + */ + hMem = GlobalAlloc(GMEM_SHARE | GMEM_MOVEABLE, dwSize * sizeof(EVENT)); + if(hMem == NULL) + { +#ifndef _WIN32 + GlobalSmartPageUnlock((HGLOBAL)HIWORD(lpBuf)); +#endif + GlobalUnlock(lpBuf->hSelf); + GlobalFree(lpBuf->hSelf); + return NULL; + } + + lpMem = (LPEVENT)GlobalLock(hMem); + if(lpMem == NULL) + { + GlobalFree(hMem); +#ifndef _WIN32 + GlobalSmartPageUnlock((HGLOBAL)HIWORD(lpBuf)); +#endif + GlobalUnlock(lpBuf->hSelf); + GlobalFree(lpBuf->hSelf); + return NULL; + } + + /* Page lock the memory. Global memory blocks accessed by + * low-level callback functions must be page locked. + */ +#ifndef _WIN32 + GlobalSmartPageLock((HGLOBAL)HIWORD(lpMem)); +#endif + + /* Set up the CIRCULARBUFFER structure. + */ + lpBuf->hBuffer = hMem; + lpBuf->wError = 0; + lpBuf->dwSize = dwSize; + lpBuf->dwCount = 0L; + lpBuf->lpStart = lpMem; + lpBuf->lpEnd = lpMem + dwSize; + lpBuf->lpTail = lpMem; + lpBuf->lpHead = lpMem; + + return lpBuf; +} + +/* FreeCircularBuffer - Frees the memory for the given CIRCULARBUFFER + * structure and the memory for the buffer it references. + * + * Params: lpBuf - Points to the CIRCULARBUFFER to be freed. + * + * Return: void + */ +void FreeCircularBuffer(LPCIRCULARBUFFER lpBuf) +{ + HANDLE hMem; + + /* Free the buffer itself. + */ +#ifndef _WIN32 + GlobalSmartPageUnlock((HGLOBAL)HIWORD(lpBuf->lpStart)); +#endif + GlobalUnlock(lpBuf->hBuffer); + GlobalFree(lpBuf->hBuffer); + + /* Free the CIRCULARBUFFER structure. + */ + hMem = lpBuf->hSelf; +#ifndef _WIN32 + GlobalSmartPageUnlock((HGLOBAL)HIWORD(lpBuf)); +#endif + GlobalUnlock(hMem); + GlobalFree(hMem); +} + +/* GetEvent - Gets a MIDI event from the circular input buffer. Events + * are removed from the buffer. The corresponding PutEvent() function + * is called by the low-level callback function, so it must reside in + * the callback DLL. PutEvent() is defined in the CALLBACK.C module. + * + * Params: lpBuf - Points to the circular buffer. + * lpEvent - Points to an EVENT structure that is filled with the + * retrieved event. + * + * Return: Returns non-zero if successful, zero if there are no + * events to get. + */ +WORD FAR PASCAL GetEvent(LPCIRCULARBUFFER lpBuf, LPEVENT lpEvent) +{ + /* If no event available, return */ + if (!wNumDevices || lpBuf->dwCount <= 0) return (0); + + /* Get the event. + */ + *lpEvent = *lpBuf->lpTail; + + /* Decrement the byte count, bump the tail pointer. + */ + --lpBuf->dwCount; + ++lpBuf->lpTail; + + /* Wrap the tail pointer, if necessary. + */ + if(lpBuf->lpTail >= lpBuf->lpEnd) + lpBuf->lpTail = lpBuf->lpStart; + + return 1; +} + +/* PutEvent - Puts an EVENT in a CIRCULARBUFFER. If the buffer is full, + * it sets the wError element of the CIRCULARBUFFER structure + * to be non-zero. + * + * Params: lpBuf - Points to the CIRCULARBUFFER. + * lpEvent - Points to the EVENT. + * + * Return: void +*/ + +void FAR PASCAL PutEvent(LPCIRCULARBUFFER lpBuf, LPEVENT lpEvent) +{ + /* If the buffer is full, set an error and return. + */ + if(lpBuf->dwCount >= lpBuf->dwSize){ + lpBuf->wError = 1; + return; + } + + /* Put the event in the buffer, bump the head pointer and the byte count. + */ + *lpBuf->lpHead = *lpEvent; + + ++lpBuf->lpHead; + ++lpBuf->dwCount; + + /* Wrap the head pointer, if necessary. + */ + if(lpBuf->lpHead >= lpBuf->lpEnd) + lpBuf->lpHead = lpBuf->lpStart; +} + +/* midiInputHandler - Low-level callback function to handle MIDI input. + * Installed by midiInOpen(). The input handler takes incoming + * MIDI events and places them in the circular input buffer. It then + * notifies the application by posting a MM_MIDIINPUT message. + * + * This function is accessed at interrupt time, so it should be as + * fast and efficient as possible. You can't make any + * Windows calls here, except PostMessage(). The only Multimedia + * Windows call you can make are timeGetSystemTime(), midiOutShortMsg(). + * + * + * Param: hMidiIn - Handle for the associated input device. + * wMsg - One of the MIM_***** messages. + * dwInstance - Points to CALLBACKINSTANCEDATA structure. + * dwParam1 - MIDI data. + * dwParam2 - Timestamp (in milliseconds) + * + * Return: void + */ +void FAR PASCAL midiInputHandler( +HMIDIIN hMidiIn, +WORD wMsg, +DWORD dwInstance, +DWORD dwParam1, +DWORD dwParam2) +{ + EVENT event; + + switch(wMsg) + { + case MIM_OPEN: + break; + + /* The only error possible is invalid MIDI data, so just pass + * the invalid data on so we'll see it. + */ + case MIM_ERROR: + case MIM_DATA: + event.fdwEvent = (wMsg == MIM_ERROR) ? EVNT_F_ERROR : 0; + event.dwDevice = ((LPCALLBACKINSTANCEDATA)dwInstance)->dwDevice; + event.data = dwParam1; +#ifdef MIDI_TIMESTAMP + event.timestamp = timeGetSystemTime(); +#endif + /* Put the MIDI event in the circular input buffer. + */ + + PutEvent(((LPCALLBACKINSTANCEDATA)dwInstance)->lpBuf, + (LPEVENT) &event); + + break; + + default: + break; + } +} + +void msw_open_midiin(int nmidiin, int *midiinvec) +{ + UINT wRtn; + char szErrorText[256]; + unsigned int i; + unsigned int ndev = 0; + /* Allocate a circular buffer for low-level MIDI input. This buffer + * is filled by the low-level callback function and emptied by the + * application. + */ + lpInputBuffer = AllocCircularBuffer((DWORD)(INPUT_BUFFER_SIZE)); + if (lpInputBuffer == NULL) + { + printf("Not enough memory available for input buffer.\n"); + return; + } + + /* Open all MIDI input devices after allocating and setting up + * instance data for each device. The instance data is used to + * pass buffer management information between the application and + * the low-level callback function. It also includes a device ID, + * a handle to the MIDI Mapper, and a handle to the application's + * display window, so the callback can notify the window when input + * data is available. A single callback function is used to service + * all opened input devices. + */ + for (i=0; (i<(unsigned)nmidiin) && (idwDevice = i; + lpCallbackInstanceData[i]->lpBuf = lpInputBuffer; + + wRtn = midiInOpen((LPHMIDIIN)&hMidiIn[ndev], + midiinvec[i] - 1, + (DWORD)midiInputHandler, + (DWORD)lpCallbackInstanceData[ndev], + CALLBACK_FUNCTION); + if (wRtn) + { + FreeCallbackInstanceData(lpCallbackInstanceData[ndev]); + msw_midiinerror("midiInOpen: %s\n", wRtn); + } + else ndev++; + } + + /* Start MIDI input. + */ + for (i=0; i= 0 && portno < msw_nmidiout) + { + foo = (a & 0xff) | ((b & 0xff) << 8) | ((c & 0xff) << 16); + res = midiOutShortMsg(hMidiOut[portno], foo); + if (res != MMSYSERR_NOERROR) + post("MIDI out error %d", res); + } +} + +void sys_putmidibyte(int portno, int byte) +{ + MMRESULT res; + if (portno >= 0 && portno < msw_nmidiout) + { + res = midiOutShortMsg(hMidiOut[portno], byte); + if (res != MMSYSERR_NOERROR) + post("MIDI out error %d", res); + } +} + +void sys_poll_midi(void) +{ + static EVENT msw_nextevent; + static int msw_isnextevent; + static double msw_nexteventtime; + + while (1) + { + if (!msw_isnextevent) + { + if (!GetEvent(lpInputBuffer, &msw_nextevent)) break; + msw_isnextevent = 1; +#ifdef MIDI_TIMESTAMP + msw_nexteventtime = msw_midigettimefor(&foo.timestamp); +#endif + } +#ifdef MIDI_TIMESTAMP + if (0.001 * clock_gettimesince(initsystime) >= msw_nexteventtime) +#endif + { + int msgtype = ((msw_nextevent.data & 0xf0) >> 4) - 8; + int commandbyte = msw_nextevent.data & 0xff; + int byte1 = (msw_nextevent.data >> 8) & 0xff; + int byte2 = (msw_nextevent.data >> 16) & 0xff; + int portno = msw_nextevent.dwDevice; + switch (msgtype) + { + case 0: + case 1: + case 2: + case 3: + case 6: + sys_midibytein(portno, commandbyte); + sys_midibytein(portno, byte1); + sys_midibytein(portno, byte2); + break; + case 4: + case 5: + sys_midibytein(portno, commandbyte); + sys_midibytein(portno, byte1); + break; + case 7: + sys_midibytein(portno, commandbyte); + break; + } + msw_isnextevent = 0; + } + } +} + +void sys_open_midi(int nmidiin, int *midiinvec, int nmidiout, int *midioutvec) +{ + if (nmidiout) + msw_open_midiout(nmidiout, midioutvec); + if (nmidiin) + { + post( + "midi input enabled; warning, don't close the DOS window directly!"); + msw_open_midiin(nmidiin, midiinvec); + } + else post("not using MIDI input (use 'pd -midiindev 1' to override)"); +} + +void sys_close_midi( void) +{ + msw_close_midiin(); + msw_close_midiout(); +} + + +/* list the audio and MIDI device names */ +void sys_listmididevs(void) +{ + UINT wRtn, ndevices; + unsigned int i; + + /* for MIDI and audio in and out, get the number of devices. + Then get the capabilities of each device and print its description. */ + + ndevices = midiInGetNumDevs(); + for (i = 0; i < ndevices; i++) + { + MIDIINCAPS micap; + wRtn = midiInGetDevCaps(i, (LPMIDIINCAPS) &micap, + sizeof(micap)); + if (wRtn) msw_midiinerror("midiInGetDevCaps: %s\n", wRtn); + else fprintf(stderr, + "MIDI input device #%d: %s\n", i+1, micap.szPname); + } + + ndevices = midiOutGetNumDevs(); + for (i = 0; i < ndevices; i++) + { + MIDIOUTCAPS mocap; + wRtn = midiOutGetDevCaps(i, (LPMIDIOUTCAPS) &mocap, + sizeof(mocap)); + if (wRtn) msw_midiouterror("midiOutGetDevCaps: %s\n", wRtn); + else fprintf(stderr, + "MIDI output device #%d: %s\n", i+1, mocap.szPname); + } + +} diff --git a/pd/src/s_midi_oss.c b/pd/src/s_midi_oss.c index 9233f09a..4d77e412 100644 --- a/pd/src/s_midi_oss.c +++ b/pd/src/s_midi_oss.c @@ -31,7 +31,8 @@ static void oss_midiout(int fd, int n) #define O_MIDIFLAG O_NDELAY -void sys_open_midi(int nmidiin, int *midiinvec, int nmidiout, int *midioutvec) +void sys_do_open_midi(int nmidiin, int *midiinvec, + int nmidiout, int *midioutvec) { int i; for (i = 0; i < nmidiout; i++) @@ -41,13 +42,13 @@ void sys_open_midi(int nmidiin, int *midiinvec, int nmidiout, int *midioutvec) int fd = -1, j, outdevindex = -1; char namebuf[80]; int devno = midiinvec[i]; - + for (j = 0; j < nmidiout; j++) if (midioutvec[j] == midiinvec[i]) outdevindex = j; /* try to open the device for read/write. */ - if (devno == 1 && fd < 0 && outdevindex >= 0) + if (devno == 0 && fd < 0 && outdevindex >= 0) { sys_setalarm(1000000); fd = open("/dev/midi", O_RDWR | O_MIDIFLAG); @@ -60,7 +61,7 @@ void sys_open_midi(int nmidiin, int *midiinvec, int nmidiout, int *midioutvec) if (fd < 0 && outdevindex >= 0) { sys_setalarm(1000000); - sprintf(namebuf, "/dev/midi%2.2d", devno-1); + sprintf(namebuf, "/dev/midi%2.2d", devno); fd = open(namebuf, O_RDWR | O_MIDIFLAG); if (sys_verbose) fprintf(stderr, @@ -72,7 +73,7 @@ void sys_open_midi(int nmidiin, int *midiinvec, int nmidiout, int *midioutvec) if (fd < 0 && outdevindex >= 0) { sys_setalarm(1000000); - sprintf(namebuf, "/dev/midi%d", devno-1); + sprintf(namebuf, "/dev/midi%d", devno); fd = open(namebuf, O_RDWR | O_MIDIFLAG); if (sys_verbose) fprintf(stderr, "device %d: tried %s READ/WRITE; returned %d\n", @@ -91,7 +92,7 @@ void sys_open_midi(int nmidiin, int *midiinvec, int nmidiout, int *midioutvec) if (fd < 0) { sys_setalarm(1000000); - sprintf(namebuf, "/dev/midi%2.2d", devno-1); + sprintf(namebuf, "/dev/midi%2.2d", devno); fd = open(namebuf, O_RDONLY | O_MIDIFLAG); if (sys_verbose) fprintf(stderr, "device %d: tried %s READONLY; returned %d\n", @@ -100,7 +101,7 @@ void sys_open_midi(int nmidiin, int *midiinvec, int nmidiout, int *midioutvec) if (fd < 0) { sys_setalarm(1000000); - sprintf(namebuf, "/dev/midi%d", devno-1); + sprintf(namebuf, "/dev/midi%d", devno); fd = open(namebuf, O_RDONLY | O_MIDIFLAG); if (sys_verbose) fprintf(stderr, "device %d: tried %s READONLY; returned %d\n", @@ -126,7 +127,7 @@ void sys_open_midi(int nmidiin, int *midiinvec, int nmidiout, int *midioutvec) if (fd < 0) { sys_setalarm(1000000); - sprintf(namebuf, "/dev/midi%2.2d", devno-1); + sprintf(namebuf, "/dev/midi%2.2d", devno); fd = open(namebuf, O_WRONLY | O_MIDIFLAG); if (sys_verbose) fprintf(stderr, "device %d: tried %s WRITEONLY; returned %d\n", @@ -135,7 +136,7 @@ void sys_open_midi(int nmidiin, int *midiinvec, int nmidiout, int *midioutvec) if (fd < 0) { sys_setalarm(1000000); - sprintf(namebuf, "/dev/midi%d", devno-1); + sprintf(namebuf, "/dev/midi%d", devno); fd = open(namebuf, O_WRONLY | O_MIDIFLAG); if (sys_verbose) fprintf(stderr, "device %d: tried %s WRITEONLY; returned %d\n", @@ -149,6 +150,8 @@ void sys_open_midi(int nmidiin, int *midiinvec, int nmidiout, int *midioutvec) if (oss_nmidiin < nmidiin || oss_nmidiout < nmidiout || sys_verbose) post("opened %d MIDI input device(s) and %d MIDI output device(s).", oss_nmidiin, oss_nmidiout); + + sys_setalarm(0); } #define md_msglen(x) (((x)<0xC0)?2:((x)<0xE0)?1:((x)<0xF0)?2:\ @@ -263,7 +266,94 @@ void sys_close_midi() oss_nmidiin = oss_nmidiout = 0; } -void sys_listmididevs(void) +#define NSEARCH 10 +static int oss_nmidiindevs, oss_nmidioutdevs, oss_initted; + +void midi_oss_init(void) { - /* LATER figure out how to detect MIDI devs */ + int i; + if (oss_initted) + return; + oss_initted = 1; + for (i = 0; i < NSEARCH; i++) + { + int fd; + char namebuf[80]; + + oss_nmidiindevs = i; + /* try to open the device for reading */ + if (i == 0) + { + fd = open("/dev/midi", O_RDONLY | O_NDELAY); + if (fd >= 0) + { + close(fd); + continue; + } + } + sprintf(namebuf, "/dev/midi%2.2d", i); + fd = open(namebuf, O_RDONLY | O_NDELAY); + if (fd >= 0) + { + close(fd); + continue; + } + sprintf(namebuf, "/dev/midi%d", i); + fd = open(namebuf, O_RDONLY | O_NDELAY); + if (fd >= 0) + { + close(fd); + continue; + } + break; + } + for (i = 0; i < NSEARCH; i++) + { + int fd; + char namebuf[80]; + + oss_nmidioutdevs = i; + /* try to open the device for writing */ + if (i == 0) + { + fd = open("/dev/midi", O_WRONLY | O_NDELAY); + if (fd >= 0) + { + close(fd); + continue; + } + } + sprintf(namebuf, "/dev/midi%2.2d", i); + fd = open(namebuf, O_WRONLY | O_NDELAY); + if (fd >= 0) + { + close(fd); + continue; + } + sprintf(namebuf, "/dev/midi%d", i); + fd = open(namebuf, O_WRONLY | O_NDELAY); + if (fd >= 0) + { + close(fd); + continue; + } + break; + } +} + +void midi_getdevs(char *indevlist, int *nindevs, + char *outdevlist, int *noutdevs, int maxndev, int devdescsize) +{ + int i, ndev; + if ((ndev = oss_nmidiindevs) > maxndev) + ndev = maxndev; + for (i = 0; i < ndev; i++) + sprintf(indevlist + i * devdescsize, "OSS MIDI device #%d", i+1); + *nindevs = ndev; + + if ((ndev = oss_nmidioutdevs) > maxndev) + ndev = maxndev; + for (i = 0; i < ndev; i++) + sprintf(outdevlist + i * devdescsize, "OSS MIDI device #%d", i+1); + *noutdevs = ndev; } diff --git a/pd/src/s_midi_pm.c b/pd/src/s_midi_pm.c index afd8ad1a..59959e83 100644 --- a/pd/src/s_midi_pm.c +++ b/pd/src/s_midi_pm.c @@ -28,15 +28,14 @@ static PmStream *mac_midioutdevlist[MAXMIDIOUTDEV]; static int mac_nmidiindev; static int mac_nmidioutdev; -void sys_open_midi(int nmidiin, int *midiinvec, +void sys_do_open_midi(int nmidiin, int *midiinvec, int nmidiout, int *midioutvec) { - int i = 0; + int i = 0, j, devno; int n = 0; PmError err; Pt_Start(1, 0, 0); /* start a timer with millisecond accuracy */ - mac_nmidiindev = 0; /* protect the unwary from having MIDI inputs open; they're bad news if you close Pd's terminal window. see sys_nmidiin @@ -50,62 +49,85 @@ void sys_open_midi(int nmidiin, int *midiinvec, else post("not using MIDI input (use 'pd -midiindev 1' to override)"); #endif + mac_nmidiindev = 0; for (i = 0; i < nmidiin; i++) { - if (midiinvec[i] == DEFMIDIDEV) - midiinvec[i] = Pm_GetDefaultInputDeviceID(); - err = Pm_OpenInput(&mac_midiindevlist[mac_nmidiindev], midiinvec[i], - NULL, 100, NULL, NULL, NULL); - if (err) - post("could not open midi input device number %d: %s", - midiinvec[i], Pm_GetErrorText(err)); - else + for (j = 0, devno = 0; j < Pm_CountDevices(); j++) { - if (sys_verbose) - post("Midi Input opened.\n"); - mac_nmidiindev++; - } - } + const PmDeviceInfo *info = Pm_GetDeviceInfo(j); + if (info->input) + { + if (devno == midiinvec[i]) + { + err = Pm_OpenInput(&mac_midiindevlist[mac_nmidiindev], + j, NULL, 100, NULL, NULL, NULL); + if (err) + post("could not open midi input %d (%s): %s", + j, info->name, Pm_GetErrorText(err)); + + else + { + if (sys_verbose) + post("Midi Input (%s) opened.", + info->name); + mac_nmidiindev++; + } + } + devno++; + } + } + } mac_nmidioutdev = 0; for (i = 0; i < nmidiout; i++) { - if (midioutvec[i] == DEFMIDIDEV) - midioutvec[i] = Pm_GetDefaultOutputDeviceID(); - err = Pm_OpenOutput(&mac_midioutdevlist[mac_nmidioutdev], midioutvec[i], - NULL, 0, NULL, NULL, 0); - if (err) - post("could not open midi output device number %d: %s", - midioutvec[i], Pm_GetErrorText(err)); - else + for (j = 0, devno = 0; j < Pm_CountDevices(); j++) { - if (sys_verbose) - post("Midi Output opened.\n"); - mac_nmidioutdev++; - } - } + const PmDeviceInfo *info = Pm_GetDeviceInfo(j); + if (info->output) + { + if (devno == midioutvec[i]) + { + err = Pm_OpenOutput( + &mac_midioutdevlist[mac_nmidioutdev], + j, NULL, 0, NULL, NULL, 0); + if (err) + post("could not open midi output %d (%s): %s", + j, info->name, Pm_GetErrorText(err)); + else + { + if (sys_verbose) + post("Midi Output (%s) opened.", + info->name); + mac_nmidioutdev++; + } + } + devno++; + } + } + } } void sys_close_midi( void) { int i; for (i = 0; i < mac_nmidiindev; i++) - Pm_Close(mac_midiindevlist[mac_nmidiindev]); + Pm_Close(mac_midiindevlist[i]); mac_nmidiindev = 0; for (i = 0; i < mac_nmidioutdev; i++) - Pm_Close(mac_midioutdevlist[mac_nmidioutdev]); + Pm_Close(mac_midioutdevlist[i]); mac_nmidioutdev = 0; } void sys_putmidimess(int portno, int a, int b, int c) { PmEvent buffer; - fprintf(stderr, "put 1 msg %d %d\n", portno, mac_nmidioutdev); + /* fprintf(stderr, "put 1 msg %d %d\n", portno, mac_nmidioutdev); */ if (portno >= 0 && portno < mac_nmidioutdev) { buffer.message = Pm_Message(a, b, c); buffer.timestamp = 0; - fprintf(stderr, "put msg\n"); + /* fprintf(stderr, "put msg\n"); */ Pm_Write(mac_midioutdevlist[portno], &buffer, 1); } } @@ -152,9 +174,10 @@ void sys_poll_midi(void) } } +#if 0 void sys_listmididevs(void) /* lifted from pa_devs.c in portaudio */ { - int i,j; + int i,j; for (i = 0; i < Pm_CountDevices(); i++) { const PmDeviceInfo *info = Pm_GetDeviceInfo(i); @@ -164,3 +187,28 @@ void sys_listmididevs(void) /* lifted from pa_devs.c in portaudio */ printf("\n"); } } +#endif + +void midi_getdevs(char *indevlist, int *nindevs, + char *outdevlist, int *noutdevs, int maxndev, int devdescsize) +{ + int i, nindev = 0, noutdev = 0; + for (i = 0; i < Pm_CountDevices(); i++) + { + const PmDeviceInfo *info = Pm_GetDeviceInfo(i); + /* post("%d: %s, %s (%d,%d)", i, info->interf, info->name, + info->input, info->output); */ + if (info->input && nindev < maxndev) + { + strcpy(indevlist + nindev * devdescsize, info->name); + nindev++; + } + if (info->output && noutdev < maxndev) + { + strcpy(outdevlist + noutdev * devdescsize, info->name); + noutdev++; + } + } + *nindevs = nindev; + *noutdevs = noutdev; +} diff --git a/pd/src/s_nt.c b/pd/src/s_nt.c deleted file mode 100644 index 99346e7c..00000000 --- a/pd/src/s_nt.c +++ /dev/null @@ -1,1586 +0,0 @@ -/* Copyright (c) 1997-1999 Miller Puckette. -* For information on usage and redistribution, and for a DISCLAIMER OF ALL -* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ - -/* modified 2/98 by Winfried Ritsch to deal with up to 4 synchronized -"wave" devices, which is how ADAT boards appear to the WAVE API. */ - -#include "m_imp.h" -#include - -#include - -#include - -/* ------------------------- audio -------------------------- */ - -static void nt_close_midiin(void); - -static void postflags(void); - -#define NAPORTS 16 /* wini hack for multiple ADDA devices */ -#define NT_MAXCH (2 * NAPORTS) -#define CHANNELS_PER_DEVICE 2 -#define DEFAULTCHANS 2 -#define DEFAULTSRATE 44100 -#define SAMPSIZE 2 - -#define REALDACBLKSIZE (4 * DACBLKSIZE) /* larger underlying bufsize */ - -#define MAXBUFFER 100 /* number of buffers in use at maximum advance */ -#define DEFBUFFER 30 /* default is about 30x6 = 180 msec! */ -static int nt_naudiobuffer = DEFBUFFER; -static int nt_advance_samples; - -float sys_dacsr = DEFAULTSRATE; - -static int nt_whichapi = API_MMIO; -static int nt_meters; /* true if we're metering */ -static float nt_inmax; /* max input amplitude */ -static float nt_outmax; /* max output amplitude */ -static int nt_nwavein, nt_nwaveout; /* number of WAVE devices in and out */ -static int nt_blocksize = 0; /* audio I/O block size in sample frames */ -int sys_schedadvance = 20000; /* scheduler advance in microseconds */ - -typedef struct _sbuf -{ - HANDLE hData; - HPSTR lpData; // pointer to waveform data memory - HANDLE hWaveHdr; - WAVEHDR *lpWaveHdr; // pointer to header structure -} t_sbuf; - -t_sbuf ntsnd_outvec[NAPORTS][MAXBUFFER]; /* circular buffer array */ -HWAVEOUT ntsnd_outdev[NAPORTS]; /* output device */ -static int ntsnd_outphase[NAPORTS]; /* index of next buffer to send */ - -t_sbuf ntsnd_invec[NAPORTS][MAXBUFFER]; /* circular buffer array */ -HWAVEIN ntsnd_indev[NAPORTS]; /* input device */ -static int ntsnd_inphase[NAPORTS]; /* index of next buffer to read */ -int sys_hipriority = 0; - -static void nt_waveinerror(char *s, int err) -{ - char t[256]; - waveInGetErrorText(err, t, 256); - fprintf(stderr, s, t); -} - -static void nt_waveouterror(char *s, int err) -{ - char t[256]; - waveOutGetErrorText(err, t, 256); - fprintf(stderr, s, t); -} - -static void wave_prep(t_sbuf *bp) -{ - WAVEHDR *wh; - short *sp; - int i; - /* - * Allocate and lock memory for the waveform data. The memory - * for waveform data must be globally allocated with - * GMEM_MOVEABLE and GMEM_SHARE flags. - */ - - if (!(bp->hData = - GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, - (DWORD) (CHANNELS_PER_DEVICE * REALDACBLKSIZE * SAMPSIZE)))) - printf("alloc 1 failed\n"); - - if (!(bp->lpData = - (HPSTR) GlobalLock(bp->hData))) - printf("lock 1 failed\n"); - - /* Allocate and lock memory for the header. */ - - if (!(bp->hWaveHdr = - GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, (DWORD) sizeof(WAVEHDR)))) - printf("alloc 2 failed\n"); - - if (!(wh = bp->lpWaveHdr = - (WAVEHDR *) GlobalLock(bp->hWaveHdr))) - printf("lock 2 failed\n"); - - for (i = CHANNELS_PER_DEVICE * REALDACBLKSIZE, - sp = (short *)bp->lpData; i--; ) - *sp++ = 0; - - wh->lpData = bp->lpData; - wh->dwBufferLength = (CHANNELS_PER_DEVICE * REALDACBLKSIZE * SAMPSIZE); - wh->dwFlags = 0; - wh->dwLoops = 0L; - wh->lpNext = 0; - wh->reserved = 0; -} - -static int nt_inalloc[NAPORTS], nt_outalloc[NAPORTS]; -static UINT nt_whichdac = WAVE_MAPPER, nt_whichadc = WAVE_MAPPER; - -int mmio_open_audio(void) -{ - PCMWAVEFORMAT form; - int i; - UINT mmresult; - int nad, nda; - - if (sys_verbose) - post("%d devices in, %d devices out", - nt_nwavein, nt_nwaveout); - - form.wf.wFormatTag = WAVE_FORMAT_PCM; - form.wf.nChannels = CHANNELS_PER_DEVICE; - form.wf.nSamplesPerSec = sys_dacsr; - form.wf.nAvgBytesPerSec = sys_dacsr * (CHANNELS_PER_DEVICE * SAMPSIZE); - form.wf.nBlockAlign = CHANNELS_PER_DEVICE * SAMPSIZE; - form.wBitsPerSample = 8 * SAMPSIZE; - - for (nad=0; nad < nt_nwavein; nad++) - { - /* Open waveform device(s), sucessively numbered, for input */ - - mmresult = waveInOpen(&ntsnd_indev[nad], nt_whichadc+nad, - (WAVEFORMATEX *)(&form), 0L, 0L, CALLBACK_NULL); - - if (sys_verbose) - printf("opened adc device %d with return %d\n", - nt_whichadc+nad,mmresult); - - if (mmresult != MMSYSERR_NOERROR) - { - nt_waveinerror("waveInOpen: %s\n", mmresult); - nt_nwavein = nad; /* nt_nwavein = 0 wini */ - } - else - { - if (!nt_inalloc[nad]) - { - for (i = 0; i < nt_naudiobuffer; i++) - wave_prep(&ntsnd_invec[nad][i]); - nt_inalloc[nad] = 1; - } - for (i = 0; i < nt_naudiobuffer; i++) - { - mmresult = waveInPrepareHeader(ntsnd_indev[nad], - ntsnd_invec[nad][i].lpWaveHdr, sizeof(WAVEHDR)); - if (mmresult != MMSYSERR_NOERROR) - nt_waveinerror("waveinprepareheader: %s\n", mmresult); - mmresult = waveInAddBuffer(ntsnd_indev[nad], - ntsnd_invec[nad][i].lpWaveHdr, sizeof(WAVEHDR)); - if (mmresult != MMSYSERR_NOERROR) - nt_waveinerror("waveInAddBuffer: %s\n", mmresult); - } - } - } - /* quickly start them all together */ - for(nad=0; nad < nt_nwavein; nad++) - waveInStart(ntsnd_indev[nad]); - - for(nda=0; nda < nt_nwaveout; nda++) - { - - /* Open a waveform device for output in sucessiv device numbering*/ - mmresult = waveOutOpen(&ntsnd_outdev[nda], nt_whichdac + nda, - (WAVEFORMATEX *)(&form), 0L, 0L, CALLBACK_NULL); - - if (sys_verbose) - fprintf(stderr,"opened dac device %d, with return %d\n", - nt_whichdac +nda, mmresult); - - if (mmresult != MMSYSERR_NOERROR) - { - fprintf(stderr,"Wave out open device %d + %d\n",nt_whichdac,nda); - nt_waveouterror("waveOutOpen device: %s\n", mmresult); - nt_nwaveout = nda; - } - else - { - if (!(nt_outalloc[nda])) - { - for (i = 0; i < nt_naudiobuffer; i++) - { - wave_prep(&ntsnd_outvec[nda][i]); - /* set DONE flag as if we had queued them */ - ntsnd_outvec[nda][i].lpWaveHdr->dwFlags = WHDR_DONE; - } - nt_outalloc[nda] = 1; - } - } - } - - return (0); -} - -void mmio_close_audio( void) -{ - int errcode; - int nda, nad; - if (sys_verbose) - post("closing audio..."); - - for (nda=0; nda < nt_nwaveout; nda++) /*if (nt_nwaveout) wini */ - { - errcode = waveOutReset(ntsnd_outdev[nda]); - if (errcode != MMSYSERR_NOERROR) - printf("error resetting output %d: %d\n", nda, errcode); - errcode = waveOutClose(ntsnd_outdev[nda]); - if (errcode != MMSYSERR_NOERROR) - printf("error closing output %d: %d\n",nda , errcode); - } - nt_nwaveout = 0; - - for(nad=0; nad < nt_nwavein;nad++) /* if (nt_nwavein) wini */ - { - errcode = waveInReset(ntsnd_indev[nad]); - if (errcode != MMSYSERR_NOERROR) - printf("error resetting input: %d\n", errcode); - errcode = waveInClose(ntsnd_indev[nad]); - if (errcode != MMSYSERR_NOERROR) - printf("error closing input: %d\n", errcode); - } - nt_nwavein = 0; -} - - -#define ADCJITTER 10 /* We tolerate X buffers of jitter by default */ -#define DACJITTER 10 - -static int nt_adcjitterbufsallowed = ADCJITTER; -static int nt_dacjitterbufsallowed = DACJITTER; - - /* ------------- MIDI time stamping from audio clock ------------ */ - -#ifdef MIDI_TIMESTAMP - -static double nt_hibuftime; -static double initsystime = -1; - - /* call this whenever we reset audio */ -static void nt_resetmidisync(void) -{ - initsystime = clock_getsystime(); - nt_hibuftime = sys_getrealtime(); -} - - /* call this whenever we're idled waiting for audio to be ready. - The routine maintains a high and low water point for the difference - between real and DAC time. */ - -static void nt_midisync(void) -{ - double jittersec, diff; - - if (initsystime == -1) nt_resetmidisync(); - jittersec = (nt_dacjitterbufsallowed > nt_adcjitterbufsallowed ? - nt_dacjitterbufsallowed : nt_adcjitterbufsallowed) - * REALDACBLKSIZE / sys_getsr(); - diff = sys_getrealtime() - 0.001 * clock_gettimesince(initsystime); - if (diff > nt_hibuftime) nt_hibuftime = diff; - if (diff < nt_hibuftime - jittersec) - { - post("jitter excess %d %f", dac, diff); - nt_resetmidisync(); - } -} - -static double nt_midigettimefor(LARGE_INTEGER timestamp) -{ - /* this is broken now... used to work when "timestamp" was derived from - QueryPerformanceCounter() instead of the gates approved - timeGetSystemTime() call in the MIDI callback routine below. */ - return (nt_tixtotime(timestamp) - nt_hibuftime); -} -#endif /* MIDI_TIMESTAMP */ - - -static int nt_fill = 0; -#define WRAPFWD(x) ((x) >= nt_naudiobuffer ? (x) - nt_naudiobuffer: (x)) -#define WRAPBACK(x) ((x) < 0 ? (x) + nt_naudiobuffer: (x)) -#define MAXRESYNC 500 - -#if 0 /* this is used for debugging */ -static void nt_printaudiostatus(void) -{ - int nad, nda; - for (nad = 0; nad < nt_nwavein; nad++) - { - int phase = ntsnd_inphase[nad]; - int phase2 = phase, phase3 = WRAPFWD(phase2), count, ntrans = 0; - int firstphasedone = -1, firstphasebusy = -1; - for (count = 0; count < nt_naudiobuffer; count++) - { - int donethis = - (ntsnd_invec[nad][phase2].lpWaveHdr->dwFlags & WHDR_DONE); - int donenext = - (ntsnd_invec[nad][phase3].lpWaveHdr->dwFlags & WHDR_DONE); - if (donethis && !donenext) - { - if (firstphasebusy >= 0) goto multipleadc; - firstphasebusy = count; - } - if (!donethis && donenext) - { - if (firstphasedone >= 0) goto multipleadc; - firstphasedone = count; - } - phase2 = phase3; - phase3 = WRAPFWD(phase2 + 1); - } - post("nad %d phase %d busy %d done %d", nad, phase, firstphasebusy, - firstphasedone); - continue; - multipleadc: - startpost("nad %d phase %d: oops:", nad, phase); - for (count = 0; count < nt_naudiobuffer; count++) - { - char buf[80]; - sprintf(buf, " %d", - (ntsnd_invec[nad][count].lpWaveHdr->dwFlags & WHDR_DONE)); - poststring(buf); - } - endpost(); - } - for (nda = 0; nda < nt_nwaveout; nda++) - { - int phase = ntsnd_outphase[nad]; - int phase2 = phase, phase3 = WRAPFWD(phase2), count, ntrans = 0; - int firstphasedone = -1, firstphasebusy = -1; - for (count = 0; count < nt_naudiobuffer; count++) - { - int donethis = - (ntsnd_outvec[nda][phase2].lpWaveHdr->dwFlags & WHDR_DONE); - int donenext = - (ntsnd_outvec[nda][phase3].lpWaveHdr->dwFlags & WHDR_DONE); - if (donethis && !donenext) - { - if (firstphasebusy >= 0) goto multipledac; - firstphasebusy = count; - } - if (!donethis && donenext) - { - if (firstphasedone >= 0) goto multipledac; - firstphasedone = count; - } - phase2 = phase3; - phase3 = WRAPFWD(phase2 + 1); - } - if (firstphasebusy < 0) post("nda %d phase %d all %d", - nda, phase, (ntsnd_outvec[nad][0].lpWaveHdr->dwFlags & WHDR_DONE)); - else post("nda %d phase %d busy %d done %d", nda, phase, firstphasebusy, - firstphasedone); - continue; - multipledac: - startpost("nda %d phase %d: oops:", nda, phase); - for (count = 0; count < nt_naudiobuffer; count++) - { - char buf[80]; - sprintf(buf, " %d", - (ntsnd_outvec[nad][count].lpWaveHdr->dwFlags & WHDR_DONE)); - poststring(buf); - } - endpost(); - } -} -#endif /* 0 */ - -/* this is a hack to avoid ever resyncing audio pointers in case for whatever -reason the sync testing below gives false positives. */ - -static int nt_resync_cancelled; - -void nt_noresync( void) -{ - nt_resync_cancelled = 1; -} - -static void nt_resyncaudio(void) -{ - UINT mmresult; - int nad, nda, count; - if (nt_resync_cancelled) - return; - /* for each open input device, eat all buffers which are marked - ready. The next one will thus be "busy". */ - post("resyncing audio"); - for (nad = 0; nad < nt_nwavein; nad++) - { - int phase = ntsnd_inphase[nad]; - for (count = 0; count < MAXRESYNC; count++) - { - WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr; - if (!(inwavehdr->dwFlags & WHDR_DONE)) break; - if (inwavehdr->dwFlags & WHDR_PREPARED) - waveInUnprepareHeader(ntsnd_indev[nad], - inwavehdr, sizeof(WAVEHDR)); - inwavehdr->dwFlags = 0L; - waveInPrepareHeader(ntsnd_indev[nad], inwavehdr, sizeof(WAVEHDR)); - mmresult = waveInAddBuffer(ntsnd_indev[nad], inwavehdr, - sizeof(WAVEHDR)); - if (mmresult != MMSYSERR_NOERROR) - nt_waveinerror("waveInAddBuffer: %s\n", mmresult); - ntsnd_inphase[nad] = phase = WRAPFWD(phase + 1); - } - if (count == MAXRESYNC) post("resync error 1"); - } - /* Each output buffer which is "ready" is filled with zeros and - queued. */ - for (nda = 0; nda < nt_nwaveout; nda++) - { - int phase = ntsnd_outphase[nda]; - for (count = 0; count < MAXRESYNC; count++) - { - WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr; - if (!(outwavehdr->dwFlags & WHDR_DONE)) break; - if (outwavehdr->dwFlags & WHDR_PREPARED) - waveOutUnprepareHeader(ntsnd_outdev[nda], - outwavehdr, sizeof(WAVEHDR)); - outwavehdr->dwFlags = 0L; - memset((char *)(ntsnd_outvec[nda][phase].lpData), - 0, (CHANNELS_PER_DEVICE * REALDACBLKSIZE * SAMPSIZE)); - waveOutPrepareHeader(ntsnd_outdev[nda], outwavehdr, - sizeof(WAVEHDR)); - mmresult = waveOutWrite(ntsnd_outdev[nda], outwavehdr, - sizeof(WAVEHDR)); - if (mmresult != MMSYSERR_NOERROR) - nt_waveouterror("waveOutAddBuffer: %s\n", mmresult); - ntsnd_outphase[nda] = phase = WRAPFWD(phase + 1); - } - if (count == MAXRESYNC) post("resync error 2"); - } - -#ifdef MIDI_TIMESTAMP - nt_resetmidisync(); -#endif - -} - -#define LATE 0 -#define RESYNC 1 -#define NOTHING 2 -static int nt_errorcount; -static int nt_resynccount; -static double nt_nextreporttime = -1; - -void nt_logerror(int which) -{ -#if 0 - post("error %d %d", count, which); - if (which < NOTHING) nt_errorcount++; - if (which == RESYNC) nt_resynccount++; - if (sys_getrealtime() > nt_nextreporttime) - { - post("%d audio I/O error%s", nt_errorcount, - (nt_errorcount > 1 ? "s" : "")); - if (nt_resynccount) post("DAC/ADC sync error"); - nt_errorcount = nt_resynccount = 0; - nt_nextreporttime = sys_getrealtime() - 5; - } -#endif -} - -/* system buffer with t_sample types for one tick */ -t_sample *sys_soundout; -t_sample *sys_soundin; -float sys_dacsr; - -int mmio_send_dacs(void) -{ - HMMIO hmmio; - UINT mmresult; - HANDLE hFormat; - int i, j; - short *sp1, *sp2; - float *fp1, *fp2; - int nextfill, doxfer = 0; - int nda, nad; - if (!nt_nwavein && !nt_nwaveout) return (0); - - - if (nt_meters) - { - int i, n; - float maxsamp; - for (i = 0, n = 2 * nt_nwavein * DACBLKSIZE, maxsamp = nt_inmax; - i < n; i++) - { - float f = sys_soundin[i]; - if (f > maxsamp) maxsamp = f; - else if (-f > maxsamp) maxsamp = -f; - } - nt_inmax = maxsamp; - for (i = 0, n = 2 * nt_nwaveout * DACBLKSIZE, maxsamp = nt_outmax; - i < n; i++) - { - float f = sys_soundout[i]; - if (f > maxsamp) maxsamp = f; - else if (-f > maxsamp) maxsamp = -f; - } - nt_outmax = maxsamp; - } - - /* the "fill pointer" nt_fill controls where in the next - I/O buffers we will write and/or read. If it's zero, we - first check whether the buffers are marked "done". */ - - if (!nt_fill) - { - for (nad = 0; nad < nt_nwavein; nad++) - { - int phase = ntsnd_inphase[nad]; - WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr; - if (!(inwavehdr->dwFlags & WHDR_DONE)) goto idle; - } - for (nda = 0; nda < nt_nwaveout; nda++) - { - int phase = ntsnd_outphase[nda]; - WAVEHDR *outwavehdr = - ntsnd_outvec[nda][phase].lpWaveHdr; - if (!(outwavehdr->dwFlags & WHDR_DONE)) goto idle; - } - for (nad = 0; nad < nt_nwavein; nad++) - { - int phase = ntsnd_inphase[nad]; - WAVEHDR *inwavehdr = - ntsnd_invec[nad][phase].lpWaveHdr; - if (inwavehdr->dwFlags & WHDR_PREPARED) - waveInUnprepareHeader(ntsnd_indev[nad], - inwavehdr, sizeof(WAVEHDR)); - } - for (nda = 0; nda < nt_nwaveout; nda++) - { - int phase = ntsnd_outphase[nda]; - WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr; - if (outwavehdr->dwFlags & WHDR_PREPARED) - waveOutUnprepareHeader(ntsnd_outdev[nda], - outwavehdr, sizeof(WAVEHDR)); - } - } - - /* Convert audio output to fixed-point and put it in the output - buffer. */ - for (nda = 0, fp1 = sys_soundout; nda < nt_nwaveout; nda++) - { - int phase = ntsnd_outphase[nda]; - - for (i = 0, sp1 = (short *)(ntsnd_outvec[nda][phase].lpData) + - CHANNELS_PER_DEVICE * nt_fill; - i < 2; i++, fp1 += DACBLKSIZE, sp1++) - { - for (j = 0, fp2 = fp1, sp2 = sp1; j < DACBLKSIZE; - j++, fp2++, sp2 += CHANNELS_PER_DEVICE) - { - int x1 = 32767.f * *fp2; - if (x1 > 32767) x1 = 32767; - else if (x1 < -32767) x1 = -32767; - *sp2 = x1; - } - } - } - memset(sys_soundout, 0, - (DACBLKSIZE*sizeof(t_sample)*CHANNELS_PER_DEVICE)*nt_nwaveout); - - /* vice versa for the input buffer */ - - for (nad = 0, fp1 = sys_soundin; nad < nt_nwavein; nad++) - { - int phase = ntsnd_inphase[nad]; - - for (i = 0, sp1 = (short *)(ntsnd_invec[nad][phase].lpData) + - CHANNELS_PER_DEVICE * nt_fill; - i < 2; i++, fp1 += DACBLKSIZE, sp1++) - { - for (j = 0, fp2 = fp1, sp2 = sp1; j < DACBLKSIZE; - j++, fp2++, sp2 += CHANNELS_PER_DEVICE) - { - *fp2 = ((float)(1./32767.)) * (float)(*sp2); - } - } - } - - nt_fill = nt_fill + DACBLKSIZE; - if (nt_fill == REALDACBLKSIZE) - { - nt_fill = 0; - - for (nad = 0; nad < nt_nwavein; nad++) - { - int phase = ntsnd_inphase[nad]; - HWAVEIN device = ntsnd_indev[nad]; - WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr; - waveInPrepareHeader(device, inwavehdr, sizeof(WAVEHDR)); - mmresult = waveInAddBuffer(device, inwavehdr, sizeof(WAVEHDR)); - if (mmresult != MMSYSERR_NOERROR) - nt_waveinerror("waveInAddBuffer: %s\n", mmresult); - ntsnd_inphase[nad] = WRAPFWD(phase + 1); - } - for (nda = 0; nda < nt_nwaveout; nda++) - { - int phase = ntsnd_outphase[nda]; - HWAVEOUT device = ntsnd_outdev[nda]; - WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr; - waveOutPrepareHeader(device, outwavehdr, sizeof(WAVEHDR)); - mmresult = waveOutWrite(device, outwavehdr, sizeof(WAVEHDR)); - if (mmresult != MMSYSERR_NOERROR) - nt_waveouterror("waveOutWrite: %s\n", mmresult); - ntsnd_outphase[nda] = WRAPFWD(phase + 1); - } - - /* check for DAC underflow or ADC overflow. */ - for (nad = 0; nad < nt_nwavein; nad++) - { - int phase = WRAPBACK(ntsnd_inphase[nad] - 2); - WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr; - if (inwavehdr->dwFlags & WHDR_DONE) goto late; - } - for (nda = 0; nda < nt_nwaveout; nda++) - { - int phase = WRAPBACK(ntsnd_outphase[nda] - 2); - WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr; - if (outwavehdr->dwFlags & WHDR_DONE) goto late; - } - } - return (1); - -late: - - nt_logerror(LATE); - nt_resyncaudio(); - return (1); - -idle: - - /* If more than nt_adcjitterbufsallowed ADC buffers are ready - on any input device, resynchronize */ - - for (nad = 0; nad < nt_nwavein; nad++) - { - int phase = ntsnd_inphase[nad]; - WAVEHDR *inwavehdr = - ntsnd_invec[nad] - [WRAPFWD(phase + nt_adcjitterbufsallowed)].lpWaveHdr; - if (inwavehdr->dwFlags & WHDR_DONE) - { - nt_resyncaudio(); - return (0); - } - } - - /* test dac sync the same way */ - for (nda = 0; nda < nt_nwaveout; nda++) - { - int phase = ntsnd_outphase[nda]; - WAVEHDR *outwavehdr = - ntsnd_outvec[nda] - [WRAPFWD(phase + nt_dacjitterbufsallowed)].lpWaveHdr; - if (outwavehdr->dwFlags & WHDR_DONE) - { - nt_resyncaudio(); - return (0); - } - } -#ifdef MIDI_TIMESTAMP - nt_midisync(); -#endif - return (0); -} - - -static void nt_setchsr(int inchannels, int outchannels, int sr) -{ - int inbytes = inchannels * (DACBLKSIZE*sizeof(float)); - int outbytes = outchannels * (DACBLKSIZE*sizeof(float)); - - if (nt_nwavein) - free(sys_soundin); - if (nt_nwaveout) - free(sys_soundout); - - nt_nwavein = inchannels/CHANNELS_PER_DEVICE; - nt_nwaveout = outchannels/CHANNELS_PER_DEVICE; - sys_dacsr = sr; - - sys_soundin = (t_float *)malloc(inbytes); - memset(sys_soundin, 0, inbytes); - - sys_soundout = (t_float *)malloc(outbytes); - memset(sys_soundout, 0, outbytes); - - nt_advance_samples = (sys_schedadvance * sys_dacsr) / (1000000.); - if (nt_advance_samples < 3 * DACBLKSIZE) - nt_advance_samples = 3 * DACBLKSIZE; -} - -/* ------------------------- MIDI output -------------------------- */ -static void nt_midiouterror(char *s, int err) -{ - char t[256]; - midiOutGetErrorText(err, t, 256); - fprintf(stderr, s, t); -} - -static HMIDIOUT hMidiOut[MAXMIDIOUTDEV]; /* output device */ -static int nt_nmidiout; /* number of devices */ - -static void nt_open_midiout(int nmidiout, int *midioutvec) -{ - UINT result, wRtn; - int i; - int dev; - MIDIOUTCAPS midioutcaps; - if (nmidiout > MAXMIDIOUTDEV) - nmidiout = MAXMIDIOUTDEV; - - dev = 0; - - for (i = 0; i < nmidiout; i++) - { - MIDIOUTCAPS mocap; - result = midiOutOpen(&hMidiOut[dev], midioutvec[i]-1, 0, 0, - CALLBACK_NULL); - wRtn = midiOutGetDevCaps(i, (LPMIDIOUTCAPS) &mocap, - sizeof(mocap)); - if (result != MMSYSERR_NOERROR) - { - fprintf(stderr,"midiOutOpen: %s\n",midioutcaps.szPname); - nt_midiouterror("midiOutOpen: %s\n", result); - } - else - { - if (sys_verbose) - fprintf(stderr,"midiOutOpen: Open %s as Port %d\n", - midioutcaps.szPname, dev); - dev++; - } - } - nt_nmidiout = dev; -} - -void sys_putmidimess(int portno, int a, int b, int c) -{ - DWORD foo; - MMRESULT res; - if (portno >= 0 && portno < nt_nmidiout) - { - foo = (a & 0xff) | ((b & 0xff) << 8) | ((c & 0xff) << 16); - res = midiOutShortMsg(hMidiOut[portno], foo); - if (res != MMSYSERR_NOERROR) - post("MIDI out error %d", res); - } -} - -void sys_putmidibyte(int portno, int byte) -{ - MMRESULT res; - if (portno >= 0 && portno < nt_nmidiout) - { - res = midiOutShortMsg(hMidiOut[portno], byte); - if (res != MMSYSERR_NOERROR) - post("MIDI out error %d", res); - } -} - -static void nt_close_midiout(void) -{ - int i; - for (i = 0; i < nt_nmidiout; i++) - { - midiOutReset(hMidiOut[i]); - midiOutClose(hMidiOut[i]); - } - nt_nmidiout = 0; -} - -/* -------------------------- MIDI input ---------------------------- */ - -#define INPUT_BUFFER_SIZE 1000 // size of input buffer in events - -static void nt_midiinerror(char *s, int err) -{ - char t[256]; - midiInGetErrorText(err, t, 256); - fprintf(stderr, s, t); -} - - -/* Structure to represent a single MIDI event. - */ - -#define EVNT_F_ERROR 0x00000001L - -typedef struct event_tag -{ - DWORD fdwEvent; - DWORD dwDevice; - LARGE_INTEGER timestamp; - DWORD data; -} EVENT; -typedef EVENT FAR *LPEVENT; - -/* Structure to manage the circular input buffer. - */ -typedef struct circularBuffer_tag -{ - HANDLE hSelf; /* handle to this structure */ - HANDLE hBuffer; /* buffer handle */ - WORD wError; /* error flags */ - DWORD dwSize; /* buffer size (in EVENTS) */ - DWORD dwCount; /* byte count (in EVENTS) */ - LPEVENT lpStart; /* ptr to start of buffer */ - LPEVENT lpEnd; /* ptr to end of buffer (last byte + 1) */ - LPEVENT lpHead; /* ptr to head (next location to fill) */ - LPEVENT lpTail; /* ptr to tail (next location to empty) */ -} CIRCULARBUFFER; -typedef CIRCULARBUFFER FAR *LPCIRCULARBUFFER; - - -/* Structure to pass instance data from the application - to the low-level callback function. - */ -typedef struct callbackInstance_tag -{ - HANDLE hSelf; - DWORD dwDevice; - LPCIRCULARBUFFER lpBuf; -} CALLBACKINSTANCEDATA; -typedef CALLBACKINSTANCEDATA FAR *LPCALLBACKINSTANCEDATA; - -/* Function prototypes - */ -LPCALLBACKINSTANCEDATA FAR PASCAL AllocCallbackInstanceData(void); -void FAR PASCAL FreeCallbackInstanceData(LPCALLBACKINSTANCEDATA lpBuf); - -LPCIRCULARBUFFER AllocCircularBuffer(DWORD dwSize); -void FreeCircularBuffer(LPCIRCULARBUFFER lpBuf); -WORD FAR PASCAL GetEvent(LPCIRCULARBUFFER lpBuf, LPEVENT lpEvent); - -// Callback instance data pointers -LPCALLBACKINSTANCEDATA lpCallbackInstanceData[MAXMIDIINDEV]; - -UINT wNumDevices = 0; // Number of MIDI input devices opened -BOOL bRecordingEnabled = 1; // Enable/disable recording flag -int nNumBufferLines = 0; // Number of lines in display buffer -RECT rectScrollClip; // Clipping rectangle for scrolling - -LPCIRCULARBUFFER lpInputBuffer; // Input buffer structure -EVENT incomingEvent; // Incoming MIDI event structure - -MIDIINCAPS midiInCaps[MAXMIDIINDEV]; // Device capabilities structures -HMIDIIN hMidiIn[MAXMIDIINDEV]; // MIDI input device handles - - -/* AllocCallbackInstanceData - Allocates a CALLBACKINSTANCEDATA - * structure. This structure is used to pass information to the - * low-level callback function, each time it receives a message. - * - * Because this structure is accessed by the low-level callback - * function, it must be allocated using GlobalAlloc() with the - * GMEM_SHARE and GMEM_MOVEABLE flags and page-locked with - * GlobalPageLock(). - * - * Params: void - * - * Return: A pointer to the allocated CALLBACKINSTANCE data structure. - */ -LPCALLBACKINSTANCEDATA FAR PASCAL AllocCallbackInstanceData(void) -{ - HANDLE hMem; - LPCALLBACKINSTANCEDATA lpBuf; - - /* Allocate and lock global memory. - */ - hMem = GlobalAlloc(GMEM_SHARE | GMEM_MOVEABLE, - (DWORD)sizeof(CALLBACKINSTANCEDATA)); - if(hMem == NULL) - return NULL; - - lpBuf = (LPCALLBACKINSTANCEDATA)GlobalLock(hMem); - if(lpBuf == NULL){ - GlobalFree(hMem); - return NULL; - } - - /* Page lock the memory. - */ - //GlobalPageLock((HGLOBAL)HIWORD(lpBuf)); - - /* Save the handle. - */ - lpBuf->hSelf = hMem; - - return lpBuf; -} - -/* FreeCallbackInstanceData - Frees the given CALLBACKINSTANCEDATA structure. - * - * Params: lpBuf - Points to the CALLBACKINSTANCEDATA structure to be freed. - * - * Return: void - */ -void FAR PASCAL FreeCallbackInstanceData(LPCALLBACKINSTANCEDATA lpBuf) -{ - HANDLE hMem; - - /* Save the handle until we're through here. - */ - hMem = lpBuf->hSelf; - - /* Free the structure. - */ - //GlobalPageUnlock((HGLOBAL)HIWORD(lpBuf)); - GlobalUnlock(hMem); - GlobalFree(hMem); -} - - -/* - * AllocCircularBuffer - Allocates memory for a CIRCULARBUFFER structure - * and a buffer of the specified size. Each memory block is allocated - * with GlobalAlloc() using GMEM_SHARE and GMEM_MOVEABLE flags, locked - * with GlobalLock(), and page-locked with GlobalPageLock(). - * - * Params: dwSize - The size of the buffer, in events. - * - * Return: A pointer to a CIRCULARBUFFER structure identifying the - * allocated display buffer. NULL if the buffer could not be allocated. - */ - - -LPCIRCULARBUFFER AllocCircularBuffer(DWORD dwSize) -{ - HANDLE hMem; - LPCIRCULARBUFFER lpBuf; - LPEVENT lpMem; - - /* Allocate and lock a CIRCULARBUFFER structure. - */ - hMem = GlobalAlloc(GMEM_SHARE | GMEM_MOVEABLE, - (DWORD)sizeof(CIRCULARBUFFER)); - if(hMem == NULL) - return NULL; - - lpBuf = (LPCIRCULARBUFFER)GlobalLock(hMem); - if(lpBuf == NULL) - { - GlobalFree(hMem); - return NULL; - } - - /* Page lock the memory. Global memory blocks accessed by - * low-level callback functions must be page locked. - */ -#ifndef _WIN32 - GlobalSmartPageLock((HGLOBAL)HIWORD(lpBuf)); -#endif - - /* Save the memory handle. - */ - lpBuf->hSelf = hMem; - - /* Allocate and lock memory for the actual buffer. - */ - hMem = GlobalAlloc(GMEM_SHARE | GMEM_MOVEABLE, dwSize * sizeof(EVENT)); - if(hMem == NULL) - { -#ifndef _WIN32 - GlobalSmartPageUnlock((HGLOBAL)HIWORD(lpBuf)); -#endif - GlobalUnlock(lpBuf->hSelf); - GlobalFree(lpBuf->hSelf); - return NULL; - } - - lpMem = (LPEVENT)GlobalLock(hMem); - if(lpMem == NULL) - { - GlobalFree(hMem); -#ifndef _WIN32 - GlobalSmartPageUnlock((HGLOBAL)HIWORD(lpBuf)); -#endif - GlobalUnlock(lpBuf->hSelf); - GlobalFree(lpBuf->hSelf); - return NULL; - } - - /* Page lock the memory. Global memory blocks accessed by - * low-level callback functions must be page locked. - */ -#ifndef _WIN32 - GlobalSmartPageLock((HGLOBAL)HIWORD(lpMem)); -#endif - - /* Set up the CIRCULARBUFFER structure. - */ - lpBuf->hBuffer = hMem; - lpBuf->wError = 0; - lpBuf->dwSize = dwSize; - lpBuf->dwCount = 0L; - lpBuf->lpStart = lpMem; - lpBuf->lpEnd = lpMem + dwSize; - lpBuf->lpTail = lpMem; - lpBuf->lpHead = lpMem; - - return lpBuf; -} - -/* FreeCircularBuffer - Frees the memory for the given CIRCULARBUFFER - * structure and the memory for the buffer it references. - * - * Params: lpBuf - Points to the CIRCULARBUFFER to be freed. - * - * Return: void - */ -void FreeCircularBuffer(LPCIRCULARBUFFER lpBuf) -{ - HANDLE hMem; - - /* Free the buffer itself. - */ -#ifndef _WIN32 - GlobalSmartPageUnlock((HGLOBAL)HIWORD(lpBuf->lpStart)); -#endif - GlobalUnlock(lpBuf->hBuffer); - GlobalFree(lpBuf->hBuffer); - - /* Free the CIRCULARBUFFER structure. - */ - hMem = lpBuf->hSelf; -#ifndef _WIN32 - GlobalSmartPageUnlock((HGLOBAL)HIWORD(lpBuf)); -#endif - GlobalUnlock(hMem); - GlobalFree(hMem); -} - -/* GetEvent - Gets a MIDI event from the circular input buffer. Events - * are removed from the buffer. The corresponding PutEvent() function - * is called by the low-level callback function, so it must reside in - * the callback DLL. PutEvent() is defined in the CALLBACK.C module. - * - * Params: lpBuf - Points to the circular buffer. - * lpEvent - Points to an EVENT structure that is filled with the - * retrieved event. - * - * Return: Returns non-zero if successful, zero if there are no - * events to get. - */ -WORD FAR PASCAL GetEvent(LPCIRCULARBUFFER lpBuf, LPEVENT lpEvent) -{ - /* If no event available, return */ - if (!wNumDevices || lpBuf->dwCount <= 0) return (0); - - /* Get the event. - */ - *lpEvent = *lpBuf->lpTail; - - /* Decrement the byte count, bump the tail pointer. - */ - --lpBuf->dwCount; - ++lpBuf->lpTail; - - /* Wrap the tail pointer, if necessary. - */ - if(lpBuf->lpTail >= lpBuf->lpEnd) - lpBuf->lpTail = lpBuf->lpStart; - - return 1; -} - -/* PutEvent - Puts an EVENT in a CIRCULARBUFFER. If the buffer is full, - * it sets the wError element of the CIRCULARBUFFER structure - * to be non-zero. - * - * Params: lpBuf - Points to the CIRCULARBUFFER. - * lpEvent - Points to the EVENT. - * - * Return: void -*/ - -void FAR PASCAL PutEvent(LPCIRCULARBUFFER lpBuf, LPEVENT lpEvent) -{ - /* If the buffer is full, set an error and return. - */ - if(lpBuf->dwCount >= lpBuf->dwSize){ - lpBuf->wError = 1; - return; - } - - /* Put the event in the buffer, bump the head pointer and the byte count. - */ - *lpBuf->lpHead = *lpEvent; - - ++lpBuf->lpHead; - ++lpBuf->dwCount; - - /* Wrap the head pointer, if necessary. - */ - if(lpBuf->lpHead >= lpBuf->lpEnd) - lpBuf->lpHead = lpBuf->lpStart; -} - -/* midiInputHandler - Low-level callback function to handle MIDI input. - * Installed by midiInOpen(). The input handler takes incoming - * MIDI events and places them in the circular input buffer. It then - * notifies the application by posting a MM_MIDIINPUT message. - * - * This function is accessed at interrupt time, so it should be as - * fast and efficient as possible. You can't make any - * Windows calls here, except PostMessage(). The only Multimedia - * Windows call you can make are timeGetSystemTime(), midiOutShortMsg(). - * - * - * Param: hMidiIn - Handle for the associated input device. - * wMsg - One of the MIM_***** messages. - * dwInstance - Points to CALLBACKINSTANCEDATA structure. - * dwParam1 - MIDI data. - * dwParam2 - Timestamp (in milliseconds) - * - * Return: void - */ -void FAR PASCAL midiInputHandler( -HMIDIIN hMidiIn, -WORD wMsg, -DWORD dwInstance, -DWORD dwParam1, -DWORD dwParam2) -{ - EVENT event; - - switch(wMsg) - { - case MIM_OPEN: - break; - - /* The only error possible is invalid MIDI data, so just pass - * the invalid data on so we'll see it. - */ - case MIM_ERROR: - case MIM_DATA: - event.fdwEvent = (wMsg == MIM_ERROR) ? EVNT_F_ERROR : 0; - event.dwDevice = ((LPCALLBACKINSTANCEDATA)dwInstance)->dwDevice; - event.data = dwParam1; -#ifdef MIDI_TIMESTAMP - event.timestamp = timeGetSystemTime(); -#endif - /* Put the MIDI event in the circular input buffer. - */ - - PutEvent(((LPCALLBACKINSTANCEDATA)dwInstance)->lpBuf, - (LPEVENT) &event); - - break; - - default: - break; - } -} - -void nt_open_midiin(int nmidiin, int *midiinvec) -{ - UINT wRtn; - char szErrorText[256]; - unsigned int i; - unsigned int ndev = 0; - /* Allocate a circular buffer for low-level MIDI input. This buffer - * is filled by the low-level callback function and emptied by the - * application. - */ - lpInputBuffer = AllocCircularBuffer((DWORD)(INPUT_BUFFER_SIZE)); - if (lpInputBuffer == NULL) - { - printf("Not enough memory available for input buffer.\n"); - return; - } - - /* Open all MIDI input devices after allocating and setting up - * instance data for each device. The instance data is used to - * pass buffer management information between the application and - * the low-level callback function. It also includes a device ID, - * a handle to the MIDI Mapper, and a handle to the application's - * display window, so the callback can notify the window when input - * data is available. A single callback function is used to service - * all opened input devices. - */ - for (i=0; (i<(unsigned)nmidiin) && (idwDevice = i; - lpCallbackInstanceData[i]->lpBuf = lpInputBuffer; - - wRtn = midiInOpen((LPHMIDIIN)&hMidiIn[ndev], - midiinvec[i] - 1, - (DWORD)midiInputHandler, - (DWORD)lpCallbackInstanceData[ndev], - CALLBACK_FUNCTION); - if (wRtn) - { - FreeCallbackInstanceData(lpCallbackInstanceData[ndev]); - nt_midiinerror("midiInOpen: %s\n", wRtn); - } - else ndev++; - } - - /* Start MIDI input. - */ - for (i=0; i= nt_nexteventtime) -#endif - { - int msgtype = ((nt_nextevent.data & 0xf0) >> 4) - 8; - int commandbyte = nt_nextevent.data & 0xff; - int byte1 = (nt_nextevent.data >> 8) & 0xff; - int byte2 = (nt_nextevent.data >> 16) & 0xff; - int portno = nt_nextevent.dwDevice; - switch (msgtype) - { - case 0: - case 1: - case 2: - case 3: - case 6: - sys_midibytein(portno, commandbyte); - sys_midibytein(portno, byte1); - sys_midibytein(portno, byte2); - break; - case 4: - case 5: - sys_midibytein(portno, commandbyte); - sys_midibytein(portno, byte1); - break; - case 7: - sys_midibytein(portno, commandbyte); - break; - } - nt_isnextevent = 0; - } - } -} - -/* ------------------- public routines -------------------------- */ - -void sys_open_audio(int naudioindev, int *audioindev, - int nchindev, int *chindev, int naudiooutdev, int *audiooutdev, - int nchoutdev, int *choutdev, int rate) /* IOhannes */ -{ - int inchans, outchans; - if (nchindev < 0) - inchans = (nchindev < 1 ? -1 : chindev[0]); - else - { - int i = nchindev; - int *l = chindev; - inchans = 0; - while (i--) - inchans += *l++; - } - if (nchoutdev<0) - outchans = (nchoutdev < 1 ? -1 : choutdev[0]); - else - { - int i = nchoutdev; - int *l = choutdev; - outchans = 0; - while (i--) - outchans += *l++; - } - if (inchans < 0) - inchans = DEFAULTCHANS; - if (outchans < 0) - outchans = DEFAULTCHANS; - if (inchans & 1) - { - post("input channels rounded up to even number"); - inchans += 1; - } - if (outchans & 1) - { - post("output channels rounded up to even number"); - outchans += 1; - } - if (inchans > NT_MAXCH) - inchans = NT_MAXCH; - if (outchans > NT_MAXCH) - outchans = NT_MAXCH; - if (sys_verbose) - post("channels in %d, out %d", inchans, outchans); - if (rate < 1) - rate = DEFAULTSRATE; - nt_setchsr(inchans, outchans, rate); - if (nt_whichapi == API_PORTAUDIO) - { - int blocksize = (nt_blocksize ? nt_blocksize : 256); - if (blocksize != (1 << ilog2(blocksize))) - post("warning: blocksize adjusted to power of 2: %d", - (blocksize = (1 << ilog2(blocksize)))); - pa_open_audio(inchans, outchans, rate, sys_soundin, sys_soundout, - blocksize, nt_advance_samples/blocksize, - (naudioindev < 1 ? -1 : audioindev[0]), - (naudiooutdev < 1 ? -1 : audiooutdev[0])); - } - else - { - nt_nwavein = inchans / 2; - nt_nwaveout = outchans / 2; - nt_whichdac = (naudiooutdev < 1 ? (nt_nwaveout > 1 ? 0 : -1) : audiooutdev[0] - 1); - nt_whichadc = (naudioindev < 1 ? (nt_nwavein > 1 ? 0 : -1) : audioindev[0] - 1); - if (naudiooutdev > 1 || naudioindev > 1) - post("separate audio device choice not supported; using sequential devices."); - if (nt_blocksize) - post("warning: blocksize not settable for MMIO, just ASIO"); - mmio_open_audio(); - } -} - -void sys_open_midi(int nmidiin, int *midiinvec, int nmidiout, int *midioutvec) -{ - if (nmidiout) - nt_open_midiout(nmidiout, midioutvec); - if (nmidiin) - { - post( - "midi input enabled; warning, don't close the DOS window directly!"); - nt_open_midiin(nmidiin, midiinvec); - } - else post("not using MIDI input (use 'pd -midiindev 1' to override)"); -} - -float sys_getsr(void) -{ - return (sys_dacsr); -} - -int sys_get_inchannels(void) -{ - return (2 * nt_nwavein); -} - -int sys_get_outchannels(void) -{ - return (2 * nt_nwaveout); -} - -void sys_audiobuf(int n) -{ - /* set the size, in msec, of the audio FIFO. It's incorrect to - calculate this on the basis of 44100 sample rate; really, the - work should have been done in nt_setchsr(). */ - int nbuf = n * (44100./(REALDACBLKSIZE * 1000.)); - if (nbuf >= MAXBUFFER) - { - fprintf(stderr, "pd: audio buffering maxed out to %d\n", - (int)(MAXBUFFER * ((REALDACBLKSIZE * 1000.)/44100.))); - nbuf = MAXBUFFER; - } - else if (nbuf < 4) nbuf = 4; - fprintf(stderr, "%d audio buffers\n", nbuf); - nt_naudiobuffer = nbuf; - if (nt_adcjitterbufsallowed > nbuf - 2) - nt_adcjitterbufsallowed = nbuf - 2; - if (nt_dacjitterbufsallowed > nbuf - 2) - nt_dacjitterbufsallowed = nbuf - 2; - sys_schedadvance = 1000 * n; -} - -void sys_getmeters(float *inmax, float *outmax) -{ - if (inmax) - { - nt_meters = 1; - *inmax = nt_inmax; - *outmax = nt_outmax; - } - else - nt_meters = 0; - nt_inmax = nt_outmax = 0; -} - -void sys_reportidle(void) -{ -} - -int sys_send_dacs(void) -{ - if (nt_whichapi == API_PORTAUDIO) - return (pa_send_dacs()); - else return (mmio_send_dacs()); -} - -void sys_close_audio( void) -{ - if (nt_whichapi == API_PORTAUDIO) - pa_close_audio(); - else mmio_close_audio(); -} - -void sys_close_midi( void) -{ - nt_close_midiin(); - nt_close_midiout(); -} - -void sys_setblocksize(int n) -{ - if (n < 1) - n = 1; - nt_blocksize = n; -} - -/* ----------- public routines which are only defined for MSW/NT ---------- */ - -/* select between MMIO and ASIO audio APIs */ -void nt_set_sound_api(int which) -{ - nt_whichapi = which; - if (sys_verbose) - post("nt_whichapi %d", nt_whichapi); -} - -/* list the audio and MIDI device names */ -void sys_listdevs(void) -{ - UINT wRtn, ndevices; - unsigned int i; - - /* for MIDI and audio in and out, get the number of devices. - Then get the capabilities of each device and print its description. */ - - ndevices = midiInGetNumDevs(); - for (i = 0; i < ndevices; i++) - { - MIDIINCAPS micap; - wRtn = midiInGetDevCaps(i, (LPMIDIINCAPS) &micap, - sizeof(micap)); - if (wRtn) nt_midiinerror("midiInGetDevCaps: %s\n", wRtn); - else fprintf(stderr, - "MIDI input device #%d: %s\n", i+1, micap.szPname); - } - - ndevices = midiOutGetNumDevs(); - for (i = 0; i < ndevices; i++) - { - MIDIOUTCAPS mocap; - wRtn = midiOutGetDevCaps(i, (LPMIDIOUTCAPS) &mocap, - sizeof(mocap)); - if (wRtn) nt_midiouterror("midiOutGetDevCaps: %s\n", wRtn); - else fprintf(stderr, - "MIDI output device #%d: %s\n", i+1, mocap.szPname); - } - - if (nt_whichapi == API_PORTAUDIO) - { - pa_listdevs(); - return; - } - ndevices = waveInGetNumDevs(); - for (i = 0; i < ndevices; i++) - { - WAVEINCAPS wicap; - wRtn = waveInGetDevCaps(i, (LPWAVEINCAPS) &wicap, - sizeof(wicap)); - if (wRtn) nt_waveinerror("waveInGetDevCaps: %s\n", wRtn); - else fprintf(stderr, - "audio input device #%d: %s\n", i+1, wicap.szPname); - } - - ndevices = waveOutGetNumDevs(); - for (i = 0; i < ndevices; i++) - { - WAVEOUTCAPS wocap; - wRtn = waveOutGetDevCaps(i, (LPWAVEOUTCAPS) &wocap, - sizeof(wocap)); - if (wRtn) nt_waveouterror("waveOutGetDevCaps: %s\n", wRtn); - else fprintf(stderr, - "audio output device #%d: %s\n", i+1, wocap.szPname); - } -} - -void nt_soundindev(int which) -{ - nt_whichadc = which - 1; -} - -void nt_soundoutdev(int which) -{ - nt_whichdac = which - 1; -} - -void glob_audio(void *dummy, t_floatarg fadc, t_floatarg fdac) -{ - int adc = fadc, dac = fdac; - if (!dac && !adc) - post("%d channels in, %d channels out", - 2 * nt_nwavein, 2 * nt_nwaveout); - else - { - sys_close_audio(); - sys_open_audio(1, 0, 1, 0, /* dummy parameters */ - 1, &adc, 1, &dac, sys_dacsr); - } -} - diff --git a/pd/src/s_path.c b/pd/src/s_path.c index 58d33db7..456be94f 100644 --- a/pd/src/s_path.c +++ b/pd/src/s_path.c @@ -212,32 +212,15 @@ int open_via_path(const char *dir, const char *name, const char* ext, return (-1); } - /* LATER make this use open_via_path above. */ -void open_via_helppath(const char *name, const char *dir) +static int do_open_via_helppath(const char *realname, t_namelist *listp) { - t_namelist *nl, thislist, *listp; + t_namelist *nl; int fd = -1; - char dirresult[MAXPDSTRING], realdir[MAXPDSTRING], dirbuf2[MAXPDSTRING], - realname[MAXPDSTRING]; - - /* if directory is supplied, put it at head of search list. */ - if (*dir) - { - thislist.nl_string = dirbuf2; - thislist.nl_next = pd_helppath; - strncpy(dirbuf2, dir, MAXPDSTRING); - dirbuf2[MAXPDSTRING-1] = 0; - sys_unbashfilename(dirbuf2, dirbuf2); - listp = &thislist; - } - else listp = pd_helppath; - strcpy(realname, "help-"); - strncat(realname, name, MAXPDSTRING-5); - realname[MAXPDSTRING-1] = 0; + char dirresult[MAXPDSTRING], realdir[MAXPDSTRING]; for (nl = listp; nl; nl = nl->nl_next) { strcpy(dirresult, nl->nl_string); - strcpy(realdir,dirresult); + strcpy(realdir, dirresult); if (*dirresult && dirresult[strlen(dirresult)-1] != '/') strcat(dirresult, "/"); strcat(dirresult, realname); @@ -267,7 +250,7 @@ void open_via_helppath(const char *name, const char *dir) sys_unbashfilename(dirresult, dirresult); close (fd); glob_evalfile(0, gensym((char*)realname), gensym(realdir)); - return; + return (1); } } else @@ -275,12 +258,54 @@ void open_via_helppath(const char *name, const char *dir) if (sys_verbose) post("tried %s and failed", dirresult); } } - post("sorry, couldn't find help for \"%s\"", name); + return (0); +} + + /* LATER make this use open_via_path above. We expect the ".pd" + suffix here, even though we have to tear it back off for one of the + search attempts. */ +void open_via_helppath(const char *name, const char *dir) +{ + t_namelist *nl, thislist, *listp; + int fd = -1; + char dirbuf2[MAXPDSTRING], realname[MAXPDSTRING]; + + /* if directory is supplied, put it at head of search list. */ + if (*dir) + { + thislist.nl_string = dirbuf2; + thislist.nl_next = pd_helppath; + strncpy(dirbuf2, dir, MAXPDSTRING); + dirbuf2[MAXPDSTRING-1] = 0; + sys_unbashfilename(dirbuf2, dirbuf2); + listp = &thislist; + } + else listp = pd_helppath; + /* 1. "objectname-help.pd" */ + strncpy(realname, name, MAXPDSTRING-10); + realname[MAXPDSTRING-10] = 0; + if (strlen(realname) > 3 && !strcmp(realname+strlen(realname)-3, ".pd")) + realname[strlen(realname)-3] = 0; + strcat(realname, "-help.pd"); + if (do_open_via_helppath(realname, listp)) + return; + /* 2. "help-objectname.pd" */ + strcpy(realname, "help-"); + strncat(realname, name, MAXPDSTRING-10); + realname[MAXPDSTRING-1] = 0; + if (do_open_via_helppath(realname, listp)) + return; + /* 3. "objectname.pd" */ + if (do_open_via_helppath(name, listp)) + return; + post("sorry, couldn't find help patch for \"%s\"", name); return; } -/* Startup file reading for linux and MACOSX */ +/* Startup file reading for linux and MACOSX. This should be replaced by +a better mechanism. This should be integrated with the audio, MIDI, and +path dialog system. */ #ifdef UNIX @@ -297,13 +322,13 @@ int sys_rcfile(void) int rcargc; char* rcargv[NUMARGS]; char* buffer; - char fname[MAXPDSTRING], buf[1000]; + char fname[MAXPDSTRING], buf[1000], *home = getenv("HOME"); /* parse a startup file */ *fname = '\0'; - strncat(fname, getenv("HOME"), MAXPDSTRING-10); + strncat(fname, home? home : ".", MAXPDSTRING-10); strcat(fname, "/"); strcat(fname, STARTUPNAME); @@ -352,4 +377,34 @@ int sys_rcfile(void) } #endif /* UNIX */ + /* start an audio settings dialog window */ +void glob_start_path_dialog(t_pd *dummy, t_floatarg flongform) +{ + char buf[MAXPDSTRING]; + int i; + t_namelist *nl; + + for (nl = pd_path, i = 0; nl && i < 10; nl = nl->nl_next, i++) + sys_vgui("pd_set pd_path%d \"%s\"\n", i, nl->nl_string); + for (; i < 10; i++) + sys_vgui("pd_set pd_path%d \"\"\n", i); + + sprintf(buf, "pdtk_path_dialog %%s\n"); + gfxstub_new(&glob_pdobject, glob_start_path_dialog, buf); +} + + /* new values from dialog window */ +void glob_path_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv) +{ + int i; + namelist_free(pd_path); + pd_path = 0; + for (i = 0; i < argc; i++) + { + t_symbol *s = atom_getsymbolarg(i, argc, argv); + if (*s->s_name) + sys_addpath(s->s_name); + } +} + diff --git a/pd/src/s_portaudio.c b/pd/src/s_portaudio.c deleted file mode 100644 index 73dd55ab..00000000 --- a/pd/src/s_portaudio.c +++ /dev/null @@ -1,197 +0,0 @@ -/* Copyright (c) 2001 Miller Puckette and others. -* For information on usage and redistribution, and for a DISCLAIMER OF ALL -* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ - -/* this file calls Ross Bencina's and Phil Burk's Portaudio package. It's - the main way in for Mac OS and, with Michael Casey's help, also into - ASIO in Windows. */ - -/* dolist. - write a version of OpenAudioStream to take nchannels param - how do we specify latency? - listing devices? - choosing devices? -*/ - -#include "m_imp.h" -#include -#include -#include "pablio_pd.h" -#include "portaudio.h" -#ifndef NT -#include "portmidi.h" -#include "porttime.h" -#include "pminternal.h" -#endif - - /* public interface declared in m_imp.h */ - - /* implementation */ -static PABLIO_Stream *pa_stream; -static int pa_inchans, pa_outchans; -static float *pa_soundin, *pa_soundout; - -#define MAX_PA_CHANS 32 -#define MAX_SAMPLES_PER_FRAME MAX_PA_CHANS * DACBLKSIZE - -int pa_open_audio(int inchans, int outchans, int rate, t_sample *soundin, - t_sample *soundout, int framesperbuf, int nbuffers, - int indeviceno, int outdeviceno) -{ - PaError err; - /* post("in %d out %d rate %d device %d", inchans, outchans, rate, deviceno); */ - if (inchans != 0 && outchans != 0 && inchans != outchans) - error("portaudio: number of input and output channels must match"); - if (sys_verbose) - post("portaudio: opening for %d channels in, %d out", - inchans, outchans); - if (inchans > MAX_PA_CHANS) - { - post("input channels reduced to maximum %d", MAX_PA_CHANS); - inchans = MAX_PA_CHANS; - } - if (outchans > MAX_PA_CHANS) - { - post("output channels reduced to maximum %d", MAX_PA_CHANS); - outchans = MAX_PA_CHANS; - } - - if (inchans && outchans) - err = OpenAudioStream( &pa_stream, rate, paFloat32, - PABLIO_READ_WRITE, inchans, framesperbuf, nbuffers, indeviceno, outdeviceno); - else if (inchans) - err = OpenAudioStream( &pa_stream, rate, paFloat32, - PABLIO_READ, inchans, framesperbuf, nbuffers, indeviceno, outdeviceno); - else if (outchans) - err = OpenAudioStream( &pa_stream, rate, paFloat32, - PABLIO_WRITE, outchans, framesperbuf, nbuffers, indeviceno, outdeviceno); - else err = 0; - if ( err != paNoError ) - { - fprintf( stderr, "Error number %d occured opening portaudio stream\n", - err); - fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); - Pa_Terminate(); - return (1); - } - else if (sys_verbose) - post("... opened OK."); - pa_inchans = inchans; - pa_outchans = outchans; - pa_soundin = soundin; - pa_soundout = soundout; - return (0); -} - -void pa_close_audio( void) -{ - if (pa_inchans || pa_outchans) - CloseAudioStream( pa_stream ); - pa_inchans = pa_outchans = 0; -} - -int pa_send_dacs(void) -{ - float samples[MAX_SAMPLES_PER_FRAME], *fp1, *fp2; - int i, j; - double timebefore; - - timebefore = sys_getrealtime(); - if (pa_inchans) - { - ReadAudioStream(pa_stream, samples, DACBLKSIZE); - for (j = 0, fp1 = pa_soundin; j < pa_inchans; j++, fp1 += DACBLKSIZE) - for (i = 0, fp2 = samples + j; i < DACBLKSIZE; i++, - fp2 += pa_inchans) - { - fp1[i] = *fp2; - } - } - if (pa_outchans) - { - for (j = 0, fp1 = pa_soundout; j < pa_outchans; j++, fp1 += DACBLKSIZE) - for (i = 0, fp2 = samples + j; i < DACBLKSIZE; i++, - fp2 += pa_outchans) - { - *fp2 = fp1[i]; - fp1[i] = 0; - } - WriteAudioStream(pa_stream, samples, DACBLKSIZE); - } - - if (sys_getrealtime() > timebefore + 0.002) - return (SENDDACS_SLEPT); - else return (SENDDACS_YES); -} - - -void pa_listdevs(void) /* lifted from pa_devs.c in portaudio */ -{ - int i,j; - int numDevices; - const PaDeviceInfo *pdi; - PaError err; - Pa_Initialize(); - numDevices = Pa_CountDevices(); - if( numDevices < 0 ) - { - fprintf(stderr, "ERROR: Pa_CountDevices returned 0x%x\n", numDevices ); - err = numDevices; - goto error; - } - fprintf(stderr, "Number of devices = %d\n", numDevices ); - for( i=0; iname ); - fprintf(stderr, "Max Inputs = %d", pdi->maxInputChannels ); - fprintf(stderr, ", Max Outputs = %d\n", pdi->maxOutputChannels ); - if( pdi->numSampleRates == -1 ) - { - fprintf(stderr, "Sample Rate Range = %f to %f\n", pdi->sampleRates[0], pdi->sampleRates[1] ); - } - else - { - fprintf(stderr, "Sample Rates ="); - for( j=0; jnumSampleRates; j++ ) - { - fprintf(stderr, " %8.2f,", pdi->sampleRates[j] ); - } - fprintf(stderr, "\n"); - } - fprintf(stderr, "Native Sample Formats = "); - if( pdi->nativeSampleFormats & paInt8 ) fprintf(stderr, "paInt8, "); - if( pdi->nativeSampleFormats & paUInt8 ) fprintf(stderr, "paUInt8, "); - if( pdi->nativeSampleFormats & paInt16 ) fprintf(stderr, "paInt16, "); - if( pdi->nativeSampleFormats & paInt32 ) fprintf(stderr, "paInt32, "); - if( pdi->nativeSampleFormats & paFloat32 ) fprintf(stderr, "paFloat32, "); - if( pdi->nativeSampleFormats & paInt24 ) fprintf(stderr, "paInt24, "); - if( pdi->nativeSampleFormats & paPackedInt24 ) fprintf(stderr, "paPackedInt24, "); - fprintf(stderr, "\n"); - } - - fprintf(stderr, "----------------------------------------------\n"); - goto midi; - -error: - fprintf( stderr, "An error occured while using the portaudio stream\n" ); - fprintf( stderr, "Error number: %d\n", err ); - fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); - - /* and MIDI */ -midi: ; -#ifndef NT - for (i = 0; i < Pm_CountDevices(); i++) - { - const PmDeviceInfo *info = Pm_GetDeviceInfo(i); - printf("%d: %s, %s", i, info->interf, info->name); - if (info->input) printf(" (input)"); - if (info->output) printf(" (output)"); - printf("\n"); - } -#endif -} diff --git a/pd/src/s_sgi.c b/pd/src/s_sgi.c deleted file mode 100644 index 82a23dfb..00000000 --- a/pd/src/s_sgi.c +++ /dev/null @@ -1,433 +0,0 @@ -/* Copyright (c) 1997-1999 Miller Puckette. -* For information on usage and redistribution, and for a DISCLAIMER OF ALL -* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ - -#include "m_imp.h" -#include -#include -#include -#include -#ifdef HAVE_BSTRING_H -#include -#endif -#include -#include - -#include -#include -#include -int mdInit(void); /* prototype was messed up in midi.h */ -/* #include "sys/select.h" */ - -static ALport iport; -static ALport oport; -static ALconfig sgi_config; -#define DEFAULTCHANS 2 -#define SGI_MAXCH 8 -static int sys_inchannels, sys_outchannels; -static int sys_audiobufsamps; -int sys_schedadvance = 50000; /* scheduler advance in microseconds */ - /* (this is set ridiculously high until we can get the real-time - scheduling act together.) */ -int sys_hipriority = 0; -static int sgi_meters; /* true if we're metering */ -static float sgi_inmax; /* max input amplitude */ -static float sgi_outmax; /* max output amplitude */ - - - /* - set the special "flush zero" but (FS, bit 24) in the - Control Status Register of the FPU of R4k and beyond - so that the result of any underflowing operation will - be clamped to zero, and no exception of any kind will - be generated on the CPU. - - thanks to cpirazzi@cp.esd.sgi.com (Chris Pirazzi). - */ - -static void sgi_flush_all_underflows_to_zero(void) -{ - union fpc_csr f; - f.fc_word = get_fpc_csr(); - f.fc_struct.flush = 1; - set_fpc_csr(f.fc_word); -} - -static void sgi_setchsr(int inchans, int outchans, int sr) -{ - int inbytes = inchans * (DACBLKSIZE*sizeof(float)); - int outbytes = outchans * (DACBLKSIZE*sizeof(float)); - - sys_audiobufsamps = 64 * (int)(((float)sys_schedadvance)* sr / 64000000.); - sys_inchannels = inchans; - sys_outchannels = outchans; - sys_dacsr = sr; - - if (sys_soundin) - free(sys_soundin); - sys_soundin = (t_float *)malloc(inbytes); - memset(sys_soundin, 0, inbytes); - - if (sys_soundout) - free(sys_soundout); - sys_soundout = (t_float *)malloc(outbytes); - memset(sys_soundout, 0, outbytes); - - memset(sys_soundout, 0, sys_outchannels * (DACBLKSIZE*sizeof(float))); - memset(sys_soundin, 0, sys_inchannels * (DACBLKSIZE*sizeof(float))); -} - -static void sgi_open_audio(void) -{ - long pvbuf[4]; - long pvbuflen; - /* get current sample rate -- should use this to set logical SR */ - pvbuf[0] = AL_INPUT_RATE; - pvbuf[2] = AL_OUTPUT_RATE; - pvbuflen = 4; - - ALgetparams(AL_DEFAULT_DEVICE, pvbuf, pvbuflen); - - if (sys_inchannels && pvbuf[1] != sys_dacsr) - post("warning: input sample rate (%d) doesn't match mine (%f)\n", - pvbuf[1], sys_dacsr); - - if (sys_outchannels && pvbuf[3] != sys_dacsr) - post("warning: output sample rate (%d) doesn't match mine (%f)\n", - pvbuf[3], sys_dacsr); - - pvbuf[3] = pvbuf[1]; - ALsetparams(AL_DEFAULT_DEVICE, pvbuf, pvbuflen); - - sgi_config = ALnewconfig(); - - ALsetsampfmt(sgi_config, AL_SAMPFMT_FLOAT); - - if (sys_outchannels) - { - ALsetchannels(sgi_config, sys_outchannels); - ALsetqueuesize(sgi_config, sys_audiobufsamps * sys_outchannels); - oport = ALopenport("the ouput port", "w", sgi_config); - if (!oport) - fprintf(stderr,"Pd: failed to open audio write port\n"); - } - else oport = 0; - if (sys_inchannels) - { - ALsetchannels(sgi_config, sys_inchannels); - ALsetqueuesize(sgi_config, sys_audiobufsamps * sys_inchannels); - iport = ALopenport("the input port", "r", sgi_config); - if (!iport) - fprintf(stderr,"Pd: failed to open audio read port\n"); - } - else iport = 0; -} - -void sys_close_audio( void) -{ - if (iport) ALcloseport(iport); - if (oport) ALcloseport(oport); -} - -void sys_close_midi( void) -{ - /* ??? */ -} - -t_sample *sys_soundout; -t_sample *sys_soundin; -float sys_dacsr; - -int sys_send_dacs(void) -{ - float buf[SGI_MAXCH * DACBLKSIZE], *fp1, *fp2, *fp3, *fp4; - long outfill, infill; - int outchannels = sys_outchannels, inchannels = sys_inchannels; - int i, nwait = 0, channel; - int outblk = DACBLKSIZE * outchannels; - int inblk = DACBLKSIZE * inchannels; - outfill = ALgetfillable(oport); - if (sgi_meters) - { - int i, n; - float maxsamp; - for (i = 0, n = sys_inchannels * DACBLKSIZE, maxsamp = sgi_inmax; - i < n; i++) - { - float f = sys_soundin[i]; - if (f > maxsamp) maxsamp = f; - else if (-f > maxsamp) maxsamp = -f; - } - sgi_inmax = maxsamp; - for (i = 0, n = sys_outchannels * DACBLKSIZE, maxsamp = sgi_outmax; - i < n; i++) - { - float f = sys_soundout[i]; - if (f > maxsamp) maxsamp = f; - else if (-f > maxsamp) maxsamp = -f; - } - sgi_outmax = maxsamp; - } - - if (outfill <= outblk) - { - while ((infill = ALgetfilled(iport)) > 2*inblk) - { - if (sys_verbose) post("drop ADC buf"); - ALreadsamps(iport, buf, inblk); - return (0); - } - } - if (outchannels) - { - for (channel = 0, fp1 = buf, fp2 = sys_soundout; - channel < outchannels; channel++, fp1++, fp2 += DACBLKSIZE) - { - for (i = 0, fp3 = fp1, fp4 = fp2; i < DACBLKSIZE; - i++, fp3 += outchannels, fp4++) - *fp3 = *fp4, *fp4 = 0; - } - ALwritesamps(oport, buf, outchannels* DACBLKSIZE); - } - if (inchannels) - { - if (infill > inblk) - ALreadsamps(iport, buf, inchannels* DACBLKSIZE); - else - { - if (sys_verbose) post("extra ADC buf"); - memset(buf, 0, inblk*sizeof(float)); - } - for (channel = 0, fp1 = buf, fp2 = sys_soundin; - channel < inchannels; channel++, fp1++, fp2 += DACBLKSIZE) - { - for (i = 0, fp3 = fp1, fp4 = fp2; i < DACBLKSIZE; - i++, fp3 += inchannels, fp4++) - *fp4 = *fp3; - } - } - return (1); -} - -/* ------------------------- MIDI -------------------------- */ - -#define NPORT 2 - -static MDport sgi_inport[NPORT]; -static MDport sgi_outport[NPORT]; - -void sgi_open_midi(int midiin, int midiout) -{ - int i; - int sgi_nports = mdInit(); - if (sgi_nports < 0) sgi_nports = 0; - else if (sgi_nports > NPORT) sgi_nports = NPORT; - if (sys_verbose) - { - if (!sgi_nports) - { - post("no serial ports are configured for MIDI;"); - post("if you want to use MIDI, try exiting Pd, typing"); - post("'startmidi -d /dev/ttyd2' to a shell, and restarting Pd."); - } - else if (sgi_nports == 1) - post("Found one MIDI port on %s", mdGetName(0)); - else if (sgi_nports == 2) - post("Found MIDI ports on %s and %s", - mdGetName(0), mdGetName(1)); - } - if (midiin) - { - for (i = 0; i < sgi_nports; i++) - { - if (!(sgi_inport[i] = mdOpenInPort(mdGetName(i)))) - error("MIDI input port %d: open failed", i+1);; - } - } - if (midiout) - { - for (i = 0; i < sgi_nports; i++) - { - if (!(sgi_outport[i] = mdOpenOutPort(mdGetName(i)))) - error("MIDI output port %d: open failed", i+1);; - } - } - return; -} - -void sys_putmidimess(int portno, int a, int b, int c) -{ - MDevent mdv; - if (portno >= NPORT || portno < 0 || !sgi_outport[portno]) return; - mdv.msg[0] = a; - mdv.msg[1] = b; - mdv.msg[2] = c; - mdv.msg[3] = 0; - mdv.sysexmsg = 0; - mdv.stamp = 0; - mdv.msglen = 0; - if (mdSend(sgi_outport[portno], &mdv, 1) < 0) - error("MIDI output error\n"); - post("msg out %d %d %d", a, b, c); -} - -void sys_putmidibyte(int portno, int foo) -{ - error("MIDI raw byte output not available on SGI"); -} - -void inmidi_noteon(int portno, int channel, int pitch, int velo); -void inmidi_controlchange(int portno, int channel, int ctlnumber, int value); -void inmidi_programchange(int portno, int channel, int value); -void inmidi_pitchbend(int portno, int channel, int value); -void inmidi_aftertouch(int portno, int channel, int value); -void inmidi_polyaftertouch(int portno, int channel, int pitch, int value); - -void sys_poll_midi(void) -{ - int i; - MDport *mp; - for (i = 0, mp = sgi_inport; i < NPORT; i++, mp++) - { - int ret, status, b1, b2, nfds; - MDevent mdv; - fd_set inports; - struct timeval timeout; - timeout.tv_sec = 0; - timeout.tv_usec = 0; - if (!*mp) continue; - FD_ZERO(&inports); - FD_SET(mdGetFd(*mp), &inports); - - if (select(mdGetFd(*mp)+1 , &inports, 0, 0, &timeout) < 0) - perror("midi select"); - if (FD_ISSET(mdGetFd(*mp),&inports)) - { - if (mdReceive(*mp, &mdv, 1) < 0) - error("failure receiving message\n"); - else if (mdv.msg[0] == MD_SYSEX) mdFree(mdv.sysexmsg); - - else - { - int status = mdv.msg[0]; - int channel = (status & 0xf) + 1; - int b1 = mdv.msg[1]; - int b2 = mdv.msg[2]; - switch(status & 0xf0) - { - case MD_NOTEOFF: - inmidi_noteon(i, channel, b1, 0); - break; - case MD_NOTEON: - inmidi_noteon(i, channel, b1, b2); - break; - case MD_POLYKEYPRESSURE: - inmidi_polyaftertouch(i, channel, b1, b2); - break; - case MD_CONTROLCHANGE: - inmidi_controlchange(i, channel, b1, b2); - break; - case MD_PITCHBENDCHANGE: - inmidi_pitchbend(i, channel, ((b2 << 7) + b1)); - break; - case MD_PROGRAMCHANGE: - inmidi_programchange(i, channel, b1); - break; - case MD_CHANNELPRESSURE: - inmidi_aftertouch(i, channel, b1); - break; - } - } - } - } -} - - /* public routines */ - -void sys_open_audio(int naudioindev, int *audioindev, int nchindev, int *chindev, - int naudiooutdev, int *audiooutdev, int nchoutdev, int *choutdev, - int rate) /* IOhannes */ -{ - int inchans=0; - int outchans=0; - if (nchindev<0)inchans == -1; - else { - int i=nchindev; - int *l=chindev; - while(i--)inchans+=*l++; - } - if (nchoutdev<0)outchans == -1; - else { - int i=nchoutdev; - int *l=choutdev; - while(i--)outchans+=*l++; - } - - if (inchans < 0) inchans = DEFAULTCHANS; - if (outchans < 0) outchans = DEFAULTCHANS; - if (inchans > SGI_MAXCH) inchans = SGI_MAXCH; - if (outchans > SGI_MAXCH) outchans = SGI_MAXCH; - - sgi_setchsr(inchans, outchans, rate); - sgi_flush_all_underflows_to_zero(); - sgi_open_audio(); -} - -void sys_open_midi(int nmidiin, int *midiinvec, - int nmidiout, int *midioutvec) -{ - sgi_open_midi(nmidiin!=0, nmidiout!=0); -} - -float sys_getsr(void) -{ - return (sys_dacsr); -} - -void sys_audiobuf(int n) -{ - /* set the size, in milliseconds, of the audio FIFO */ - if (n < 5) n = 5; - else if (n > 5000) n = 5000; - fprintf(stderr, "audio buffer set to %d milliseconds\n", n); - sys_schedadvance = n * 1000; -} - -void sys_getmeters(float *inmax, float *outmax) -{ - if (inmax) - { - sgi_meters = 1; - *inmax = sgi_inmax; - *outmax = sgi_outmax; - } - else - sgi_meters = 0; - sgi_inmax = sgi_outmax = 0; -} - -void sys_reportidle(void) -{ -} - -int sys_get_inchannels(void) -{ - return (sys_inchannels); -} - -int sys_get_outchannels(void) -{ - return (sys_outchannels); -} - -void sys_set_priority(int foo) -{ - fprintf(stderr, - "warning: priority boosting in IRIX not implemented yet\n"); -} - -void sys_setblocksize(int n) -{ - fprintf(stderr, - "warning: blocksize not settable in IRIX\n"); -} diff --git a/pd/src/s_stuff.h b/pd/src/s_stuff.h index c8ac47f8..7a827b8b 100644 --- a/pd/src/s_stuff.h +++ b/pd/src/s_stuff.h @@ -54,12 +54,18 @@ extern int sys_sleepgrain; void sys_open_audio(int naudioindev, int *audioindev, int nchindev, int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev, int *choutdev, - int srate); /* IOhannes */ + int srate, int advance, int enable); void sys_close_audio(void); -void sys_open_midi(int nmidiin, int *midiinvec, + /* s_midi.c */ +void sys_open_midi(int nmidiin, int *midiinvec, int nmidiout, int *midioutvec); + + /* implemented in the system dependent MIDI code (s_midi_pm.c, etc. ) */ +void sys_do_open_midi(int nmidiin, int *midiinvec, int nmidiout, int *midioutvec); void sys_close_midi(void); +void midi_getdevs(char *indevlist, int *nindevs, + char *outdevlist, int *noutdevs, int maxndev, int devdescsize); int sys_send_dacs(void); void sys_reportidle(void); @@ -90,6 +96,7 @@ EXTERN void sys_log_error(int type); #define ERR_DACSLEPT 2 #define ERR_RESYNC 3 #define ERR_DATALATE 4 +void sched_set_using_dacs(int flag); /* s_inter.c */ @@ -122,6 +129,7 @@ void sys_setvirtualalarm( void); #define API_OSS 2 #define API_MMIO 3 #define API_PORTAUDIO 4 +#define API_JACK 5 #ifdef __linux__ #define API_DEFAULT API_OSS @@ -135,9 +143,19 @@ void sys_setvirtualalarm( void); #define API_DEFAULT API_PORTAUDIO #define API_DEFSTRING "portaudio" #endif -#define DEFAULTAUDIODEV -1 +#define DEFAULTAUDIODEV 0 + +#define MAXAUDIOINDEV 4 +#define MAXAUDIOOUTDEV 4 -#define DEFMIDIDEV -1 +#define DEFMIDIDEV 0 + +#define DEFAULTSRATE 44100 +#ifdef MSW +#define DEFAULTADVANCE 70 +#else +#define DEFAULTADVANCE 50 +#endif int pa_open_audio(int inchans, int outchans, int rate, t_sample *soundin, t_sample *soundout, int framesperbuf, int nbuffers, @@ -146,6 +164,9 @@ void pa_close_audio(void); int pa_send_dacs(void); void sys_reportidle(void); void pa_listdevs(void); +void pa_getdevs(char *indevlist, int *nindevs, + char *outdevlist, int *noutdevs, int *canmulti, + int maxndev, int devdescsize); int oss_open_audio(int naudioindev, int *audioindev, int nchindev, int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev, @@ -153,13 +174,25 @@ int oss_open_audio(int naudioindev, int *audioindev, int nchindev, void oss_close_audio(void); int oss_send_dacs(void); void oss_reportidle(void); -void oss_listdevs(void); +void oss_getdevs(char *indevlist, int *nindevs, + char *outdevlist, int *noutdevs, int *canmulti, + int maxndev, int devdescsize); -int alsa_open_audio(int wantinchans, int wantoutchans, int srate); +int alsa_open_audio(int naudioindev, int *audioindev, int nchindev, + int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev, + int *choutdev, int rate); void alsa_close_audio(void); int alsa_send_dacs(void); void alsa_reportidle(void); -void alsa_listdevs(void); +void alsa_getdevs(char *indevlist, int *nindevs, + char *outdevlist, int *noutdevs, int *canmulti, + int maxndev, int devdescsize); + +int jack_open_audio(int wantinchans, int wantoutchans, int srate); +void jack_close_audio(void); +int jack_send_dacs(void); +void jack_reportidle(void); +void jack_listdevs(void); void mmio_open_audio(int naudioindev, int *audioindev, int nchindev, int *chindev, int naudiooutdev, int *audiooutdev, @@ -167,13 +200,16 @@ void mmio_open_audio(int naudioindev, int *audioindev, void mmio_close_audio( void); void mmio_reportidle(void); int mmio_send_dacs(void); -void mmio_listdevs(void); +void mmio_getdevs(char *indevlist, int *nindevs, + char *outdevlist, int *noutdevs, int *canmulti, + int maxndev, int devdescsize); void sys_listmididevs(void); -void sys_set_sound_api(int whichapi); +void sys_set_audio_api(int whichapi); +void sys_get_audio_apis(char *buf); extern int sys_audioapi; +void sys_set_audio_state(int onoff); /* API dependent audio flags and settings */ void oss_set32bit( void); void linux_alsa_devname(char *devname); - diff --git a/pd/src/s_unix.c b/pd/src/s_unix.c deleted file mode 100644 index 85282f3b..00000000 --- a/pd/src/s_unix.c +++ /dev/null @@ -1,454 +0,0 @@ -/* Copyright (c) 1997-1999 Miller Puckette and others. -* For information on usage and redistribution, and for a DISCLAIMER OF ALL -* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ - -/* this file is misnamed. It seems to handle clock functions and MIDI I/O; -probably should be called "s_midi.c" */ - -#include "m_imp.h" -#ifdef UNIX -#include -#include -#ifdef HAVE_BSTRING_H -#include -#endif -#endif -#ifdef NT -#include -#include -#include -#include -#endif -#include -#include -#include - -#ifdef NT -static LARGE_INTEGER nt_inittime; -static double nt_freq = 0; - -static void sys_initntclock(void) -{ - LARGE_INTEGER f1; - LARGE_INTEGER now; - QueryPerformanceCounter(&now); - if (!QueryPerformanceFrequency(&f1)) - { - fprintf(stderr, "pd: QueryPerformanceFrequency failed\n"); - f1.QuadPart = 1; - } - nt_freq = f1.QuadPart; - nt_inittime = now; -} - -#if 0 - /* this is a version you can call if you did the QueryPerformanceCounter - call yourself. Necessary for time tagging incoming MIDI at interrupt - level, for instance; but we're not doing that just now. */ - -double nt_tixtotime(LARGE_INTEGER *dumbass) -{ - if (nt_freq == 0) sys_initntclock(); - return (((double)(dumbass->QuadPart - nt_inittime.QuadPart)) / nt_freq); -} -#endif -#endif /* NT */ - -double sys_getrealtime(void) /* get "real time" in seconds */ -{ -#ifdef UNIX - static struct timeval then; - struct timeval now; - gettimeofday(&now, 0); - if (then.tv_sec == 0 && then.tv_usec == 0) then = now; - return ((now.tv_sec - then.tv_sec) + - (1./1000000.) * (now.tv_usec - then.tv_usec)); -#endif -#ifdef NT - LARGE_INTEGER now; - QueryPerformanceCounter(&now); - if (nt_freq == 0) sys_initntclock(); - return (((double)(now.QuadPart - nt_inittime.QuadPart)) / nt_freq); -#endif -} - -typedef struct _midiqelem -{ - double q_time; - int q_portno; - unsigned char q_onebyte; - unsigned char q_byte1; - unsigned char q_byte2; - unsigned char q_byte3; -} t_midiqelem; - -#define MIDIQSIZE 1024 - -t_midiqelem midi_outqueue[MIDIQSIZE]; -int midi_outhead, midi_outtail; -t_midiqelem midi_inqueue[MIDIQSIZE]; -int midi_inhead, midi_intail; -static double sys_midiinittime; - - /* this is our current estimate for at what "system" real time the - current logical time's output should occur. */ -static double sys_dactimeminusrealtime; - /* same for input, should be schduler advance earlier. */ -static double sys_adctimeminusrealtime; - -static double sys_newdactimeminusrealtime = -1e20; -static double sys_newadctimeminusrealtime = -1e20; -static double sys_whenupdate; - -void sys_initmidiqueue( void) -{ - sys_midiinittime = clock_getlogicaltime(); - sys_dactimeminusrealtime = sys_adctimeminusrealtime = 0; -} - - /* this is called from the OS dependent code from time to time when we - think we know the delay (outbuftime) in seconds, at which the last-output - audio sample will go out the door. */ -void sys_setmiditimediff(double inbuftime, double outbuftime) -{ - double dactimeminusrealtime = - .001 * clock_gettimesince(sys_midiinittime) - - outbuftime - sys_getrealtime(); - double adctimeminusrealtime = - .001 * clock_gettimesince(sys_midiinittime) - + inbuftime - sys_getrealtime(); - if (dactimeminusrealtime > sys_newdactimeminusrealtime) - sys_newdactimeminusrealtime = dactimeminusrealtime; - if (adctimeminusrealtime > sys_newadctimeminusrealtime) - sys_newadctimeminusrealtime = adctimeminusrealtime; - if (sys_getrealtime() > sys_whenupdate) - { - sys_dactimeminusrealtime = sys_newdactimeminusrealtime; - sys_adctimeminusrealtime = sys_newadctimeminusrealtime; - sys_newdactimeminusrealtime = -1e20; - sys_newadctimeminusrealtime = -1e20; - sys_whenupdate = sys_getrealtime() + 1; - } -} - - /* return the logical time of the DAC sample we believe is currently - going out, based on how much "system time" has elapsed since the - last time sys_setmiditimediff got called. */ -static double sys_getmidioutrealtime( void) -{ - return (sys_getrealtime() + sys_dactimeminusrealtime); -} - -static double sys_getmidiinrealtime( void) -{ - return (sys_getrealtime() + sys_adctimeminusrealtime); -} - -static void sys_putnext( void) -{ - int portno = midi_outqueue[midi_outtail].q_portno; - if (midi_outqueue[midi_outtail].q_onebyte) - sys_putmidibyte(portno, midi_outqueue[midi_outtail].q_byte1); - else sys_putmidimess(portno, midi_outqueue[midi_outtail].q_byte1, - midi_outqueue[midi_outtail].q_byte2, - midi_outqueue[midi_outtail].q_byte3); - midi_outtail = (midi_outtail + 1 == MIDIQSIZE ? 0 : midi_outtail + 1); -} - -/* #define TEST_DEJITTER */ - -void sys_pollmidioutqueue( void) -{ -#ifdef TEST_DEJITTER - static int db = 0; -#endif - double midirealtime = sys_getmidioutrealtime(); -#ifdef TEST_DEJITTER - if (midi_outhead == midi_outtail) - db = 0; -#endif - while (midi_outhead != midi_outtail) - { -#ifdef TEST_DEJITTER - if (!db) - { - post("out: del %f, midiRT %f logicaltime %f, RT %f dacminusRT %f", - (midi_outqueue[midi_outtail].q_time - midirealtime), - midirealtime, .001 * clock_gettimesince(sys_midiinittime), - sys_getrealtime(), sys_dactimeminusrealtime); - db = 1; - } -#endif - if (midi_outqueue[midi_outtail].q_time <= midirealtime) - sys_putnext(); - else break; - } -} - -static void sys_queuemidimess(int portno, int onebyte, int a, int b, int c) -{ - t_midiqelem *midiqelem; - int newhead = midi_outhead +1; - if (newhead == MIDIQSIZE) - newhead = 0; - /* if FIFO is full flush an element to make room */ - if (newhead == midi_outtail) - sys_putnext(); - midi_outqueue[midi_outhead].q_portno = portno; - midi_outqueue[midi_outhead].q_onebyte = onebyte; - midi_outqueue[midi_outhead].q_byte1 = a; - midi_outqueue[midi_outhead].q_byte2 = b; - midi_outqueue[midi_outhead].q_byte3 = c; - midi_outqueue[midi_outhead].q_time = - .001 * clock_gettimesince(sys_midiinittime); - midi_outhead = newhead; - sys_pollmidioutqueue(); -} - -#define MIDI_NOTEON 144 -#define MIDI_POLYAFTERTOUCH 160 -#define MIDI_CONTROLCHANGE 176 -#define MIDI_PROGRAMCHANGE 192 -#define MIDI_AFTERTOUCH 208 -#define MIDI_PITCHBEND 224 - -void outmidi_noteon(int portno, int channel, int pitch, int velo) -{ - if (pitch < 0) pitch = 0; - else if (pitch > 127) pitch = 127; - if (velo < 0) velo = 0; - else if (velo > 127) velo = 127; - sys_queuemidimess(portno, 0, MIDI_NOTEON + (channel & 0xf), pitch, velo); -} - -void outmidi_controlchange(int portno, int channel, int ctl, int value) -{ - if (ctl < 0) ctl = 0; - else if (ctl > 127) ctl = 127; - if (value < 0) value = 0; - else if (value > 127) value = 127; - sys_queuemidimess(portno, 0, MIDI_CONTROLCHANGE + (channel & 0xf), - ctl, value); -} - -void outmidi_programchange(int portno, int channel, int value) -{ - if (value < 0) value = 0; - else if (value > 127) value = 127; - sys_queuemidimess(portno, 0, - MIDI_PROGRAMCHANGE + (channel & 0xf), value, 0); -} - -void outmidi_pitchbend(int portno, int channel, int value) -{ - if (value < 0) value = 0; - else if (value > 16383) value = 16383; - sys_queuemidimess(portno, 0, MIDI_PITCHBEND + (channel & 0xf), - (value & 127), ((value>>7) & 127)); -} - -void outmidi_aftertouch(int portno, int channel, int value) -{ - if (value < 0) value = 0; - else if (value > 127) value = 127; - sys_queuemidimess(portno, 0, MIDI_AFTERTOUCH + (channel & 0xf), value, 0); -} - -void outmidi_polyaftertouch(int portno, int channel, int pitch, int value) -{ - if (pitch < 0) pitch = 0; - else if (pitch > 127) pitch = 127; - if (value < 0) value = 0; - else if (value > 127) value = 127; - sys_queuemidimess(portno, 0, MIDI_POLYAFTERTOUCH + (channel & 0xf), - pitch, value); -} - -void outmidi_mclk(int portno) -{ - sys_queuemidimess(portno, 1, 0xf8, 0,0); -} - -/* ------------------------- MIDI input queue handling ------------------ */ -typedef struct midiparser -{ - int mp_status; - int mp_sysex; - int mp_gotbyte1; - int mp_byte1; -} t_midiparser; - -#define MIDINOTEOFF 0x80 -#define MIDINOTEON 0x90 -#define MIDIPOLYTOUCH 0xa0 -#define MIDICONTROLCHANGE 0xb0 -#define MIDIPROGRAMCHANGE 0xc0 -#define MIDICHANNELTOUCH 0xd0 -#define MIDIPITCHBEND 0xe0 - /* functions in x_midi.c */ -void inmidi_realtimein(int portno, int cmd); -void inmidi_byte(int portno, int byte); -void inmidi_sysex(int portno, int byte); -void inmidi_noteon(int portno, int channel, int pitch, int velo); -void inmidi_controlchange(int portno, int channel, int ctlnumber, int value); -void inmidi_programchange(int portno, int channel, int value); -void inmidi_pitchbend(int portno, int channel, int value); -void inmidi_aftertouch(int portno, int channel, int value); -void inmidi_polyaftertouch(int portno, int channel, int pitch, int value); - -static void sys_dispatchnextmidiin( void) -{ - static t_midiparser parser[MAXMIDIINDEV], *parserp; - int portno = midi_inqueue[midi_intail].q_portno, - byte = midi_inqueue[midi_intail].q_byte1; - if (!midi_inqueue[midi_intail].q_onebyte) - bug("sys_dispatchnextmidiin"); - if (portno < 0 || portno >= MAXMIDIINDEV) - bug("sys_dispatchnextmidiin 2"); - parserp = parser + portno; - outlet_setstacklim(); - - if (byte >= 0xf8) - inmidi_realtimein(portno, byte); - else - { - inmidi_byte(portno, byte); - if (byte < 0xf0) - { - if (byte & 0x80) - { - parserp->mp_status = byte; - parserp->mp_gotbyte1 = 0; - } - else - { - int cmd = (parserp->mp_status & 0xf0); - int chan = (parserp->mp_status & 0xf); - int byte1 = parserp->mp_byte1, gotbyte1 = parserp->mp_gotbyte1; - switch (cmd) - { - case MIDINOTEOFF: - if (gotbyte1) - inmidi_noteon(portno, chan, byte1, 0), - parserp->mp_gotbyte1 = 0; - else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1; - break; - case MIDINOTEON: - if (gotbyte1) - inmidi_noteon(portno, chan, byte1, byte), - parserp->mp_gotbyte1 = 0; - else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1; - break; - case MIDIPOLYTOUCH: - if (gotbyte1) - inmidi_polyaftertouch(portno, chan, byte1, byte), - parserp->mp_gotbyte1 = 0; - else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1; - break; - case MIDICONTROLCHANGE: - if (gotbyte1) - inmidi_controlchange(portno, chan, byte1, byte), - parserp->mp_gotbyte1 = 0; - else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1; - break; - case MIDIPROGRAMCHANGE: - inmidi_programchange(portno, chan, byte); - break; - case MIDICHANNELTOUCH: - inmidi_aftertouch(portno, chan, byte); - break; - case MIDIPITCHBEND: - if (gotbyte1) - inmidi_pitchbend(portno, chan, ((byte << 7) + byte1)), - parserp->mp_gotbyte1 = 0; - else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1; - break; - } - } - } - } - midi_intail = (midi_intail + 1 == MIDIQSIZE ? 0 : midi_intail + 1); -} - -void sys_pollmidiinqueue( void) -{ -#ifdef TEST_DEJITTER - static int db = 0; -#endif - double logicaltime = .001 * clock_gettimesince(sys_midiinittime); -#ifdef TEST_DEJITTER - if (midi_inhead == midi_intail) - db = 0; -#endif - while (midi_inhead != midi_intail) - { -#ifdef TEST_DEJITTER - if (!db) - { - post("in del %f, logicaltime %f, RT %f adcminusRT %f", - (midi_inqueue[midi_intail].q_time - logicaltime), - logicaltime, sys_getrealtime(), sys_adctimeminusrealtime); - db = 1; - } -#endif -#if 0 - if (midi_inqueue[midi_intail].q_time <= logicaltime - 0.007) - post("late %f", - 1000 * (logicaltime - midi_inqueue[midi_intail].q_time)); -#endif - if (midi_inqueue[midi_intail].q_time <= logicaltime) - { -#if 0 - post("diff %f", - 1000* (logicaltime - midi_inqueue[midi_intail].q_time)); -#endif - sys_dispatchnextmidiin(); - } - else break; - } -} - - /* this should be called from the system dependent MIDI code when a byte - comes in, as a result of our calling sys_poll_midi. We stick it on a - timetag queue and dispatch it at the appropriate logical time. */ - - -void sys_midibytein(int portno, int byte) -{ - static int warned = 0; - t_midiqelem *midiqelem; - int newhead = midi_inhead +1; - if (newhead == MIDIQSIZE) - newhead = 0; - /* if FIFO is full flush an element to make room */ - if (newhead == midi_intail) - { - if (!warned) - { - post("warning: MIDI timing FIFO overflowed"); - warned = 1; - } - sys_dispatchnextmidiin(); - } - midi_inqueue[midi_inhead].q_portno = portno; - midi_inqueue[midi_inhead].q_onebyte = 1; - midi_inqueue[midi_inhead].q_byte1 = byte; - midi_inqueue[midi_inhead].q_time = sys_getmidiinrealtime(); - midi_inhead = newhead; - sys_pollmidiinqueue(); -} - -void sys_pollmidiqueue( void) -{ -#if 0 - static double lasttime; - double newtime = sys_getrealtime(); - if (newtime - lasttime > 0.007) - post("delay %d", (int)(1000 * (newtime - lasttime))); - lasttime = newtime; -#endif - sys_poll_midi(); /* OS dependent poll for MIDI input */ - sys_pollmidioutqueue(); - sys_pollmidiinqueue(); -} - diff --git a/pd/src/u_main.tk b/pd/src/u_main.tk index b879843a..ef10c80b 100644 --- a/pd/src/u_main.tk +++ b/pd/src/u_main.tk @@ -1,4 +1,4 @@ -set pd_nt 0 +set pd_nt 1 # (The above is 0 for unix, 1 for microsoft, and 2 for Mac OSX. The first # line is automatically munged by the relevant makefiles.) @@ -36,19 +36,30 @@ if {$pd_nt == 2} { set pd_tearoff 0 } +# hack so you can easily test-run this script in linux... define pd_guidir +# (which is normally defined at startup in pd under linux...) + +if {$pd_nt == 0} { + if {! [info exists pd_guidir]} { + global pd_guidir + puts stderr {setting pd_guidir to '.'} + set pd_guidir . + } +} + # it's unfortunate but we seem to have to turn off global bindings # for Text objects to get control-s and control-t to do what we want for # "text" dialogs below. Also we have to get rid of tab's changing the focus. bind all "" -bind all "" +bind all <> "" bind Text {} bind Text {} # puts stderr [bind all] ################## set up main window ######################### menu .mbar -canvas .dummy -height 2p -width 9c +canvas .dummy -height 2p -width 6c frame .controls pack .controls .dummy -side top -fill x @@ -60,11 +71,11 @@ menu .mbar.windows -postcommand [concat pdtk_fixwindowmenu] -tearoff $pd_tearoff menu .mbar.audio -tearoff $pd_tearoff if {$pd_nt != 2} { .mbar add cascade -label "Windows" -menu .mbar.windows - .mbar add cascade -label "Audio" -menu .mbar.audio + .mbar add cascade -label "Media" -menu .mbar.audio } else { # Perhaps this is silly, but Mac HIG want "Window Help" as the last menus - .mbar add cascade -label "Audio" -menu .mbar.audio - .mbar add cascade -label "Window" -menu .mbar.windows + .mbar add cascade -label "Media" -menu .mbar.audio + .mbar add cascade -label "Windows" -menu .mbar.windows } menu .mbar.help -tearoff $pd_tearoff .mbar add cascade -label "Help" -menu .mbar.help @@ -272,7 +283,8 @@ set help_directory $pd_guidir/doc proc menu_documentation {} { global help_directory - + global pd_nt + set filename [tk_getOpenFile -defaultextension .pd \ -filetypes { {{documentation} {.pd .txt .htm}} } \ -initialdir $help_directory] @@ -282,7 +294,6 @@ proc menu_documentation {} { menu_opentext $filename } elseif {[string first .htm $filename] >= 0} { if {$pd_nt == 0} { -#I wish I could get this to run in the background; the "&" doesn't do it: exec sh -c \ [format "mozilla file:%s || netscape file:%s &\n" \ $filename $filename] @@ -291,9 +302,8 @@ proc menu_documentation {} { exec sh -c \ [format "open %s" $filename] } else { - tk_messageBox -message \ - {sorry -- can't open htm files yet; open this manually} \ - -type ok + exec rundll32 url.dll,FileProtocolHandler \ + [format "file:%s" $filename] & } } else { set help_directory [string range $filename 0 \ @@ -319,6 +329,38 @@ proc menu_doc_open {subdir basename} { } } +############# routine to add audio and help menus ############### + +proc menu_addstd {mbar} { + global pd_apilist +# the "Audio" menu + $mbar.audio add command -label {audio ON} -accelerator [accel_munge "Ctrl+/"] \ + -command {menu_audio 1} + $mbar.audio add command -label {audio OFF} -accelerator [accel_munge "Ctrl+."] \ + -command {menu_audio 0} + for {set x 0} {$x<[llength $pd_apilist]} {incr x} { + $mbar.audio add radiobutton -label [lindex [lindex $pd_apilist $x] 0] \ + -command {menu_audio 0} -variable pd_whichapi \ + -value [lindex [lindex $pd_apilist $x] 1]\ + -command {pd [concat pd audio-setapi $pd_whichapi \;]} + } + $mbar.audio add command -label {Audio settings...} \ + -command {pd pd audio-properties \;} + + $mbar.audio add command -label {MIDI settings...} \ + -command {pd pd midi-properties \;} + $mbar.audio add command -label {Test Audio and MIDI} \ + -command {menu_doc_open doc/7.stuff/tools testtone.pd} + $mbar.audio add command -label {Load Meter} \ + -command {menu_doc_open doc/7.stuff/tools load-meter.pd} + +# the "Help" menu + $mbar.help add command -label {About Pd} \ + -command {menu_doc_open doc/1.manual 1.introduction.txt} + $mbar.help add command -label {Pure Documentation...} \ + -command {menu_documentation} +} + #################### the "File" menu for the Pd window ############## .mbar.file add command -label New -command {menu_new} \ @@ -328,6 +370,8 @@ proc menu_doc_open {subdir basename} { .mbar.file add separator .mbar.file add command -label Message -command {menu_send} \ -accelerator [accel_munge "Ctrl+m"] +.mbar.file add command -label Path... \ + -command {pd pd start-path-dialog \;} .mbar.file add separator .mbar.file add command -label Quit -command {menu_quit} \ -accelerator [accel_munge "Ctrl+q"] @@ -335,22 +379,6 @@ proc menu_doc_open {subdir basename} { #################### the "Find" menu for the Pd window ############## .mbar.find add command -label {last error?} -command {menu_finderror} -#################### the "Audio" menu for the Pd window ############## -.mbar.audio add command -label On -accelerator [accel_munge "Ctrl+/"] \ - -command {menu_audio 1} -.mbar.audio add command -label Off -accelerator [accel_munge "Ctrl+."] \ - -command {menu_audio 0} - -#################### the "Help" menu for the Pd window ############## -.mbar.help add command -label {About Pd} \ - -command {menu_doc_open doc/1.manual 1.introduction.txt} -.mbar.help add command -label {Test Audio and MIDI} \ - -command {menu_doc_open doc/7.stuff/tools testtone.pd} -.mbar.help add command -label {Load Meter} \ - -command {menu_doc_open doc/7.stuff/tools load-meter.pd} -.mbar.help add command -label {Pure Documentation...} \ - -command {menu_documentation} - ########### functions for menu functions on document windows ######## proc menu_save {name} { @@ -660,6 +688,9 @@ proc pdtk_canvas_new {name width height geometry editable} { $name.m.file add command -label Message -command {menu_send} \ -accelerator [accel_munge "Ctrl+m"] + $name.m.file add command -label Path... \ + -command {pd pd start-path-dialog \;} + $name.m.file add separator $name.m.file add command -label Close \ -command [concat menu_close $name] \ @@ -812,8 +843,6 @@ proc pdtk_canvas_new {name width height geometry editable} { $name.m.put add command -label Array \ -command [concat menu_array $name] - - # the find menu menu $name.m.find -tearoff $pd_tearoff $name.m add cascade -label Find -menu $name.m.find @@ -839,30 +868,19 @@ proc pdtk_canvas_new {name width height geometry editable} { # the audio menu menu $name.m.audio -tearoff $pd_tearoff - $name.m.audio add command -label On -accelerator [accel_munge "Ctrl+/"] \ - -command {menu_audio 1} - $name.m.audio add command -label Off -accelerator [accel_munge "Ctrl+."] \ - -command {menu_audio 0} - if {$pd_nt != 2} { $name.m add cascade -label Windows -menu $name.m.windows - $name.m add cascade -label Audio -menu $name.m.audio + $name.m add cascade -label Media -menu $name.m.audio } else { - $name.m add cascade -label Audio -menu $name.m.audio + $name.m add cascade -label Media -menu $name.m.audio $name.m add cascade -label Window -menu $name.m.windows } # the help menu menu $name.m.help -tearoff $pd_tearoff $name.m add cascade -label Help -menu $name.m.help - $name.m.help add command -label {Getting Started} \ - -command {menu_doc_open doc/1.manual 1.introduction.txt} - $name.m.help add command -label {Test Audio and MIDI} \ - -command {menu_doc_open doc/7.stuff/tools testtone.pd} - $name.m.help add command -label {Load Meter} \ - -command {menu_doc_open doc/7.stuff/tools load-meter.pd} - $name.m.help add command -label {Pure Documentation} \ - -command {menu_documentation} + + menu_addstd $name.m # the popup menu menu $name.popup -tearoff false @@ -911,8 +929,8 @@ proc pdtk_canvas_new {name width height geometry editable} { bind $name.c {pdtk_canvas_keyup %W %K %A} bind $name.c {pdtk_canvas_motion %W %x %y 0} bind $name.c {pdtk_canvas_motion %W %x %y 4} - bind $name.c {pdtk_canvas_map %W %s} -# bind $name.c {puts stderr map} + bind $name.c {pdtk_canvas_map %W} + bind $name.c {pdtk_canvas_unmap %W} focus $name.c # puts stderr "all done" # after 1 [concat raise $name] @@ -1036,6 +1054,10 @@ proc pdtk_canvas_key {name key iso shift} { set keynum 8 } } + if {$key == "KP_Delete"} { + set key 127 + set keynum 127 + } if {$iso != ""} { scan $iso %c keynum pd [canvastosym $name] key 1 $keynum $shift\; @@ -1115,12 +1137,14 @@ proc pdtk_canvas_motion {name x y mods} { # "map" event tells us when the canvas becomes visible (arg is "0") or # invisible (arg is ""). Invisibility means the Window Manager has minimized # us. We don't get a final "unmap" event when we destroy the window. -proc pdtk_canvas_map {name arg} { - if {$arg == "0"} { - pd [canvastosym $name] map 1 \; - } else { - pd [canvastosym $name] map 0 \; - } +proc pdtk_canvas_map {name} { +# puts stderr [concat map $name] + pd [canvastosym $name] map 1 \; +} + +proc pdtk_canvas_unmap {name} { +# puts stderr [concat unmap $name] + pd [canvastosym $name] map 0 \; } set saveas_dir nowhere @@ -2267,6 +2291,14 @@ proc pdtk_iemgui_dialog {id mainheader \ label $id.space5 -text "" pack $id.space5 -side top + if {[info tclversion] < 8.4} { + bind $id {tkTabToWindow [tk_focusNext %W]} + bind $id <> {tkTabToWindow [tk_focusPrev %W]} + } else { + bind $id {tk::TabToWindow [tk_focusNext %W]} + bind $id <> {tk::TabToWindow [tk_focusPrev %W]} + } + bind $id.dim.w_ent [concat iemgui_ok $id] bind $id.dim.h_ent [concat iemgui_ok $id] bind $id.rng.min_ent [concat iemgui_ok $id] @@ -2583,9 +2615,10 @@ proc pdtk_pd_ctrlkey {name key shift} { # asked pd to open something. Also, get character width and height for # font sizes 8, 10, 12, 14, 16, and 24. -proc pdtk_pd_startup {version} { - global pd_myversion +proc pdtk_pd_startup {version apilist} { + global pd_myversion pd_apilist set pd_myversion $version + set pd_apilist $apilist set width1 [font measure -*-courier-bold--normal--8-* x] set height1 [lindex [font metrics -*-courier-bold--normal--8-*] 5] @@ -2617,6 +2650,11 @@ proc pdtk_pd_startup {version} { 24 $width6 $height6 \ 36 $width7 $height7 \ \;]; + + # add the audio and help menus to the Pd window. We delayed this + # so that we'd know the value of "apilist". + menu_addstd .mbar + } ##################### DSP ON/OFF, METERS, DIO ERROR ################### @@ -2759,3 +2797,494 @@ if {$pd_nt == 1} { polleofloop } +####################### audio dialog ##################3 + +proc audio_apply {id} { + global audio_indev1 audio_indev2 audio_indev3 audio_indev4 + global audio_inchan1 audio_inchan2 audio_inchan3 audio_inchan4 + global audio_outdev1 audio_outdev2 audio_outdev3 audio_outdev4 + global audio_outchan1 audio_outchan2 audio_outchan3 audio_outchan4 + global audio_sr audio_advance + + pd [concat pd audio-dialog \ + $audio_indev1 \ + $audio_indev2 \ + $audio_indev3 \ + $audio_indev4 \ + $audio_inchan1 \ + $audio_inchan2 \ + $audio_inchan3 \ + $audio_inchan4 \ + $audio_outdev1 \ + $audio_outdev2 \ + $audio_outdev3 \ + $audio_outdev4 \ + $audio_outchan1 \ + $audio_outchan2 \ + $audio_outchan3 \ + $audio_outchan4 \ + $audio_sr \ + $audio_advance \ + \;] +} + +proc audio_cancel {id} { + pd [concat $id cancel \;] +} + +proc audio_ok {id} { + audio_apply $id + audio_cancel $id +} + +# callback from popup menu +proc audio_popup_action {buttonname varname devlist index} { + global audio_indevlist audio_outdevlist $varname + $buttonname configure -text [lindex $devlist $index] +# puts stderr [concat popup_action $buttonname $varname $index] + set $varname $index +} + +# create a popup menu +proc audio_popup {name buttonname varname devlist} { + if [winfo exists $name.popup] {destroy $name.popup} + menu $name.popup -tearoff false +# puts stderr [concat $devlist ] + for {set x 0} {$x<[llength $devlist]} {incr x} { + $name.popup add command -label [lindex $devlist $x] \ + -command [list audio_popup_action \ + $buttonname $varname $devlist $x] + } + tk_popup $name.popup [winfo pointerx $name] [winfo pointery $name] 0 +} + +# start a dialog window to select audio devices and settings. "multi" +# is 0 if only one device is allowed; 1 if one apiece may be specified for +# input and output; and 2 if we can select multiple devices. "longform" +# (which only makes sense if "multi" is 2) asks us to make controls for +# opening several devices; if not, we get an extra button to turn longform +# on and restart the dialog. + +proc pdtk_audio_dialog {id indevlist indev1 indev2 indev3 indev4 \ + inchan1 inchan2 inchan3 inchan4 \ + outdevlist outdev1 outdev2 outdev3 outdev4 \ + outchan1 outchan2 outchan3 outchan4 sr advance multi longform} { + global audio_indev1 audio_indev2 audio_indev3 audio_indev4 + global audio_inchan1 audio_inchan2 audio_inchan3 audio_inchan4 + global audio_outdev1 audio_outdev2 audio_outdev3 audio_outdev4 + global audio_outchan1 audio_outchan2 audio_outchan3 audio_outchan4 + global audio_sr audio_advance + global audio_indevlist audio_outdevlist + + set audio_indev1 $indev1 + set audio_indev2 $indev2 + set audio_indev3 $indev3 + set audio_indev4 $indev4 + set audio_inchan1 $inchan1 + set audio_inchan2 $inchan2 + set audio_inchan3 $inchan3 + set audio_inchan4 $inchan4 + set audio_outdev1 $outdev1 + set audio_outdev2 $outdev2 + set audio_outdev3 $outdev3 + set audio_outdev4 $outdev4 + set audio_outchan1 $outchan1 + set audio_outchan2 $outchan2 + set audio_outchan3 $outchan3 + set audio_outchan4 $outchan4 + set audio_sr $sr + set audio_advance $advance + set audio_indevlist $indevlist + set audio_outdevlist $outdevlist + + toplevel $id + wm title $id {audio} + wm protocol $id WM_DELETE_WINDOW [concat audio_cancel $id] + + frame $id.buttonframe + pack $id.buttonframe -side bottom -fill x -pady 2m + button $id.buttonframe.cancel -text {Cancel}\ + -command "audio_cancel $id" + button $id.buttonframe.apply -text {Apply}\ + -command "audio_apply $id" + button $id.buttonframe.ok -text {OK}\ + -command "audio_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 + + # sample rate and advance + frame $id.srf + pack $id.srf -side top + + label $id.srf.l1 -text "sample rate:" + entry $id.srf.x1 -textvariable audio_sr -width 7 + label $id.srf.l2 -text "delay (msec):" + entry $id.srf.x2 -textvariable audio_advance -width 4 + pack $id.srf.l1 $id.srf.x1 $id.srf.l2 $id.srf.x2 -side left + + # input device 1 + frame $id.in1f + pack $id.in1f -side top + + label $id.in1f.l1 -text "input device 1:" + button $id.in1f.x1 -text [lindex $indevlist $audio_indev1] \ + -command [list audio_popup $id $id.in1f.x1 audio_indev1 $indevlist] + label $id.in1f.l2 -text "channels:" + entry $id.in1f.x2 -textvariable audio_inchan1 -width 3 + pack $id.in1f.l1 $id.in1f.x1 $id.in1f.l2 $id.in1f.x2 -side left + + # input device 2 + if {$longform && $multi > 1 && [llength $indevlist] > 1} { + frame $id.in2f + pack $id.in2f -side top + + label $id.in2f.l1 -text "input device 2:" + button $id.in2f.x1 -text [lindex $indevlist $audio_indev2] \ + -command [list audio_popup $id $id.in2f.x1 audio_indev2 $indevlist] + label $id.in2f.l2 -text "channels:" + entry $id.in2f.x2 -textvariable audio_inchan2 -width 3 + pack $id.in2f.l1 $id.in2f.x1 $id.in2f.l2 $id.in2f.x2 -side left + } + + # input device 3 + if {$longform && $multi > 1 && [llength $indevlist] > 2} { + frame $id.in3f + pack $id.in3f -side top + + label $id.in3f.l1 -text "input device 3:" + button $id.in3f.x1 -text [lindex $indevlist $audio_indev3] \ + -command [list audio_popup $id $id.in3f.x1 audio_indev3 $indevlist] + label $id.in3f.l2 -text "channels:" + entry $id.in3f.x2 -textvariable audio_inchan3 -width 3 + pack $id.in3f.l1 $id.in3f.x1 $id.in3f.l2 $id.in3f.x2 -side left + } + + # input device 4 + if {$longform && $multi > 1 && [llength $indevlist] > 3} { + frame $id.in4f + pack $id.in4f -side top + + label $id.in4f.l1 -text "input device 4:" + button $id.in4f.x1 -text [lindex $indevlist $audio_indev4] \ + -command [list audio_popup $id $id.in4f.x1 audio_indev4 $indevlist] + label $id.in4f.l2 -text "channels:" + entry $id.in4f.x2 -textvariable audio_inchan4 -width 3 + pack $id.in4f.l1 $id.in4f.x1 $id.in4f.l2 $id.in4f.x2 -side left + } + + # output device 1 + frame $id.out1f + pack $id.out1f -side top + + if {$multi == 0} { + label $id.out1f.l1 \ + -text "(output device same as input device) .............. " + } else { + label $id.out1f.l1 -text "output device 1:" + button $id.out1f.x1 -text [lindex $outdevlist $audio_outdev1] \ + -command \ + [list audio_popup $id $id.out1f.x1 audio_outdev1 $outdevlist] + } + label $id.out1f.l2 -text "channels:" + entry $id.out1f.x2 -textvariable audio_outchan1 -width 3 + if {$multi == 0} { + pack $id.out1f.l1 $id.out1f.l2 $id.out1f.x2 -side left + } else { + pack $id.out1f.l1 $id.out1f.x1 $id.out1f.l2 $id.out1f.x2 -side left + } + + # output device 2 + if {$longform && $multi > 1 && [llength $indevlist] > 1} { + frame $id.out2f + pack $id.out2f -side top + label $id.out2f.l1 -text "output device 2:" + button $id.out2f.x1 -text [lindex $outdevlist $audio_outdev2] \ + -command \ + [list audio_popup $id $id.out2f.x1 audio_outdev2 $outdevlist] + label $id.out2f.l2 -text "channels:" + entry $id.out2f.x2 -textvariable audio_outchan2 -width 3 + pack $id.out2f.l1 $id.out2f.x1 $id.out2f.l2 $id.out2f.x2 -side left + } + + # output device 3 + if {$longform && $multi > 1 && [llength $indevlist] > 2} { + frame $id.out3f + pack $id.out3f -side top + label $id.out3f.l1 -text "output device 3:" + button $id.out3f.x1 -text [lindex $outdevlist $audio_outdev3] \ + -command \ + [list audio_popup $id $id.out3f.x1 audio_outdev3 $outdevlist] + label $id.out3f.l2 -text "channels:" + entry $id.out3f.x2 -textvariable audio_outchan3 -width 3 + pack $id.out3f.l1 $id.out3f.x1 $id.out3f.l2 $id.out3f.x2 -side left + } + + # output device 4 + if {$longform && $multi > 1 && [llength $indevlist] > 3} { + frame $id.out4f + pack $id.out4f -side top + label $id.out4f.l1 -text "output device 4:" + button $id.out4f.x1 -text [lindex $outdevlist $audio_outdev4] \ + -command \ + [list audio_popup $id $id.out4f.x1 audio_outdev4 $outdevlist] + label $id.out4f.l2 -text "channels:" + entry $id.out4f.x2 -textvariable audio_outchan4 -width 3 + pack $id.out4f.l1 $id.out4f.x1 $id.out4f.l2 $id.out4f.x2 -side left + } + + # if not the "long form" but if "multi" is 2, make a button to + # restart with longform set. + + if {$longform == 0 && $multi > 1} { + frame $id.longbutton + pack $id.longbutton -side top + button $id.longbutton.b -text {use multiple devices} \ + -command {pd pd audio-properties 1 \;} + pack $id.longbutton.b + } + bind $id.srf.x1 [concat audio_ok $id] + bind $id.srf.x2 [concat audio_ok $id] + bind $id.in1f.x2 [concat audio_ok $id] + $id.srf.x1 select from 0 + $id.srf.x1 select adjust end + focus $id.srf.x1 +} + +####################### midi dialog ##################3 + +proc midi_apply {id} { + global midi_indev1 midi_indev2 midi_indev3 midi_indev4 + global midi_outdev1 midi_outdev2 midi_outdev3 midi_outdev4 + + pd [concat pd midi-dialog \ + $midi_indev1 \ + $midi_indev2 \ + $midi_indev3 \ + $midi_indev4 \ + $midi_outdev1 \ + $midi_outdev2 \ + $midi_outdev3 \ + $midi_outdev4 \ + \;] +} + +proc midi_cancel {id} { + pd [concat $id cancel \;] +} + +proc midi_ok {id} { + midi_apply $id + midi_cancel $id +} + +# callback from popup menu +proc midi_popup_action {buttonname varname devlist index} { + global midi_indevlist midi_outdevlist $varname + $buttonname configure -text [lindex $devlist $index] +# puts stderr [concat popup_action $buttonname $varname $index] + set $varname $index +} + +# create a popup menu +proc midi_popup {name buttonname varname devlist} { + if [winfo exists $name.popup] {destroy $name.popup} + menu $name.popup -tearoff false +# puts stderr [concat $devlist ] + for {set x 0} {$x<[llength $devlist]} {incr x} { + $name.popup add command -label [lindex $devlist $x] \ + -command [list midi_popup_action \ + $buttonname $varname $devlist $x] + } + tk_popup $name.popup [winfo pointerx $name] [winfo pointery $name] 0 +} + +# start a dialog window to select midi devices. "longform" asks us to make +# controls for opening several devices; if not, we get an extra button to +# turn longform on and restart the dialog. + +proc pdtk_midi_dialog {id indevlist indev1 indev2 indev3 indev4 \ + outdevlist outdev1 outdev2 outdev3 outdev4 longform} { + global midi_indev1 midi_indev2 midi_indev3 midi_indev4 + global midi_outdev1 midi_outdev2 midi_outdev3 midi_outdev4 + global midi_indevlist midi_outdevlist + + set midi_indev1 $indev1 + set midi_indev2 $indev2 + set midi_indev3 $indev3 + set midi_indev4 $indev4 + set midi_outdev1 $outdev1 + set midi_outdev2 $outdev2 + set midi_outdev3 $outdev3 + set midi_outdev4 $outdev4 + set midi_indevlist $indevlist + set midi_outdevlist $outdevlist + + toplevel $id + wm title $id {midi} + wm protocol $id WM_DELETE_WINDOW [concat midi_cancel $id] + + frame $id.buttonframe + pack $id.buttonframe -side bottom -fill x -pady 2m + button $id.buttonframe.cancel -text {Cancel}\ + -command "midi_cancel $id" + button $id.buttonframe.apply -text {Apply}\ + -command "midi_apply $id" + button $id.buttonframe.ok -text {OK}\ + -command "midi_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 + + # input device 1 + frame $id.in1f + pack $id.in1f -side top + + label $id.in1f.l1 -text "input device 1:" + button $id.in1f.x1 -text [lindex $indevlist $midi_indev1] \ + -command [list midi_popup $id $id.in1f.x1 midi_indev1 $indevlist] + pack $id.in1f.l1 $id.in1f.x1 -side left + + # input device 2 + if {$longform && [llength $indevlist] > 2} { + frame $id.in2f + pack $id.in2f -side top + + label $id.in2f.l1 -text "input device 2:" + button $id.in2f.x1 -text [lindex $indevlist $midi_indev2] \ + -command [list midi_popup $id $id.in2f.x1 midi_indev2 $indevlist] + pack $id.in2f.l1 $id.in2f.x1 -side left + } + + # input device 3 + if {$longform && [llength $indevlist] > 3} { + frame $id.in3f + pack $id.in3f -side top + + label $id.in3f.l1 -text "input device 3:" + button $id.in3f.x1 -text [lindex $indevlist $midi_indev3] \ + -command [list midi_popup $id $id.in3f.x1 midi_indev3 $indevlist] + pack $id.in3f.l1 $id.in3f.x1 -side left + } + + # input device 4 + if {$longform && [llength $indevlist] > 4} { + frame $id.in4f + pack $id.in4f -side top + + label $id.in4f.l1 -text "input device 4:" + button $id.in4f.x1 -text [lindex $indevlist $midi_indev4] \ + -command [list midi_popup $id $id.in4f.x1 midi_indev4 $indevlist] + pack $id.in4f.l1 $id.in4f.x1 -side left + } + + # output device 1 + + frame $id.out1f + pack $id.out1f -side top + label $id.out1f.l1 -text "output device 1:" + button $id.out1f.x1 -text [lindex $outdevlist $midi_outdev1] \ + -command [list midi_popup $id $id.out1f.x1 midi_outdev1 $outdevlist] + pack $id.out1f.l1 $id.out1f.x1 -side left + + # output device 2 + if {$longform && [llength $indevlist] > 2} { + frame $id.out2f + pack $id.out2f -side top + label $id.out2f.l1 -text "output device 2:" + button $id.out2f.x1 -text [lindex $outdevlist $midi_outdev2] \ + -command \ + [list midi_popup $id $id.out2f.x1 midi_outdev2 $outdevlist] + pack $id.out2f.l1 $id.out2f.x1 -side left + } + + # output device 3 + if {$longform && [llength $indevlist] > 3} { + frame $id.out3f + pack $id.out3f -side top + label $id.out3f.l1 -text "output device 3:" + button $id.out3f.x1 -text [lindex $outdevlist $midi_outdev3] \ + -command \ + [list midi_popup $id $id.out3f.x1 midi_outdev3 $outdevlist] + pack $id.out3f.l1 $id.out3f.x1 -side left + } + + # output device 4 + if {$longform && [llength $indevlist] > 4} { + frame $id.out4f + pack $id.out4f -side top + label $id.out4f.l1 -text "output device 4:" + button $id.out4f.x1 -text [lindex $outdevlist $midi_outdev4] \ + -command \ + [list midi_popup $id $id.out4f.x1 midi_outdev4 $outdevlist] + pack $id.out4f.l1 $id.out4f.x1 -side left + } + + # if not the "long form" make a button to + # restart with longform set. + + if {$longform == 0} { + frame $id.longbutton + pack $id.longbutton -side top + button $id.longbutton.b -text {use multiple devices} \ + -command {pd pd midi-properties 1 \;} + pack $id.longbutton.b + } +} + +############ pdtk_path_dialog -- dialog window for search path ######### + +proc path_apply {id} { + global pd_path0 pd_path1 pd_path2 pd_path3 pd_path4 + global pd_path5 pd_path6 pd_path7 pd_path8 pd_path9 + + pd [concat pd path-dialog \ + $pd_path0 $pd_path1 $pd_path2 $pd_path3 $pd_path4 \ + $pd_path5 $pd_path6 $pd_path7 $pd_path8 $pd_path9 \ + \;] +} + +proc path_cancel {id} { + pd [concat $id cancel \;] +} + +proc path_ok {id} { + path_apply $id + path_cancel $id +} +set pd_path0 sdfgh + +proc pdtk_path_dialog {id} { + global pd_path0 pd_path1 pd_path2 pd_path3 pd_path4 + global pd_path5 pd_path6 pd_path7 pd_path8 pd_path9 + + toplevel $id + wm title $id {PD search path for patches and other files} + wm protocol $id WM_DELETE_WINDOW [concat path_cancel $id] + + frame $id.buttonframe + pack $id.buttonframe -side bottom -fill x -pady 2m + button $id.buttonframe.cancel -text {Cancel}\ + -command "path_cancel $id" + button $id.buttonframe.apply -text {Apply}\ + -command "path_apply $id" + button $id.buttonframe.ok -text {OK}\ + -command "path_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 + + for {set x 0} {$x < 10} {incr x} { + # input device 1 + entry $id.f$x -textvariable pd_path$x -width 80 + bind $id.f$x [concat path_ok $id] + pack $id.f$x -side top + } + + focus $id.f0 +} + +proc pd_set {var value} { + global $var + set $var $value +} diff --git a/pd/src/u_main.tk.test b/pd/src/u_main.tk.test deleted file mode 100644 index fc32a321..00000000 --- a/pd/src/u_main.tk.test +++ /dev/null @@ -1,2686 +0,0 @@ -set pd_nt 0 -# (The above is 0 for unix, 1 for microsoft, and 2 for Mac OSX. The first -# line is automatically munged by the relevant makefiles.) - -# Copyright (c) 1997-1999 Miller Puckette. -# For information on usage and redistribution, and for a DISCLAIMER OF ALL -# WARRANTIES, see the file, "LICENSE.txt," in this distribution. - -# changed by Thomas Musil 09.2001 -# between "pdtk_graph_dialog -- dialog window for graphs" -# and "pdtk_array_dialog -- dialog window for arrays" -# a new dialogbox was inserted, named: -# "pdtk_iemgui_dialog -- dialog window for iem guis" -# -# there are 2 new features: 1.) line-delete-protection in edit-menue -# -# 2.) there are all iem-guis in a seperated put-gui-menue -# -# all this changes are labeled with #######iemlib########## - -if {$pd_nt == 1} { - global pd_guidir - set pd_gui2 [string range $argv0 0 [expr [string last \\ $argv0 ] - 1]] - regsub -all \\\\ $pd_gui2 / pd_gui3 - set pd_guidir $pd_gui3/.. - load $pd_guidir/bin/pdtcl -} - -if {$pd_nt == 2} { - global pd_guidir - set pd_gui2 [string range $argv0 0 [expr [string last / $argv0 ] - 1]] - set pd_guidir $pd_gui2/.. - load $pd_guidir/bin/pdtcl -} - -# it's unfortunate but we seem to have to turn off global bindings -# for Text objects to get control-s and control-t to do what we want for -# "text" dialogs below. Also we have to get rid of tab's changing the focus. - -bind all "" -bind all "" -bind Text {} -bind Text {} -# puts stderr [bind all] - -################## set up main window ######################### -frame .mbar -relief raised -bd 2 -canvas .dummy -height 1c -width 1c -frame .controls -pack .mbar .controls .dummy -side top -fill x -menubutton .mbar.file -text File -menu .mbar.file.menu -menubutton .mbar.find -text Find -menu .mbar.find.menu -menubutton .mbar.windows -text Windows -menu .mbar.windows.menu -menubutton .mbar.audio -text Audio -menu .mbar.audio.menu -menubutton .mbar.help -text Help -menu .mbar.help.menu -pack .mbar.file .mbar.find .mbar.windows .mbar.audio -side left -pack .mbar.help -side right -menu .mbar.file.menu -menu .mbar.find.menu -menu .mbar.windows.menu -postcommand [concat pdtk_fixwindowmenu] -menu .mbar.audio.menu -menu .mbar.help.menu - -set ctrls_audio_on 0 -set ctrls_meter_on 0 -set ctrls_inlevel 0 -set ctrls_outlevel 0 - -frame .controls.switches -checkbutton .controls.switches.audiobutton -text {compute audio} \ - -variable ctrls_audio_on \ - -anchor w \ - -command {pd [concat pd dsp $ctrls_audio_on \;]} - -checkbutton .controls.switches.meterbutton -text {peak meters} \ - -variable ctrls_meter_on \ - -anchor w \ - -command {pd [concat pd meters $ctrls_meter_on \;]} - -pack .controls.switches.meterbutton .controls.switches.audiobutton -side left - -frame .controls.in -label .controls.in.label -text IN -entry .controls.in.level -textvariable ctrls_inlevel -width 3 -button .controls.in.clip -text {CLIP} -state disabled -pack .controls.in.label .controls.in.level .controls.in.clip -side top - -frame .controls.out -label .controls.out.label -text OUT -entry .controls.out.level -textvariable ctrls_outlevel -width 3 -button .controls.out.clip -text {CLIP} -state disabled -pack .controls.out.label .controls.out.level .controls.out.clip -side top - -button .controls.dio -text "DIO\nerrors" \ - -command {pd [concat pd audiostatus \;]} - -pack .controls.switches -side bottom -pack .controls.in .controls.out -side left -pack .controls.dio -side right - -bind . {pdtk_pd_ctrlkey %W %K 0} -bind . {pdtk_pd_ctrlkey %W %K 1} - - -############### set up global variables ################################ - -set untitled_number 1 -set untitled_directory [pwd] -set saveas_client doggy -set pd_opendir $untitled_directory -############iemlib################## -# need it to know, if new or open file -set iem_new_open_flag "open" -############iemlib################## - -################ utility functions ######################### - -proc pdtk_enquote {x} { - set foo [string map {"," "" ";" "" \" ""} $x] - set foo2 [string map {" " "\\ "} $foo] - concat $foo2 -} - -proc pdtk_debug {x} { - tk_messageBox -message $x -type ok -} - -proc pdtk_watchdog {} { - pd [concat pd ping \;] - after 2000 {pdtk_watchdog} -} - -proc pdtk_check {x message} { - set answer [tk_messageBox \-message $x \-type yesno \-icon question] - switch $answer { - yes {pd $message} } -# no {tk_messageBox \-message "cancelled" \-type ok} -} - -set menu_windowlist {} - -proc pdtk_fixwindowmenu {} { - global menu_windowlist - .mbar.windows.menu delete 0 end - foreach i $menu_windowlist { - .mbar.windows.menu add command -label [lindex $i 0] \ - -command [concat menu_domenuwindow [lindex $i 1]] - } -} - -############### the "New" menu command ######################## -proc menu_new {} { - global untitled_number - global untitled_directory -############iemlib################## - global iem_new_open_flag - - set iem_new_open_flag "new" -############iemlib################## - pd [concat pd filename Untitled-$untitled_number $untitled_directory \;] - pd { - #N canvas; - #X pop 1; - } - set untitled_number [expr $untitled_number + 1] -} - -################## the "Open" menu command ######################### - -proc menu_open {} { - global pd_opendir - global pd_nt -############iemlib################## - global iem_new_open_flag - - set iem_new_open_flag "open" -############iemlib################## - -# workaround -- initialdir doesn't work on MACOSX yet --- - if {$pd_nt == 2} { - cd $pd_opendir - set filename [tk_getOpenFile -defaultextension .pd \ - -filetypes { {{pd files} {.pd}} {{max files} {.pat}}} ] - } else { - set filename [tk_getOpenFile -defaultextension .pd \ - -filetypes { {{pd files} {.pd}} {{max files} {.pat}}} \ - -initialdir $pd_opendir] - } -# puts stderr $filename - if {$filename != ""} { - set directory [string range $filename 0 \ - [expr [string last / $filename ] - 1]] - set pd_opendir $directory - set basename [string range $filename \ - [expr [string last / $filename ] + 1] end] - -# pd_debug [concat file $filename base $basename dir $directory] - - pd [concat pd open [pdtk_enquote $basename] \ - [pdtk_enquote $directory]\;] - } -} - -################## the "Message" menu command ######################### -proc menu_send {} { - toplevel .sendpanel - entry .sendpanel.entry -textvariable send_textvariable - pack .sendpanel.entry -side bottom -fill both -ipadx 100 - .sendpanel.entry select from 0 - .sendpanel.entry select adjust end - bind .sendpanel.entry { - pd [concat $send_textvariable \;] - after 50 {destroy .sendpanel} - } - focus .sendpanel.entry -} - -################## the "Quit" menu command ######################### -proc menu_really_quit {} {pd {pd quit;}} - -proc menu_quit {} {pdtk_check {Really quit?} {pd quit;}} - -######### the "Pd" menu command, which puts the Pd window on top ######## -proc menu_pop_pd {} {raise .} - -######### the "audio" menu command ############### -proc menu_audio {flag} {pd [concat pd dsp $flag \;]} - -######### the "documentation" menu command ############### - -set doc_number 1 - -proc menu_opentext {filename} { - global doc_number - global pd_guidir - global pd_myversion - set name [format ".help%d" $doc_number] - toplevel $name - text $name.text -relief raised -bd 2 -font fixed \ - -yscrollcommand "$name.scroll set" -background white - scrollbar $name.scroll -command "$name.text yview" - pack $name.scroll -side right -fill y - pack $name.text -side left -fill both -expand 1 - - set f [open $filename] - while {![eof $f]} { - set bigstring [read $f 1000] - regsub -all PD_BASEDIR $bigstring $pd_guidir bigstring2 - regsub -all PD_VERSION $bigstring2 $pd_myversion bigstring3 - $name.text insert end $bigstring3 - } - close $f - set doc_number [expr $doc_number + 1] -} - -set help_directory $pd_guidir/doc - -proc menu_documentation {} { - global help_directory - global pd_nt -############iemlib################## - global iem_new_open_flag - - set iem_new_open_flag "open" -############iemlib################## - - if {$pd_nt == 2} { - cd $help_directory - set filename [tk_getOpenFile -defaultextension .pd \ - -filetypes { {{documentation} {.pd .txt .htm}} } ] - } else { - set filename [tk_getOpenFile -defaultextension .pd \ - -filetypes { {{documentation} {.pd .txt .htm}} } \ - -initialdir $help_directory] - } - - if {$filename != ""} { - if {[string first .txt $filename] >= 0} { - menu_opentext $filename - } elseif {[string first .htm $filename] >= 0} { - if {$pd_nt == 0} { -#I wish I could get this to run in the background; the "&" doesn't do it: - exec sh -c \ - [format "mozilla file:%s || netscape file:%s &\n" \ - $filename $filename] - } else { - tk_messageBox -message \ - {sorry -- can't open htm files yet; open this manually} \ - -type ok - } - } else { - set help_directory [string range $filename 0 \ - [expr [string last / $filename ] - 1]] - set basename [string range $filename \ - [expr [string last / $filename ] + 1] end] - pd [concat pd open [pdtk_enquote $basename] \ - [pdtk_enquote $help_directory] \;] - } - } -} - -proc menu_doc_open {subdir basename} { - global pd_guidir -############iemlib################## - global iem_new_open_flag - - set iem_new_open_flag "open" -############iemlib################## - - set dirname $pd_guidir/$subdir - - if {[string first .txt $basename] >= 0} { - menu_opentext $dirname/$basename - } else { - pd [concat pd open [pdtk_enquote $basename] \ - [pdtk_enquote $dirname] \;] - } -} - -#################### the "File" menu for the Pd window ############## -.mbar.file.menu add command -label New -command {menu_new} \ - -accelerator "Ctrl+n" -.mbar.file.menu add command -label Open -command {menu_open} \ - -accelerator "Ctrl+o" -.mbar.file.menu add command -label Message -command {menu_send} \ - -accelerator "Ctrl+m" -.mbar.file.menu add separator -.mbar.file.menu add command -label Quit -command {menu_quit} \ - -accelerator "Ctrl+q" - -#################### the "Find" menu for the Pd window ############## -.mbar.find.menu add command -label {last error?} -command {menu_finderror} - -#################### the "Audio" menu for the Pd window ############## -.mbar.audio.menu add command -label On -accelerator "Ctrl+/" \ - -command {menu_audio 1} -.mbar.audio.menu add command -label Off -accelerator "Ctrl+." \ - -command {menu_audio 0} - -#################### the "Help" menu for the Pd window ############## -.mbar.help.menu add command -label {About Pd} \ - -command {menu_doc_open doc/1.manual 1.introduction.txt} -.mbar.help.menu add command -label {Test Audio and MIDI} \ - -command {menu_doc_open doc/7.stuff/tools testtone.pd} -.mbar.help.menu add command -label {Load Meter} \ - -command {menu_doc_open doc/7.stuff/tools load-meter.pd} -.mbar.help.menu add command -label {Pure Documentation...} \ - -command {menu_documentation} - -########### functions for menu functions on document windows ######## - -proc menu_save {name} { - pdtk_canvas_checkgeometry $name - pd [concat $name menusave \;] -} - -proc menu_saveas {name} { - pdtk_canvas_checkgeometry $name - pd [concat $name menusaveas \;] -} - -proc menu_print {name} { - $name.c postscript -file x.ps -} - -proc menu_close {name} { - pd [concat $name menuclose \;] -} - -proc menu_cut {name} { - pd [concat $name cut \;] -} - -proc menu_copy {name} { - pd [concat $name copy \;] -} - -proc menu_paste {name} { - pd [concat $name paste \;] -} - -proc menu_duplicate {name} { - pd [concat $name duplicate \;] -} - -proc menu_selectall {name} { - pd [concat $name selectall \;] -} - -proc menu_texteditor {name} { - pd [concat $name texteditor \;] -} - -proc menu_font {name} { - pd [concat $name menufont \;] -} - -proc menu_tidyup {name} { - pd [concat $name tidy \;] -} - -proc menu_editmode {name} { - pd [concat $name editmode 0 \;] -} - -proc menu_object {name accel} { - pd [concat $name obj $accel \;] -} - -proc menu_message {name accel} { - pd [concat $name msg $accel \;] -} - -proc menu_floatatom {name accel} { - pd [concat $name floatatom $accel \;] -} - -proc menu_symbolatom {name accel} { - pd [concat $name symbolatom $accel \;] -} - -proc menu_comment {name accel} { - pd [concat $name text $accel \;] -} - -proc menu_graph {name} { - pd [concat $name graph \;] -} - -proc menu_array {name} { - pd [concat $name menuarray \;] -} - -############iemlib################## -proc menu_bng {name accel} { - pd [concat $name bng $accel \;] -} - -proc menu_toggle {name accel} { - pd [concat $name toggle $accel \;] -} - -proc menu_numbox {name accel} { - pd [concat $name numbox $accel \;] -} - -proc menu_vslider {name accel} { - pd [concat $name vslider $accel \;] -} - -proc menu_hslider {name accel} { - pd [concat $name hslider $accel \;] -} - -proc menu_hdial {name accel} { - pd [concat $name hdial $accel \;] -} - -proc menu_vdial {name accel} { - pd [concat $name vdial $accel \;] -} - -proc menu_vumeter {name accel} { - pd [concat $name vumeter $accel \;] -} - -proc menu_mycnv {name accel} { - pd [concat $name mycnv $accel \;] -} - -proc menu_protectmode {name} { - pd [concat $name protectmode 0 \;] -} - -############iemlib################## - -proc menu_windowparent {name} { - pd [concat $name findparent \;] -} - -proc menu_findagain {name} { - pd [concat $name findagain \;] -} - -proc menu_finderror {} { - pd [concat pd finderror \;] -} - -proc menu_domenuwindow {i} { - raise $i -} - -proc menu_fixwindowmenu {name} { - global menu_windowlist - $name.m.windows.m add command - $name.m.windows.m delete 4 end - foreach i $menu_windowlist { - $name.m.windows.m add command -label [lindex $i 0] \ - -command [concat menu_domenuwindow [lindex $i 1]] - } -} - -################## the "find" menu item ################### - -set find_canvas nobody -set find_string "" -set find_count 1 - -proc find_apply {name} { - global find_string - global find_canvas - regsub -all \; $find_string " _semi_ " find_string2 - regsub -all \, $find_string2 " _comma_ " find_string3 -# puts stderr [concat $find_canvas find $find_string3 \ -# \;] - pd [concat $find_canvas find $find_string3 \ - \;] - after 50 destroy $name -} - -proc find_cancel {name} { - after 50 destroy $name -} - -proc menu_findobject {canvas} { - global find_string - global find_canvas - global find_count - - set name [format ".find%d" $find_count] - set find_count [expr $find_count + 1] - - set find_canvas $canvas - - toplevel $name - - label $name.label -text {find...} - pack $name.label -side top - - entry $name.entry -textvariable find_string - pack $name.entry -side top - - frame $name.buttonframe - pack $name.buttonframe -side bottom -fill x -pady 2m - button $name.buttonframe.cancel -text {Cancel}\ - -command "find_cancel $name" - button $name.buttonframe.ok -text {OK}\ - -command "find_apply $name" - pack $name.buttonframe.cancel -side left -expand 1 - pack $name.buttonframe.ok -side left -expand 1 - - $name.entry select from 0 - $name.entry select adjust end - bind $name.entry [ concat find_apply $name] - focus $name.entry -} - - -############# pdtk_canvas_new -- create a new canvas ############### -proc pdtk_canvas_new {name width height geometry} { - global pd_opendir - global iem_new_open_flag - - toplevel $name - frame $name.m -relief raised -bd 2 -# puts stderr [concat geometry: $geometry] - wm geometry $name $geometry - canvas $name.c -width $width -height $height -background white \ - -yscrollcommand "$name.scrollvert set" \ - -xscrollcommand "$name.scrollhort set" \ - -scrollregion [concat 0 0 $width $height] - - scrollbar $name.scrollvert -command "$name.c yview" - scrollbar $name.scrollhort -command "$name.c xview" \ - -orient horizontal - - pack $name.m -side top -fill x - pack $name.scrollhort -side bottom -fill x - pack $name.scrollvert -side right -fill y - pack $name.c -side left -expand 1 -fill both - wm minsize $name 1 1 - wm geometry $name $geometry - -# the file menu - - menubutton $name.m.file -text File -menu $name.m.file.m - pack $name.m.file -side left - menu $name.m.file.m - - $name.m.file.m add command -label New -command {menu_new} \ - -accelerator "Ctrl+n" - - $name.m.file.m add command -label Open -command {menu_open} \ - -accelerator "Ctrl+o" - - $name.m.file.m add command -label Message -command {menu_send} \ - -accelerator "Ctrl+m" - - $name.m.file.m add separator - $name.m.file.m add command -label Save -command [concat menu_save $name] \ - -accelerator "Ctrl+s" - - $name.m.file.m add command -label Close \ - -command [concat menu_close $name] \ - -accelerator "Ctrl+w" - - $name.m.file.m add command -label "Save as..." \ - -command [concat menu_saveas $name] \ - -accelerator "Ctrl+S" - - $name.m.file.m add command -label Print -command [concat menu_print $name] \ - -accelerator "Ctrl+p" - - $name.m.file.m add separator - - $name.m.file.m add command -label Quit -command {menu_quit} \ - -accelerator "Ctrl+q" - -# the edit menu - menubutton $name.m.edit -text Edit -menu $name.m.edit.m - pack $name.m.edit -side left - menu $name.m.edit.m - - - $name.m.edit.m add command -label Cut -command [concat menu_cut $name] \ - -accelerator "Ctrl+x" - - $name.m.edit.m add command -label Copy -command [concat menu_copy $name] \ - -accelerator "Ctrl+c" - - $name.m.edit.m add command -label Paste \ - -command [concat menu_paste $name] \ - -accelerator "Ctrl+v" - - $name.m.edit.m add command -label Duplicate \ - -command [concat menu_duplicate $name] \ - -accelerator "Ctrl+d" - - $name.m.edit.m add command -label {Select all} \ - -command [concat menu_selectall $name] \ - -accelerator "Ctrl+a" - - $name.m.edit.m add command -label {Text Editor} \ - -command [concat menu_texteditor $name] \ - -accelerator "Ctrl+t" - - $name.m.edit.m add command -label Font \ - -command [concat menu_font $name] - - $name.m.edit.m add command -label {Tidy Up} \ - -command [concat menu_tidyup $name] - - $name.m.edit.m add separator - -############iemlib################## -# instead of "red = #BC3C60" we take "grey85", so there is no difference, -# if widget is selected or not. - - $name.m.edit.m add checkbutton -label "Edit mode" \ - -indicatoron true -selectcolor grey85 \ - -command [concat menu_editmode $name] \ - -accelerator "Ctrl+e" - - - - $name.m.edit.m add checkbutton -label "Protect" \ - -indicatoron true -selectcolor grey85 \ - -command [concat menu_protectmode $name] \ - -accelerator "Ctrl+r" - - if { $iem_new_open_flag == "open" } { - $name.m.edit.m entryconfigure "Edit mode" -indicatoron false } - $name.m.edit.m entryconfigure "Protect" -indicatoron false - -############iemlib################## - -# the put menu - menubutton $name.m.put -text Put -menu $name.m.put.m - pack $name.m.put -side left - menu $name.m.put.m - - $name.m.put.m add command -label Object \ - -command [concat menu_object $name 0] \ - -accelerator "Ctrl+1" - - $name.m.put.m add command -label Message \ - -command [concat menu_message $name 0] \ - -accelerator "Ctrl+2" - - $name.m.put.m add command -label Number \ - -command [concat menu_floatatom $name 0] \ - -accelerator "Ctrl+3" - - $name.m.put.m add command -label Symbol \ - -command [concat menu_symbolatom $name 0] \ - -accelerator "Ctrl+4" - - $name.m.put.m add command -label Comment \ - -command [concat menu_comment $name 0] \ - -accelerator "Ctrl+5" - -############iemlib################## - - $name.m.put.m add command -label Bang \ - -command [concat menu_bng $name 0] \ - -accelerator "Alt+b" - - $name.m.put.m add command -label Toggle \ - -command [concat menu_toggle $name 0] \ - -accelerator "Alt+t" - - $name.m.put.m add command -label Number2 \ - -command [concat menu_numbox $name 0] \ - -accelerator "Alt+n" - - $name.m.put.m add command -label Vslider \ - -command [concat menu_vslider $name 0] \ - -accelerator "Alt+v" - - $name.m.put.m add command -label Hslider \ - -command [concat menu_hslider $name 0] \ - -accelerator "Alt+h" - - $name.m.put.m add command -label Vdial \ - -command [concat menu_vdial $name 0] \ - -accelerator "Alt+d" - - $name.m.put.m add command -label Hdial \ - -command [concat menu_hdial $name 0] \ - -accelerator "Alt+i" - - $name.m.put.m add command -label VU \ - -command [concat menu_vumeter $name 0] \ - -accelerator "Alt+u" - - $name.m.put.m add command -label Canvas \ - -command [concat menu_mycnv $name 0] \ - -accelerator "Alt+c" - -############iemlib################## - - $name.m.put.m add command -label Graph \ - -command [concat menu_graph $name] - - $name.m.put.m add command -label Array \ - -command [concat menu_array $name] - - - -# the find menu - menubutton $name.m.find -text Find -menu $name.m.find.m - pack $name.m.find -side left - menu $name.m.find.m - $name.m.find.m add command -label {Find...} -accelerator "Ctrl+f" \ - -command [concat menu_findobject $name] - $name.m.find.m add command -label {Find Again} -accelerator "Ctrl+g" \ - -command [concat menu_findagain $name] - $name.m.find.m add command -label {Find last error} \ - -command [concat menu_finderror] - -# the window menu - menubutton $name.m.windows -text Windows -menu $name.m.windows.m - pack $name.m.windows -side left - menu $name.m.windows.m -postcommand [concat menu_fixwindowmenu $name] - $name.m.windows.m add command -label {parent window}\ - -command [concat menu_windowparent $name] - $name.m.windows.m add command -label {Pd window} -command menu_pop_pd - $name.m.windows.m add separator - -# the audio menu - menubutton $name.m.audio -text Audio -menu $name.m.audio.m - pack $name.m.audio -side left - menu $name.m.audio.m - $name.m.audio.m add command -label On -accelerator "Ctrl+/" \ - -command {menu_audio 1} - $name.m.audio.m add command -label Off -accelerator "Ctrl+." \ - -command {menu_audio 0} - -# the help menu - menubutton $name.m.help -text Help -menu $name.m.help.m - pack $name.m.help -side right - menu $name.m.help.m - $name.m.help.m add command -label {Getting Started} \ - -command {menu_doc_open doc/1.manual 1.introduction.txt} - $name.m.help.m add command -label {Test Audio and MIDI} \ - -command {menu_doc_open doc/7.stuff/tools testtone.pd} - $name.m.help.m add command -label {Load Meter} \ - -command {menu_doc_open doc/7.stuff/tools load-meter.pd} - $name.m.help.m add command -label {Pure Documentation} \ - -command {menu_documentation} - -# the popup menu - menu $name.popup -tearoff false - $name.popup add command -label {Properties} \ - -command [concat popup_action $name 0] - $name.popup add command -label {Open} \ - -command [concat popup_action $name 1] - $name.popup add command -label {Help} \ - -command [concat popup_action $name 2] - -# WM protocol - wm protocol $name WM_DELETE_WINDOW [concat menu_close $name] - -# bindings. -# this is idiotic -- how do you just sense what mod keys are down and -# pass them on? I can't find it anywhere. -# Here we encode shift as 1, control 2, alt 4, in agreement -# with definitions in g_canvas.c. The third button gets "8" but we don't -# bother with modifiers there. -# We don't handle multiple clicks yet. - - bind $name.c