From 0005de02835d836778ce210c480f65b9ea356f3a Mon Sep 17 00:00:00 2001 From: Jonathan Wilkes <jon.w.wilkes@gmail.com> Date: Fri, 3 Jun 2016 17:52:20 -0400 Subject: [PATCH] Vanilla 0.47 backport 12: m_pd.c m_sched.c s_audio.c --- pd/src/m_pd.c | 68 ++++++++++++++++- pd/src/m_sched.c | 195 ++++++++++++++++++++++++++++++----------------- pd/src/s_audio.c | 5 +- 3 files changed, 194 insertions(+), 74 deletions(-) diff --git a/pd/src/m_pd.c b/pd/src/m_pd.c index 054fb5b22..a8811ec49 100644 --- a/pd/src/m_pd.c +++ b/pd/src/m_pd.c @@ -401,7 +401,9 @@ void pd_popsym(t_pd *x) void pd_doloadbang(void) { if (lastpopped) - pd_vmess(lastpopped, gensym("loadbang"), ""); + { + pd_vmess(lastpopped, gensym("loadbang"), "f", LB_LOAD); + } lastpopped = 0; } @@ -442,11 +444,75 @@ void conf_init(void); void glob_init(void); void garray_init(void); +t_pdinstance *pd_this; + +static t_symbol *midi_gensym(const char *prefix, const char *name) +{ + char buf[80]; + strncpy(buf, prefix, 79); + buf[79] = 0; + strncat(buf, name, 79 - strlen(buf)); + return (gensym(buf)); +} + +static t_pdinstance *pdinstance_donew(int useprefix) +{ + t_pdinstance *x = (t_pdinstance *)getbytes(sizeof(t_pdinstance)); + char midiprefix[80]; + if (useprefix) + sprintf(midiprefix, "%p", x); + else midiprefix[0] = 0; + x->pd_systime = 0; + x->pd_clock_setlist = 0; + x->pd_dspchain = 0; + x->pd_dspchainsize = 0; + x->pd_canvaslist = 0; + x->pd_dspstate = 0; + x->pd_midiin_sym = midi_gensym(midiprefix, "#midiin"); + x->pd_sysexin_sym = midi_gensym(midiprefix, "#sysexin"); + x->pd_notein_sym = midi_gensym(midiprefix, "#notein"); + x->pd_ctlin_sym = midi_gensym(midiprefix, "#ctlin"); + x->pd_pgmin_sym = midi_gensym(midiprefix, "#pgmin"); + x->pd_bendin_sym = midi_gensym(midiprefix, "#bendin"); + x->pd_touchin_sym = midi_gensym(midiprefix, "#touchin"); + x->pd_polytouchin_sym = midi_gensym(midiprefix, "#polytouchin"); + x->pd_midiclkin_sym = midi_gensym(midiprefix, "#midiclkin"); + x->pd_midirealtimein_sym = midi_gensym(midiprefix, "#midirealtimein"); + return (x); +} + +EXTERN t_pdinstance *pdinstance_new(void) +{ + return (pdinstance_donew(1)); +} + void pd_init(void) { + if (!pd_this) + pd_this = pdinstance_donew(0); mess_init(); obj_init(); conf_init(); glob_init(); garray_init(); } + +EXTERN void pd_setinstance(t_pdinstance *x) +{ + pd_this = x; +} + +EXTERN void pdinstance_free(t_pdinstance *x) +{ + /* placeholder - LATER free symtab, dsp chain, classes and canvases */ +} + +EXTERN t_canvas *pd_getcanvaslist(void) +{ + return (pd_this->pd_canvaslist); +} + +EXTERN int pd_getdspstate(void) +{ + return (pd_this->pd_dspstate); +} diff --git a/pd/src/m_sched.c b/pd/src/m_sched.c index 981b7d2bd..87b25b08a 100644 --- a/pd/src/m_sched.c +++ b/pd/src/m_sched.c @@ -4,49 +4,45 @@ /* scheduling stuff */ -#include "config.h" - #include "m_pd.h" #include "m_imp.h" #include "s_stuff.h" -#ifdef MSW +#ifdef _WIN32 #include <windows.h> #endif /* LATER consider making this variable. It's now the LCM of all sample rates we expect to see: 32000, 44100, 48000, 88200, 96000. */ -#define TIMEUNITPERSEC (32.*441000.) +#define TIMEUNITPERMSEC (32. * 441.) +#define TIMEUNITPERSECOND (TIMEUNITPERMSEC * 1000.) + +#ifndef THREAD_LOCKING +#define THREAD_LOCKING 1 +#endif -#define THREAD_LOCKING +#if THREAD_LOCKING #include "pthread.h" +#endif #define SYS_QUIT_QUIT 1 #define SYS_QUIT_RESTART 2 static int sys_quit; -double sys_time; -static double sys_time_per_msec = TIMEUNITPERSEC / 1000.; int sys_schedblocksize = DEFDACBLKSIZE; int sys_usecsincelastsleep(void); int sys_sleepgrain; -void sched_reopenmeplease(void) /* request from s_audio for deferred reopen */ -{ - sys_quit = SYS_QUIT_RESTART; -} - typedef void (*t_clockmethod)(void *client); struct _clock { - double c_settime; + double c_settime; /* in TIMEUNITS; <0 if unset */ void *c_owner; t_clockmethod c_fn; struct _clock *c_next; + t_float c_unit; /* >0 if in TIMEUNITS; <0 if in samples */ }; -t_clock *clock_setlist; - #ifdef HAVE_UNISTD_H #include <unistd.h> #endif @@ -58,6 +54,7 @@ t_clock *clock_new(void *owner, t_method fn) x->c_owner = owner; x->c_fn = (t_clockmethod)fn; x->c_next = 0; + x->c_unit = TIMEUNITPERMSEC; return (x); } @@ -65,12 +62,13 @@ void clock_unset(t_clock *x) { if (x->c_settime >= 0) { - if (x == clock_setlist) clock_setlist = x->c_next; + if (x == pd_this->pd_clock_setlist) + pd_this->pd_clock_setlist = x->c_next; else { - t_clock *x2 = clock_setlist; - while (x2 && x2->c_next != x) x2 = x2->c_next; - if (x2) x2->c_next = x->c_next; + t_clock *x2 = pd_this->pd_clock_setlist; + while (x2->c_next != x) x2 = x2->c_next; + x2->c_next = x->c_next; } x->c_settime = -1; } @@ -79,14 +77,16 @@ void clock_unset(t_clock *x) /* set the clock to call back at an absolute system time */ void clock_set(t_clock *x, double setticks) { - if (setticks < sys_time) setticks = sys_time; + if (setticks < pd_this->pd_systime) setticks = pd_this->pd_systime; clock_unset(x); x->c_settime = setticks; - if (clock_setlist && clock_setlist->c_settime <= setticks) + if (pd_this->pd_clock_setlist && + pd_this->pd_clock_setlist->c_settime <= setticks) { t_clock *cbefore, *cafter; - for (cbefore = clock_setlist, cafter = clock_setlist->c_next; - cbefore; cbefore = cafter, cafter = cbefore->c_next) + for (cbefore = pd_this->pd_clock_setlist, + cafter = pd_this->pd_clock_setlist->c_next; + cbefore; cbefore = cafter, cafter = cbefore->c_next) { if (!cafter || cafter->c_settime > setticks) { @@ -96,36 +96,75 @@ void clock_set(t_clock *x, double setticks) } } } - else x->c_next = clock_setlist, clock_setlist = x; + else x->c_next = pd_this->pd_clock_setlist, pd_this->pd_clock_setlist = x; } /* set the clock to call back after a delay in msec */ void clock_delay(t_clock *x, double delaytime) { - clock_set(x, sys_time + sys_time_per_msec * delaytime); + clock_set(x, (x->c_unit > 0 ? + pd_this->pd_systime + x->c_unit * delaytime : + pd_this->pd_systime - (x->c_unit*(TIMEUNITPERSECOND/sys_dacsr)) * delaytime)); +} + + /* set the time unit in msec or (if 'samps' is set) in samples. This + is flagged by setting c_unit negative. If the clock is currently set, + recalculate the delay based on the new unit and reschedule */ +void clock_setunit(t_clock *x, double timeunit, int sampflag) +{ + double timeleft; + if (timeunit <= 0) + timeunit = 1; + /* if no change, return to avoid truncation errors recalculating delay */ + if ((sampflag && (timeunit == -x->c_unit)) || + (!sampflag && (timeunit == x->c_unit * TIMEUNITPERMSEC))) + return; + + /* figure out time left in the units we were in */ + timeleft = (x->c_settime < 0 ? -1 : + (x->c_settime - pd_this->pd_systime)/((x->c_unit > 0)? x->c_unit : + (x->c_unit*(TIMEUNITPERSECOND/sys_dacsr)))); + if (sampflag) + x->c_unit = -timeunit; /* negate to flag sample-based */ + else x->c_unit = timeunit * TIMEUNITPERMSEC; + if (timeleft >= 0) /* reschedule if already set */ + clock_delay(x, timeleft); } /* get current logical time. We don't specify what units this is in; - use clock_gettimesince() to measure intervals from time of this call. - This was previously, incorrectly named "clock_getsystime"; the old - name is aliased to the new one in m_pd.h. */ + use clock_gettimesince() to measure intervals from time of this call. */ double clock_getlogicaltime( void) { - return (sys_time); + return (pd_this->pd_systime); } - /* OBSOLETE NAME */ -double clock_getsystime( void) { return (sys_time); } + + /* OBSOLETE (misleading) function name kept for compatibility */ +double clock_getsystime( void) { return (pd_this->pd_systime); } /* elapsed time in milliseconds since the given system time */ double clock_gettimesince(double prevsystime) { - return ((sys_time - prevsystime)/sys_time_per_msec); + return ((pd_this->pd_systime - prevsystime)/TIMEUNITPERMSEC); +} + + /* elapsed time in units, ala clock_setunit(), since given system time */ +double clock_gettimesincewithunits(double prevsystime, + double units, int sampflag) +{ + /* If in samples, divide TIMEUNITPERSECOND/sys_dacsr first (at + cost of an extra division) since it's probably an integer and if + units == 1 and (sys_time - prevsystime) is an integer number of + DSP ticks, the result will be exact. */ + if (sampflag) + return ((pd_this->pd_systime - prevsystime)/ + ((TIMEUNITPERSECOND/sys_dacsr)*units)); + else return ((pd_this->pd_systime - prevsystime)/(TIMEUNITPERMSEC*units)); } /* what value the system clock will have after a delay */ double clock_getsystimeafter(double delaytime) { - return (sys_time + sys_time_per_msec * delaytime); + return (pd_this->pd_systime + TIMEUNITPERMSEC * delaytime); } void clock_free(t_clock *x) @@ -181,12 +220,12 @@ static int sys_histphase; int sys_addhist(int phase) { - int j, phasewas = sys_histphase; + int i, j, phasewas = sys_histphase; double newtime = sys_getrealtime(); int msec = (newtime - sys_histtime) * 1000.; for (j = NBIN-1; j >= 0; j--) { - if (msec >= sys_bin[j]) + if (msec >= sys_bin[j]) { sys_histogram[phasewas][j]++; break; @@ -220,7 +259,7 @@ static char *(oss_errornames[]) = { void glob_audiostatus(void) { - int nresync, nresyncphase, i; + int dev, nresync, nresyncphase, i; nresync = (oss_nresync >= NRESYNC ? NRESYNC : oss_nresync); nresyncphase = oss_resyncphase - 1; post("audio I/O error history:"); @@ -233,7 +272,7 @@ void glob_audiostatus(void) errtype = oss_resync[nresyncphase].r_error; if (errtype < 0 || errtype > 4) errtype = 0; - + post("%9.2f\t%s", (sched_diddsp - oss_resync[nresyncphase].r_ntick) * ((double)sys_schedblocksize) / sys_dacsr, @@ -274,7 +313,7 @@ static void sched_pollformeters( void) /* if there's no GUI but we're running in "realtime", here is where we arrange to ping the watchdog every 2 seconds. */ -#ifdef __linux__ +#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__GNU__) if (sys_nogui && sys_hipriority && (sched_diddsp - sched_nextpingtime > 0)) { glob_watchdog(0); @@ -284,13 +323,13 @@ static void sched_pollformeters( void) } #endif + if (sched_diddsp - sched_nextmeterpolltime < 0) + return; if (sched_diored && (sched_diddsp - sched_dioredtime > 0)) { - //sys_vgui("pdtk_pd_dio 0\n"); + sys_vgui("pdtk_pd_dio 0\n"); sched_diored = 0; } - if (sched_diddsp - sched_nextmeterpolltime < 0) - return; if (sched_meterson) { t_sample inmax, outmax; @@ -337,10 +376,15 @@ void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv) void dsp_tick(void); -static int sched_useaudio = SCHED_AUDIO_POLL; +static int sched_useaudio = SCHED_AUDIO_NONE; static double sched_referencerealtime, sched_referencelogicaltime; double sys_time_per_dsp_tick; +void sched_reopenmeplease(void) /* request from s_audio for deferred reopen */ +{ + sys_quit = SYS_QUIT_RESTART; +} + void sched_set_using_audio(int flag) { sched_useaudio = flag; @@ -356,21 +400,23 @@ void sched_set_using_audio(int flag) sched_useaudio == SCHED_AUDIO_CALLBACK) post("sorry, can't turn off callbacks yet; restart Pd"); /* not right yet! */ - - sys_time_per_dsp_tick = (TIMEUNITPERSEC) * + + sys_time_per_dsp_tick = (TIMEUNITPERSECOND) * ((double)sys_schedblocksize) / sys_dacsr; + sys_vgui("pdtk_pd_dsp %s\n", flag ? "on" : "off"); } /* take the scheduler forward one DSP tick, also handling clock timeouts */ -void sched_tick(void ) +void sched_tick( void) { - double next_sys_time = sys_time + sys_time_per_dsp_tick; + double next_sys_time = pd_this->pd_systime + sys_time_per_dsp_tick; int countdown = 5000; - while (clock_setlist && clock_setlist->c_settime < next_sys_time) + while (pd_this->pd_clock_setlist && + pd_this->pd_clock_setlist->c_settime < next_sys_time) { - t_clock *c = clock_setlist; - sys_time = c->c_settime; - clock_unset(clock_setlist); + t_clock *c = pd_this->pd_clock_setlist; + pd_this->pd_systime = c->c_settime; + clock_unset(pd_this->pd_clock_setlist); outlet_setstacklim(); (*c->c_fn)(c->c_owner); if (!countdown--) @@ -381,7 +427,7 @@ void sched_tick(void ) if (sys_quit) return; } - sys_time = next_sys_time; + pd_this->pd_systime = next_sys_time; dsp_tick(); sched_diddsp++; } @@ -408,10 +454,10 @@ int (*sys_idlehook)(void); static void m_pollingscheduler( void) { int idlecount = 0; - sys_time_per_dsp_tick = (TIMEUNITPERSEC) * + sys_time_per_dsp_tick = (TIMEUNITPERSECOND) * ((double)sys_schedblocksize) / sys_dacsr; -#ifdef THREAD_LOCKING +#if THREAD_LOCKING sys_lock(); #endif @@ -432,15 +478,15 @@ static void m_pollingscheduler( void) waitfortick: if (sched_useaudio != SCHED_AUDIO_NONE) { -#ifdef THREAD_LOCKING - /* T.Grill - send_dacs may sleep -> - unlock thread lock make that time available +#if THREAD_LOCKING + /* T.Grill - send_dacs may sleep -> + unlock thread lock make that time available - could messaging do any harm while sys_send_dacs is running? */ sys_unlock(); #endif timeforward = sys_send_dacs(); -#ifdef THREAD_LOCKING +#if THREAD_LOCKING /* T.Grill - done */ sys_lock(); #endif @@ -464,7 +510,7 @@ static void m_pollingscheduler( void) idletime = sys_getrealtime(); else if (sys_getrealtime() - idletime > 1.) { - post("audio I/O stuck... closing audio\n"); + error("audio I/O stuck... closing audio\n"); sys_close_audio(); sched_set_using_audio(SCHED_AUDIO_NONE); goto waitfortick; @@ -500,7 +546,7 @@ static void m_pollingscheduler( void) { sched_pollformeters(); sys_reportidle(); -#ifdef THREAD_LOCKING +#if THREAD_LOCKING sys_unlock(); /* unlock while we idle */ #endif /* call externally installed idle function if any. */ @@ -510,7 +556,7 @@ static void m_pollingscheduler( void) if (timeforward != SENDDACS_SLEPT) sys_microsleep(sys_sleepgrain); } -#ifdef THREAD_LOCKING +#if THREAD_LOCKING sys_lock(); #endif sys_addhist(5); @@ -518,7 +564,7 @@ static void m_pollingscheduler( void) } } -#ifdef THREAD_LOCKING +#if THREAD_LOCKING sys_unlock(); #endif } @@ -544,11 +590,19 @@ static void m_callbackscheduler(void) sys_initmidiqueue(); while (!sys_quit) { -#ifdef MSW - Sleep(1000); + double timewas = pd_this->pd_systime; +#ifdef _WIN32 + Sleep(1000); #else sleep(1); #endif + if (pd_this->pd_systime == timewas) + { + sys_lock(); + sys_pollgui(); + sched_tick(); + sys_unlock(); + } if (sys_idlehook) sys_idlehook(); } @@ -564,8 +618,11 @@ int m_mainloop(void) if (sys_quit == SYS_QUIT_RESTART) { sys_quit = 0; - sys_close_audio(); - sys_reopen_audio(); + if (audio_isopen()) + { + sys_close_audio(); + sys_reopen_audio(); + } } } return (0); @@ -573,7 +630,7 @@ int m_mainloop(void) int m_batchmain(void) { - sys_time_per_dsp_tick = (TIMEUNITPERSEC) * + sys_time_per_dsp_tick = (TIMEUNITPERSECOND) * ((double)sys_schedblocksize) / sys_dacsr; while (sys_quit != SYS_QUIT_QUIT) sched_tick(); @@ -582,10 +639,9 @@ int m_batchmain(void) /* ------------ thread locking ------------------- */ -#ifdef THREAD_LOCKING +#if THREAD_LOCKING static pthread_mutex_t sys_mutex = PTHREAD_MUTEX_INITIALIZER; static int sys_mutex_lock = 0; -//#include <stdio.h> void sys_lock(void) { @@ -601,7 +657,6 @@ void sys_lock(void) void sys_unlock(void) { - //fprintf(stderr,"sys_unlock\n"); if (sys_mutex_lock) { int res = pthread_mutex_unlock(&sys_mutex); @@ -624,7 +679,7 @@ int sys_trylock(void) void sys_lock(void) {} void sys_unlock(void) {} -int sys_trylock(void) {} +int sys_trylock(void) {return (1);} #endif diff --git a/pd/src/s_audio.c b/pd/src/s_audio.c index 7ec1c0ef7..0383d54a7 100644 --- a/pd/src/s_audio.c +++ b/pd/src/s_audio.c @@ -1069,8 +1069,7 @@ void alsa_getzeros(int n); void alsa_printstate( void); #endif - /* debugging */ -void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv) +/*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")) @@ -1091,7 +1090,7 @@ void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv) alsa_printstate(); } #endif -} +}*/ /* convert a device name to a (1-based) device number. (Output device if 'output' parameter is true, otherwise input device). Negative on failure. */ -- GitLab