configuring its capacity.
/* -*-c-*-
*
- * $Id: au.c,v 1.1 2002/02/02 19:16:28 mdw Exp $
+ * $Id: au.c,v 1.2 2002/02/02 22:43:50 mdw Exp $
*
* High-level audio subsystem
*
/*----- Revision history --------------------------------------------------*
*
* $Log: au.c,v $
+ * Revision 1.2 2002/02/02 22:43:50 mdw
+ * Provide a decent interface for finding out about the audio cache and
+ * configuring its capacity.
+ *
* Revision 1.1 2002/02/02 19:16:28 mdw
* New audio subsystem.
*
static sym_table au_tab; /* Sample cache, by name */
static const char *au_dir = AUDIODIR; /* Directory containing samples */
static struct { au_data *next, *prev; } au_spare; /* Lists for sample data */
-static size_t au_sz, au_max; /* Size of cached samples */
+static au_cacheinfo cache; /* Cache usage information */
#define AU_SPARE ((au_data*)&au_spare)
#define f_init 1u
static void prune(void)
{
T( trace(T_AU, "au: pruning cache (%lu/%lu)",
- (unsigned long)au_sz, (unsigned long)au_max); )
- while (au_sz > au_max && AU_SPARE->next != AU_SPARE) {
+ (unsigned long)cache.sz_total, (unsigned long)cache.sz_max); )
+ while (cache.sz_total > cache.sz_max && AU_SPARE->next != AU_SPARE) {
au_data *a = AU_SPARE->next;
au_sample *s = a->s;
assert(!a->ref);
AU_SPARE->next = a->next;
a->next->prev = AU_SPARE;
s->a = 0;
- au_sz -= a->sz;
+ cache.sz_spare -= a->sz;
+ cache.sz_total -= a->sz;
+ cache.n_spare--;
+ cache.n_total--;
ausys_free(a);
T( trace(T_AU, "au: ... discarded `%s' (%lu/%lu)", SYM_NAME(s),
- (unsigned long)au_sz, (unsigned long)au_max); )
+ (unsigned long)cache.sz_total, (unsigned long)cache.sz_max); )
}
}
sym_create(&au_tab);
AU_SPARE->next = AU_SPARE->prev = AU_SPARE;
- au_max = max;
+ cache.sz_max = max;
/* --- Initialize the system-specific subsystem --- */
T( trace(T_AU, "au: shutdown ok"); )
}
+/* --- @au_getcacheinfo@ --- *
+ *
+ * Arguments: @au_cacheinfo *c@ = where to put the information
+ *
+ * Returns: ---
+ *
+ * Use: Extracts audio cache information.
+ */
+
+void au_getcacheinfo(au_cacheinfo *c)
+{
+ ausys_lock();
+ *c = cache;
+ ausys_unlock();
+ assert(c->sz_spare + c->sz_queue == c->sz_total);
+ assert(c->n_spare + c->n_queue == c->n_total);
+}
+
+/* --- @au_setcachelimit@ --- *
+ *
+ * Arguments: @size_t max@ = new cache limit
+ *
+ * Returns: ---
+ *
+ * Use: Reconfigures the maximum cache size. This probably isn't
+ * very useful, but it was easy...
+ */
+
+void au_setcachelimit(size_t max)
+{
+ ausys_lock();
+ cache.sz_max = max;
+ prune();
+ ausys_unlock();
+}
+
/* --- @au_find@ --- *
*
* Arguments: @const char *tag@ = sample tag string
a->prev->next = a->next;
a->next->prev = a->prev;
a->next = a->prev = 0;
+ cache.sz_spare -= a->sz;
+ cache.sz_queue += a->sz;
+ cache.n_spare--;
+ cache.n_queue++;
+ cache.hits++;
}
a->ref++;
T( trace(T_AU, "au: reusing sample `%s'", SYM_NAME(s)); )
if ((a = ausys_decode(s, d.buf, d.len)) == 0)
goto fail_0;
- au_sz += a->sz;
a->ref = 1;
a->next = a->prev = 0;
a->s = s;
/* --- Done --- */
ausys_lock();
+ cache.sz_queue += a->sz;
+ cache.sz_total += a->sz;
+ cache.n_queue++;
+ cache.n_total++;
+ cache.misses++;
prune();
ausys_unlock();
goto done;
a->prev = AU_SPARE->prev;
AU_SPARE->prev->next = a;
AU_SPARE->prev = a;
+ cache.sz_queue -= a->sz;
+ cache.sz_spare += a->sz;
+ cache.n_queue--;
+ cache.n_spare++;
T( trace(T_AU, "au: drop last ref to `%s'", SYM_NAME(a->s)); )
prune();
}
/* -*-c-*-
*
- * $Id: au.h,v 1.1 2002/02/02 19:16:28 mdw Exp $
+ * $Id: au.h,v 1.2 2002/02/02 22:43:50 mdw Exp $
*
* Audio handling
*
/*----- Revision history --------------------------------------------------*
*
* $Log: au.h,v $
+ * Revision 1.2 2002/02/02 22:43:50 mdw
+ * Provide a decent interface for finding out about the audio cache and
+ * configuring its capacity.
+ *
* Revision 1.1 2002/02/02 19:16:28 mdw
* New audio subsystem.
*
size_t sz; /* Size of sample file data */
} au_data;
-#define AU_CACHEMAX 0x01000000 /* Maximum resident sample data */
+/* --- Audio cache information --- */
+
+typedef struct au_cacheinfo {
+ size_t sz_max; /* Maximum allowed cache size */
+ size_t sz_total; /* Total size used by samples */
+ size_t sz_spare; /* Size used by `spare' samples */
+ size_t sz_queue; /* Size used by queued samples */
+ unsigned n_total; /* Total number of cached samples */
+ unsigned n_spare; /* Number of `spare' samples */
+ unsigned n_queue; /* Number of queued samples */
+ unsigned long hits; /* Number of cache hits */
+ unsigned long misses; /* Number of cache misses */
+} au_cacheinfo;
+
+#define AU_CACHEMAX 0x01000000 /* Default cache maximum size */
/*----- Functions provided ------------------------------------------------*/
extern void au_shutdown(void);
+/* --- @au_getcacheinfo@ --- *
+ *
+ * Arguments: @au_cacheinfo *c@ = where to put the information
+ *
+ * Returns: ---
+ *
+ * Use: Extracts audio cache information.
+ */
+
+extern void au_getcacheinfo(au_cacheinfo */*c*/);
+
+/* --- @au_setcachelimit@ --- *
+ *
+ * Arguments: @size_t max@ = new cache limit
+ *
+ * Returns: ---
+ *
+ * Use: Reconfigures the maximum cache size. This probably isn't
+ * very useful, but it was easy...
+ */
+
+extern void au_setcachelimit(size_t /*max*/);
+
/* --- @au_find@ --- *
*
* Arguments: @const char *tag@ = sample tag string
/* -*-c-*-
*
- * $Id: rxglue.c,v 1.3 2002/02/02 19:17:41 mdw Exp $
+ * $Id: rxglue.c,v 1.4 2002/02/02 22:43:50 mdw Exp $
*
* REXX glue for C core functionality
*
/*----- Revision history --------------------------------------------------*
*
* $Log: rxglue.c,v $
+ * Revision 1.4 2002/02/02 22:43:50 mdw
+ * Provide a decent interface for finding out about the audio cache and
+ * configuring its capacity.
+ *
* Revision 1.3 2002/02/02 19:17:41 mdw
* New audio subsystem.
*
return (0);
}
+/* --- @AUCACHE([FLAG], [VALUE, ...]@ --- *
+ *
+ * Arguments: @FLAG@ = operation to perform
+ *
+ * Returns: Dependent on operation.
+ *
+ * Use: If @FLAG@ is omitted or `Info', returns audio cache usage
+ * information as words in the following order:
+ *
+ * sz_max Maximum allowed cache size
+ * sz_total Total size used by samples
+ * sz_spare Size used by `spare' samples
+ * sz_queue Size used by queued samples
+ * n_total Total number of cached samples
+ * n_spare Number of `spare' samples
+ * n_queue Number of queued samples
+ * hits Number of cache hits
+ * misses Number of cache misses
+ *
+ * If @FLAG@ is `Max', sets the maximum cache size to the first
+ * @VALUE@ (if set), and returns the old maximum on its own.
+ *
+ * If @FLAG@ is `Usage', returns the `sz_*' items, as a list of
+ * words.
+ *
+ * If @FLAGS@ is `Numbers', returns the `n_*' items, as a list
+ * of words.
+ *
+ * If @FLAGS@ is `Hits', returns `hits' and `misses' as a pair
+ * of words.
+ */
+
+static APIRET APIENTRY rxfn_aucache(const char *fn, ULONG ac, RXSTRING *av,
+ const char *sn, RXSTRING *r)
+{
+ int i = 1;
+ au_cacheinfo c;
+
+ au_getcacheinfo(&c);
+ if (ac < 1 || !av[0].strlength)
+ goto info;
+ switch (av[0].strptr[0]) {
+ case 'i': case 'I': info:
+ rxs_putf(r, "%lu %lu %lu %lu %u %u %u %lu %lu",
+ (unsigned long)c.sz_max, (unsigned long)c.sz_total,
+ (unsigned long)c.sz_spare, (unsigned long)c.sz_queue,
+ c.n_total, c.n_spare, c.n_total, c.hits, c.misses);
+ break;
+ case 'm': case 'M':
+ if (ac > i) {
+ long max;
+ if (rxs_tol(&av[i], &max))
+ return (-1);
+ au_setcachelimit(max);
+ i++;
+ }
+ rxs_putf(r, "%lu", (unsigned long)c.sz_max);
+ break;
+ case 'u': case 'U':
+ rxs_putf(r, "%lu %lu %lu %lu",
+ (unsigned long)c.sz_max, (unsigned long)c.sz_total,
+ (unsigned long)c.sz_spare, (unsigned long)c.sz_queue);
+ break;
+ case 'n': case 'N':
+ rxs_putf(r, "%u %u %u", c.n_total, c.n_spare, c.n_total);
+ break;
+ case 'h': case 'H':
+ rxs_putf(r, "%lu %lu", c.hits, c.misses);
+ break;
+ default:
+ return (-1);
+ }
+ if (i > ac)
+ return (-1);
+ return (0);
+}
+
/* --- @MILLIWAIT(MILLIS)@ --- *
*
* Arguments: @MILLIS@ = how long (in milliseconds) to wait
{ "txready", rxfn_txready },
{ "auplay", rxfn_auplay },
{ "aufetch", rxfn_aufetch },
+ { "aucache", rxfn_aucache },
{ "aunum", rxfn_aunum },
{ "milliwait", rxfn_milliwait },
{ 0, 0 }