summaryrefslogtreecommitdiff
path: root/apps/plugins/pdbox/PDa/src/m_sched.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/pdbox/PDa/src/m_sched.c')
-rw-r--r--apps/plugins/pdbox/PDa/src/m_sched.c580
1 files changed, 0 insertions, 580 deletions
diff --git a/apps/plugins/pdbox/PDa/src/m_sched.c b/apps/plugins/pdbox/PDa/src/m_sched.c
index f40f0ff270..9d3bed828a 100644
--- a/apps/plugins/pdbox/PDa/src/m_sched.c
+++ b/apps/plugins/pdbox/PDa/src/m_sched.c
@@ -579,584 +579,4 @@ void sys_exit(void)
579{ 579{
580 sys_quit = 1; 580 sys_quit = 1;
581} 581}
582/* Copyright (c) 1997-1999 Miller Puckette.
583* For information on usage and redistribution, and for a DISCLAIMER OF ALL
584* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
585
586/* scheduling stuff */
587
588#include "m_pd.h"
589#include "m_imp.h"
590#include "s_stuff.h"
591
592 /* LATER consider making this variable. It's now the LCM of all sample
593 rates we expect to see: 32000, 44100, 48000, 88200, 96000. */
594#define TIMEUNITPERSEC (32.*441000.)
595
596
597/* T.Grill - enable PD global thread locking - sys_lock, sys_unlock, sys_trylock functions */
598#define THREAD_LOCKING
599#include "pthread.h"
600
601
602static int sys_quit;
603static t_time sys_time;
604static t_time sys_time_per_msec = TIMEUNITPERSEC / 1000.;
605
606int sys_schedblocksize = DEFDACBLKSIZE;
607int sys_usecsincelastsleep(void);
608int sys_sleepgrain;
609
610typedef void (*t_clockmethod)(void *client);
611
612struct _clock
613{
614 t_time c_settime;
615 void *c_owner;
616 t_clockmethod c_fn;
617 struct _clock *c_next;
618};
619
620t_clock *clock_setlist;
621
622#ifdef UNIX
623#include <unistd.h>
624#endif
625
626t_clock *clock_new(void *owner, t_method fn)
627{
628 t_clock *x = (t_clock *)getbytes(sizeof *x);
629 x->c_settime = -1;
630 x->c_owner = owner;
631 x->c_fn = (t_clockmethod)fn;
632 x->c_next = 0;
633 return (x);
634}
635
636void clock_unset(t_clock *x)
637{
638 if (x->c_settime >= 0)
639 {
640 if (x == clock_setlist) clock_setlist = x->c_next;
641 else
642 {
643 t_clock *x2 = clock_setlist;
644 while (x2->c_next != x) x2 = x2->c_next;
645 x2->c_next = x->c_next;
646 }
647 x->c_settime = -1;
648 }
649}
650
651 /* set the clock to call back at an absolute system time */
652void clock_set(t_clock *x, t_time setticks)
653{
654 if (setticks < sys_time) setticks = sys_time;
655 clock_unset(x);
656 x->c_settime = setticks;
657 if (clock_setlist && clock_setlist->c_settime <= setticks)
658 {
659 t_clock *cbefore, *cafter;
660 for (cbefore = clock_setlist, cafter = clock_setlist->c_next;
661 cbefore; cbefore = cafter, cafter = cbefore->c_next)
662 {
663 if (!cafter || cafter->c_settime > setticks)
664 {
665 cbefore->c_next = x;
666 x->c_next = cafter;
667 return;
668 }
669 }
670 }
671 else x->c_next = clock_setlist, clock_setlist = x;
672}
673
674 /* set the clock to call back after a delay in msec */
675void clock_delay(t_clock *x, t_time delaytime)
676{
677 clock_set(x, sys_time + sys_time_per_msec * delaytime);
678}
679
680 /* get current logical time. We don't specify what units this is in;
681 use clock_gettimesince() to measure intervals from time of this call.
682 This was previously, incorrectly named "clock_getsystime"; the old
683 name is aliased to the new one in m_pd.h. */
684t_time clock_getlogicaltime( void)
685{
686 return (sys_time);
687}
688 /* OBSOLETE NAME */
689t_time clock_getsystime( void) { return (sys_time); }
690
691 /* elapsed time in milliseconds since the given system time */
692t_time clock_gettimesince(t_time prevsystime)
693{
694 return ((sys_time - prevsystime)/sys_time_per_msec);
695}
696
697 /* what value the system clock will have after a delay */
698t_time clock_getsystimeafter(t_time delaytime)
699{
700 return (sys_time + sys_time_per_msec * delaytime);
701}
702
703void clock_free(t_clock *x)
704{
705 clock_unset(x);
706 freebytes(x, sizeof *x);
707}
708
709
710/* the following routines maintain a real-execution-time histogram of the
711various phases of real-time execution. */
712
713static int sys_bin[] = {0, 2, 5, 10, 20, 30, 50, 100, 1000};
714#define NBIN (sizeof(sys_bin)/sizeof(*sys_bin))
715#define NHIST 10
716static int sys_histogram[NHIST][NBIN];
717static t_time sys_histtime;
718static int sched_diddsp, sched_didpoll, sched_didnothing;
719
720static void sys_clearhist( void)
721{
722 unsigned int i, j;
723 for (i = 0; i < NHIST; i++)
724 for (j = 0; j < NBIN; j++) sys_histogram[i][j] = 0;
725 sys_histtime = sys_getrealtime();
726 sched_diddsp = sched_didpoll = sched_didnothing = 0;
727}
728
729void sys_printhist( void)
730{
731 unsigned int i, j;
732 for (i = 0; i < NHIST; i++)
733 {
734 int doit = 0;
735 for (j = 0; j < NBIN; j++) if (sys_histogram[i][j]) doit = 1;
736 if (doit)
737 {
738 post("%2d %8d %8d %8d %8d %8d %8d %8d %8d", i,
739 sys_histogram[i][0],
740 sys_histogram[i][1],
741 sys_histogram[i][2],
742 sys_histogram[i][3],
743 sys_histogram[i][4],
744 sys_histogram[i][5],
745 sys_histogram[i][6],
746 sys_histogram[i][7]);
747 }
748 }
749 post("dsp %d, pollgui %d, nothing %d",
750 sched_diddsp, sched_didpoll, sched_didnothing);
751}
752
753static int sys_histphase;
754
755int sys_addhist(int phase)
756{
757#ifndef FIXEDPOINT
758 int i, j, phasewas = sys_histphase;
759 t_time newtime = sys_getrealtime();
760 int msec = (newtime - sys_histtime) * 1000.;
761 for (j = NBIN-1; j >= 0; j--)
762 {
763 if (msec >= sys_bin[j])
764 {
765 sys_histogram[phasewas][j]++;
766 break;
767 }
768 }
769 sys_histtime = newtime;
770 sys_histphase = phase;
771 return (phasewas);
772#else
773 return 0;
774#endif
775}
776
777#define NRESYNC 20
778
779typedef struct _resync
780{
781 int r_ntick;
782 int r_error;
783} t_resync;
784
785static int oss_resyncphase = 0;
786static int oss_nresync = 0;
787static t_resync oss_resync[NRESYNC];
788
789
790static char *(oss_errornames[]) = {
791"unknown",
792"ADC blocked",
793"DAC blocked",
794"A/D/A sync",
795"data late"
796};
797
798void glob_audiostatus(void)
799{
800 int dev, nresync, nresyncphase, i;
801 nresync = (oss_nresync >= NRESYNC ? NRESYNC : oss_nresync);
802 nresyncphase = oss_resyncphase - 1;
803 post("audio I/O error history:");
804 post("seconds ago\terror type");
805 for (i = 0; i < nresync; i++)
806 {
807 int errtype;
808 if (nresyncphase < 0)
809 nresyncphase += NRESYNC;
810 errtype = oss_resync[nresyncphase].r_error;
811 if (errtype < 0 || errtype > 4)
812 errtype = 0;
813
814 post("%9.2f\t%s",
815 (sched_diddsp - oss_resync[nresyncphase].r_ntick)
816 * ((double)sys_schedblocksize) / sys_dacsr,
817 oss_errornames[errtype]);
818 nresyncphase--;
819 }
820}
821
822static int sched_diored;
823static int sched_dioredtime;
824static int sched_meterson;
825
826void sys_log_error(int type)
827{
828 oss_resync[oss_resyncphase].r_ntick = sched_diddsp;
829 oss_resync[oss_resyncphase].r_error = type;
830 oss_nresync++;
831 if (++oss_resyncphase == NRESYNC) oss_resyncphase = 0;
832 if (type != ERR_NOTHING && !sched_diored &&
833 (sched_diddsp >= sched_dioredtime))
834 {
835 sys_vgui("pdtk_pd_dio 1\n");
836 sched_diored = 1;
837 }
838 sched_dioredtime =
839 sched_diddsp + (int)(sys_dacsr /(double)sys_schedblocksize);
840}
841
842static int sched_lastinclip, sched_lastoutclip,
843 sched_lastindb, sched_lastoutdb;
844
845void glob_ping(t_pd *dummy);
846
847static void sched_pollformeters( void)
848{
849 int inclip, outclip, indb, outdb;
850 static int sched_nextmeterpolltime, sched_nextpingtime;
851
852 /* if there's no GUI but we're running in "realtime", here is
853 where we arrange to ping the watchdog every 2 seconds. */
854#ifdef __linux__
855 if (sys_nogui && sys_hipriority && (sched_diddsp - sched_nextpingtime > 0))
856 {
857 glob_ping(0);
858 /* ping every 2 seconds */
859 sched_nextpingtime = sched_diddsp +
860 (2* sys_dacsr) /(int)sys_schedblocksize;
861 }
862#endif
863
864 if (sched_diddsp - sched_nextmeterpolltime < 0)
865 return;
866 if (sched_diored && (sched_diddsp - sched_dioredtime > 0))
867 {
868 sys_vgui("pdtk_pd_dio 0\n");
869 sched_diored = 0;
870 }
871 if (sched_meterson)
872 {
873 float inmax, outmax;
874 sys_getmeters(&inmax, &outmax);
875 indb = 0.5 + rmstodb(inmax);
876 outdb = 0.5 + rmstodb(outmax);
877 inclip = (inmax > 0.999);
878 outclip = (outmax >= 1.0);
879 }
880 else
881 {
882 indb = outdb = 0;
883 inclip = outclip = 0;
884 }
885 if (inclip != sched_lastinclip || outclip != sched_lastoutclip
886 || indb != sched_lastindb || outdb != sched_lastoutdb)
887 {
888 sys_vgui("pdtk_pd_meters %d %d %d %d\n", indb, outdb, inclip, outclip);
889 sched_lastinclip = inclip;
890 sched_lastoutclip = outclip;
891 sched_lastindb = indb;
892 sched_lastoutdb = outdb;
893 }
894 sched_nextmeterpolltime =
895 sched_diddsp + (int)(sys_dacsr /(double)sys_schedblocksize);
896}
897
898void glob_meters(void *dummy, float f)
899{
900 if (f == 0)
901 sys_getmeters(0, 0);
902 sched_meterson = (f != 0);
903 sched_lastinclip = sched_lastoutclip = sched_lastindb = sched_lastoutdb =
904 -1;
905}
906
907#if 0
908void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv)
909{
910 if (argc) sys_clearhist();
911 else sys_printhist();
912}
913#endif
914
915void dsp_tick(void);
916
917static int sched_usedacs = 1;
918static t_time sched_referencerealtime, sched_referencelogicaltime;
919static t_time sys_time_per_dsp_tick;
920
921void sched_set_using_dacs(int flag)
922{
923 sched_usedacs = flag;
924 if (!flag)
925 {
926 sched_referencerealtime = sys_getrealtime();
927 sched_referencelogicaltime = clock_getlogicaltime();
928 post("schedsetuding");
929 }
930 sys_time_per_dsp_tick = (TIMEUNITPERSEC) *
931 ((double)sys_schedblocksize) / sys_dacsr;
932}
933
934 /* take the scheduler forward one DSP tick, also handling clock timeouts */
935static void sched_tick(t_time next_sys_time)
936{
937 int countdown = 5000;
938 while (clock_setlist && clock_setlist->c_settime < next_sys_time)
939 {
940 t_clock *c = clock_setlist;
941 sys_time = c->c_settime;
942 clock_unset(clock_setlist);
943 outlet_setstacklim();
944 (*c->c_fn)(c->c_owner);
945 if (!countdown--)
946 {
947 countdown = 5000;
948 sys_pollgui();
949 }
950 if (sys_quit)
951 return;
952 }
953 sys_time = next_sys_time;
954 dsp_tick();
955 sched_diddsp++;
956}
957
958/*
959Here is Pd's "main loop." This routine dispatches clock timeouts and DSP
960"ticks" deterministically, and polls for input from MIDI and the GUI. If
961we're left idle we also poll for graphics updates; but these are considered
962lower priority than the rest.
963
964The time source is normally the audio I/O subsystem via the "sys_send_dacs()"
965call. This call returns true if samples were transferred; false means that
966the audio I/O system is still busy with previous transfers.
967*/
968
969void sys_pollmidiqueue( void);
970void sys_initmidiqueue( void);
971
972int m_scheduler_pda( void)
973{
974 int idlecount = 0;
975 sys_time_per_dsp_tick = (TIMEUNITPERSEC) *
976 ((double)sys_schedblocksize) / sys_dacsr;
977
978
979 sys_clearhist();
980 if (sys_sleepgrain < 1000)
981 sys_sleepgrain = sys_schedadvance/4;
982 if (sys_sleepgrain < 100)
983 sys_sleepgrain = 100;
984 else if (sys_sleepgrain > 5000)
985 sys_sleepgrain = 5000;
986 sys_initmidiqueue();
987 while (!sys_quit)
988 {
989 int didsomething = 0;
990 int timeforward;
991
992 sys_addhist(0);
993 waitfortick:
994 if (sched_usedacs)
995 {
996 timeforward = sys_send_dacs();
997 sys_pollgui();
998 }
999 else {
1000 if ((sys_getrealtime() - sched_referencerealtime)
1001 > (t_time)clock_gettimesince(sched_referencelogicaltime)*1000)
1002 timeforward = SENDDACS_YES;
1003 else timeforward = SENDDACS_NO;
1004 if (timeforward == SENDDACS_YES)
1005 sys_microsleep(sys_sleepgrain);
1006 }
1007 if (timeforward != SENDDACS_NO) {
1008 sched_tick(sys_time + sys_time_per_dsp_tick);
1009 }
1010 }
1011 return 0;
1012}
1013
1014
1015int m_scheduler( void)
1016{
1017 int idlecount = 0;
1018 sys_time_per_dsp_tick = (TIMEUNITPERSEC) *
1019 ((double)sys_schedblocksize) / sys_dacsr;
1020
1021#ifdef THREAD_LOCKING
1022 /* T.Grill - lock mutex */
1023 sys_lock();
1024#endif
1025 582
1026 sys_clearhist();
1027 if (sys_sleepgrain < 1000)
1028 sys_sleepgrain = sys_schedadvance/4;
1029 if (sys_sleepgrain < 100)
1030 sys_sleepgrain = 100;
1031 else if (sys_sleepgrain > 5000)
1032 sys_sleepgrain = 5000;
1033 sys_initmidiqueue();
1034 while (!sys_quit)
1035 {
1036 int didsomething = 0;
1037 int timeforward;
1038
1039 sys_addhist(0);
1040 waitfortick:
1041 if (sched_usedacs)
1042 {
1043 timeforward = sys_send_dacs();
1044
1045 /* if dacs remain "idle" for 1 sec, they're hung up. */
1046 if (timeforward != 0)
1047 idlecount = 0;
1048 else
1049 {
1050 idlecount++;
1051 if (!(idlecount & 31))
1052 {
1053 static t_time idletime;
1054 /* on 32nd idle, start a clock watch; every
1055 32 ensuing idles, check it */
1056 if (idlecount == 32)
1057 idletime = sys_getrealtime();
1058 else if (sys_getrealtime() - idletime > 1.)
1059 {
1060 post("audio I/O stuck... closing audio\n");
1061 sys_close_audio();
1062 sched_set_using_dacs(0);
1063 goto waitfortick;
1064 }
1065 }
1066 }
1067 }
1068 else
1069 {
1070 if (1000. * (sys_getrealtime() - sched_referencerealtime)
1071 > clock_gettimesince(sched_referencelogicaltime))
1072 timeforward = SENDDACS_YES;
1073 else timeforward = SENDDACS_NO;
1074 }
1075 sys_setmiditimediff(0, 1e-6 * sys_schedadvance);
1076 sys_addhist(1);
1077 if (timeforward != SENDDACS_NO)
1078 sched_tick(sys_time + sys_time_per_dsp_tick);
1079 if (timeforward == SENDDACS_YES)
1080 didsomething = 1;
1081
1082 sys_addhist(2);
1083 // sys_pollmidiqueue();
1084 if (sys_pollgui())
1085 {
1086 if (!didsomething)
1087 sched_didpoll++;
1088 didsomething = 1;
1089 }
1090 sys_addhist(3);
1091 /* test for idle; if so, do graphics updates. */
1092 if (!didsomething)
1093 {
1094 sched_pollformeters();
1095 sys_reportidle();
1096
1097#ifdef THREAD_LOCKING
1098 /* T.Grill - enter idle phase -> unlock thread lock */
1099 sys_unlock();
1100#endif
1101 if (timeforward != SENDDACS_SLEPT)
1102 sys_microsleep(sys_sleepgrain);
1103#ifdef THREAD_LOCKING
1104 /* T.Grill - leave idle phase -> lock thread lock */
1105 sys_lock();
1106#endif
1107
1108 sys_addhist(5);
1109 sched_didnothing++;
1110
1111 }
1112 }
1113
1114#ifdef THREAD_LOCKING
1115 /* T.Grill - done */
1116 sys_unlock();
1117#endif
1118
1119 return (0);
1120}
1121
1122
1123/* ------------ thread locking ------------------- */
1124/* added by Thomas Grill */
1125
1126#ifdef THREAD_LOCKING
1127static pthread_mutex_t sys_mutex = PTHREAD_MUTEX_INITIALIZER;
1128
1129void sys_lock(void)
1130{
1131 pthread_mutex_lock(&sys_mutex);
1132}
1133
1134void sys_unlock(void)
1135{
1136 pthread_mutex_unlock(&sys_mutex);
1137}
1138
1139int sys_trylock(void)
1140{
1141 return pthread_mutex_trylock(&sys_mutex);
1142}
1143
1144#else
1145
1146void sys_lock(void) {}
1147void sys_unlock(void) {}
1148int sys_trylock(void) {}
1149
1150#endif
1151
1152
1153/* ------------ soft quit ------------------- */
1154/* added by Thomas Grill -
1155 just set the quit flag for the scheduler loop
1156 this is useful for applications using the PD shared library to signal the scheduler to terminate
1157*/
1158
1159void sys_exit(void)
1160{
1161 sys_quit = 1;
1162}