[xiph-commits] r9181 - in trunk/speex: . libspeex

jm at motherfish-iii.xiph.org jm at motherfish-iii.xiph.org
Mon Apr 25 01:12:06 PDT 2005


Author: jm
Date: 2005-04-25 01:12:04 -0700 (Mon, 25 Apr 2005)
New Revision: 9181

Modified:
   trunk/speex/configure.ac
   trunk/speex/libspeex/nb_celp.c
   trunk/speex/libspeex/sb_celp.c
   trunk/speex/libspeex/stack_alloc.h
Log:
Autodetection of C99 variable arrays and alloca. The pseudo-stack is only used
if nothing else is available.


Modified: trunk/speex/configure.ac
===================================================================
--- trunk/speex/configure.ac	2005-04-25 07:16:23 UTC (rev 9180)
+++ trunk/speex/configure.ac	2005-04-25 08:12:04 UTC (rev 9181)
@@ -70,7 +70,35 @@
 AC_SUBST(SIZE16)
 AC_SUBST(SIZE32)
 
+AC_MSG_CHECKING(for C99 variable-size arrays)
+AC_TRY_RUN([
+int foo=10;
+int main() {int array[foo];return 0;}
+],
+[has_var_arrays=yes;AC_DEFINE([VAR_ARRAYS], [], [Use C99 variable-size arrays])],
+has_var_arrays=no,
+has_var_arrays=no,
+)
+AC_MSG_RESULT($has_var_arrays)
 
+AC_MSG_CHECKING(for alloca)
+AC_TRY_RUN([
+#include <alloca.h>
+int foo=10;
+int main() {int *array = alloca(foo);return 0;}
+],
+[
+has_alloca=yes;
+if test x$has_var_arrays = "xno" ; then
+AC_DEFINE([USE_ALLOCA], [], [Make use of alloca])
+fi
+],
+has_alloca=no,
+has_alloca=no,
+)
+AC_MSG_RESULT($has_alloca)
+
+
 AC_CHECK_HEADERS(sys/soundcard.h sys/audioio.h)
 
 XIPH_PATH_OGG([src="src"], [src=""])
@@ -95,12 +123,12 @@
 AC_DEFINE_UNQUOTED(SPEEX_MICRO_VERSION, ${SPEEX_MICRO_VERSION}, [Version micro])
 AC_DEFINE_UNQUOTED(SPEEX_EXTRA_VERSION, "${SPEEX_EXTRA_VERSION}", [Version extra])
 
-AC_ARG_ENABLE(wideband, [  --disable-wideband       disable wideband codec],
+AC_ARG_ENABLE(wideband, [  --disable-wideband      Disable wideband codec],
 [if test "$enableval" = no; then
   AC_DEFINE([DISABLE_WIDEBAND], , [Disable wideband codec])
 fi])
 
-AC_ARG_ENABLE(valgrind, [  --enable-valgrind       enable valgrind extra checks],
+AC_ARG_ENABLE(valgrind, [  --enable-valgrind       Enable valgrind extra checks],
 [if test "$enableval" = yes; then
   AC_DEFINE([ENABLE_VALGRIND], , [Enable valgrind extra checks])
 fi])
@@ -116,12 +144,12 @@
   AC_DEFINE([FIXED_POINT], , [Compile as fixed-point])
 fi])
 
-AC_ARG_ENABLE(arm4-asm, [  --enable-arm4-asm        make use of ARM4 assembly instructions],
+AC_ARG_ENABLE(arm4-asm, [  --enable-arm4-asm       Make use of ARM4 assembly instructions],
 [if test "$enableval" = yes; then
   AC_DEFINE([ARM4_ASM], , [Make use of ARM4 assembly instructions])
 fi])
 
-AC_ARG_ENABLE(arm5e-asm, [  --enable-arm5e-asm        make use of ARM5E assembly instructions],
+AC_ARG_ENABLE(arm5e-asm, [  --enable-arm5e-asm      Make use of ARM5E assembly instructions],
 [if test "$enableval" = yes; then
   AC_DEFINE([ARM5_ASM], , [Make use of ARM5E assembly instructions])
 fi])

Modified: trunk/speex/libspeex/nb_celp.c
===================================================================
--- trunk/speex/libspeex/nb_celp.c	2005-04-25 07:16:23 UTC (rev 9180)
+++ trunk/speex/libspeex/nb_celp.c	2005-04-25 08:12:04 UTC (rev 9181)
@@ -95,11 +95,15 @@
    int i;
 
    mode=(const SpeexNBMode *)m->mode;
+#if defined(VAR_ARRAYS) || defined (USE_ALLOCA)
+   st = (EncState*)speex_alloc(sizeof(EncState));
+   st->stack = NULL;
+#else
    st = (EncState*)speex_alloc(sizeof(EncState)+8000*sizeof(spx_sig_t));
+   st->stack = ((char*)st) + sizeof(EncState);
+#endif
    if (!st)
       return NULL;
-
-   st->stack = ((char*)st) + sizeof(EncState);
    
    st->mode=m;
 
@@ -125,46 +129,46 @@
 #endif
 
    /* Allocating input buffer */
-   st->inBuf = PUSH(st->stack, st->windowSize, spx_sig_t);
+   st->inBuf = speex_alloc((st->windowSize)*sizeof(spx_sig_t));
    st->frame = st->inBuf;
    /* Allocating excitation buffer */
-   st->excBuf = PUSH(st->stack, mode->frameSize+mode->pitchEnd+1, spx_sig_t);
+   st->excBuf = speex_alloc((mode->frameSize+mode->pitchEnd+1)*sizeof(spx_sig_t));
    st->exc = st->excBuf + mode->pitchEnd + 1;
-   st->swBuf = PUSH(st->stack, mode->frameSize+mode->pitchEnd+1, spx_sig_t);
+   st->swBuf = speex_alloc((mode->frameSize+mode->pitchEnd+1)*sizeof(spx_sig_t));
    st->sw = st->swBuf + mode->pitchEnd + 1;
 
-   st->innov = PUSH(st->stack, st->frameSize, spx_sig_t);
+   st->innov = speex_alloc((st->frameSize)*sizeof(spx_sig_t));
 
    /* Asymmetric "pseudo-Hamming" window */
    {
       int part1, part2;
       part1=st->frameSize - (st->subframeSize>>1);
       part2=(st->frameSize>>1) + (st->subframeSize>>1);
-      st->window = PUSH(st->stack, st->windowSize, spx_word16_t);
+      st->window = speex_alloc((st->windowSize)*sizeof(spx_word16_t));
       for (i=0;i<part1;i++)
          st->window[i]=(spx_word16_t)(SIG_SCALING*(.54-.46*cos(M_PI*i/part1)));
       for (i=0;i<part2;i++)
          st->window[part1+i]=(spx_word16_t)(SIG_SCALING*(.54+.46*cos(M_PI*i/part2)));
    }
    /* Create the window for autocorrelation (lag-windowing) */
-   st->lagWindow = PUSH(st->stack, st->lpcSize+1, spx_word16_t);
+   st->lagWindow = speex_alloc((st->lpcSize+1)*sizeof(spx_word16_t));
    for (i=0;i<st->lpcSize+1;i++)
       st->lagWindow[i]=16384*exp(-.5*sqr(2*M_PI*st->lag_factor*i));
 
-   st->autocorr = PUSH(st->stack, st->lpcSize+1, spx_word16_t);
+   st->autocorr = speex_alloc((st->lpcSize+1)*sizeof(spx_word16_t));
 
-   st->lpc = PUSH(st->stack, st->lpcSize+1, spx_coef_t);
-   st->interp_lpc = PUSH(st->stack, st->lpcSize+1, spx_coef_t);
-   st->interp_qlpc = PUSH(st->stack, st->lpcSize+1, spx_coef_t);
-   st->bw_lpc1 = PUSH(st->stack, st->lpcSize+1, spx_coef_t);
-   st->bw_lpc2 = PUSH(st->stack, st->lpcSize+1, spx_coef_t);
+   st->lpc = speex_alloc((st->lpcSize+1)*sizeof(spx_coef_t));
+   st->interp_lpc = speex_alloc((st->lpcSize+1)*sizeof(spx_coef_t));
+   st->interp_qlpc = speex_alloc((st->lpcSize+1)*sizeof(spx_coef_t));
+   st->bw_lpc1 = speex_alloc((st->lpcSize+1)*sizeof(spx_coef_t));
+   st->bw_lpc2 = speex_alloc((st->lpcSize+1)*sizeof(spx_coef_t));
 
-   st->lsp = PUSH(st->stack, st->lpcSize, spx_lsp_t);
-   st->qlsp = PUSH(st->stack, st->lpcSize, spx_lsp_t);
-   st->old_lsp = PUSH(st->stack, st->lpcSize, spx_lsp_t);
-   st->old_qlsp = PUSH(st->stack, st->lpcSize, spx_lsp_t);
-   st->interp_lsp = PUSH(st->stack, st->lpcSize, spx_lsp_t);
-   st->interp_qlsp = PUSH(st->stack, st->lpcSize, spx_lsp_t);
+   st->lsp = speex_alloc((st->lpcSize)*sizeof(spx_lsp_t));
+   st->qlsp = speex_alloc((st->lpcSize)*sizeof(spx_lsp_t));
+   st->old_lsp = speex_alloc((st->lpcSize)*sizeof(spx_lsp_t));
+   st->old_qlsp = speex_alloc((st->lpcSize)*sizeof(spx_lsp_t));
+   st->interp_lsp = speex_alloc((st->lpcSize)*sizeof(spx_lsp_t));
+   st->interp_qlsp = speex_alloc((st->lpcSize)*sizeof(spx_lsp_t));
 
    st->first = 1;
    for (i=0;i<st->lpcSize;i++)
@@ -172,16 +176,16 @@
       st->lsp[i]=LSP_SCALING*(M_PI*((float)(i+1)))/(st->lpcSize+1);
    }
 
-   st->mem_sp = PUSH(st->stack, st->lpcSize, spx_mem_t);
-   st->mem_sw = PUSH(st->stack, st->lpcSize, spx_mem_t);
-   st->mem_sw_whole = PUSH(st->stack, st->lpcSize, spx_mem_t);
-   st->mem_exc = PUSH(st->stack, st->lpcSize, spx_mem_t);
+   st->mem_sp = speex_alloc((st->lpcSize)*sizeof(spx_mem_t));
+   st->mem_sw = speex_alloc((st->lpcSize)*sizeof(spx_mem_t));
+   st->mem_sw_whole = speex_alloc((st->lpcSize)*sizeof(spx_mem_t));
+   st->mem_exc = speex_alloc((st->lpcSize)*sizeof(spx_mem_t));
 
-   st->pi_gain = PUSH(st->stack, st->nbSubframes, spx_word32_t);
+   st->pi_gain = speex_alloc((st->nbSubframes)*sizeof(spx_word32_t));
 
-   st->pitch = PUSH(st->stack, st->nbSubframes, int);
+   st->pitch = speex_alloc((st->nbSubframes)*sizeof(int));
 
-   st->vbr = PUSHS(st->stack, VBRState);
+   st->vbr = speex_alloc(sizeof(VBRState));
    vbr_init(st->vbr);
    st->vbr_quality = 8;
    st->vbr_enabled = 0;
@@ -928,10 +932,18 @@
    int i;
 
    mode=(const SpeexNBMode*)m->mode;
+#if defined(VAR_ARRAYS) || defined (USE_ALLOCA)
+   st = (DecState *)speex_alloc(sizeof(DecState));
+   st->stack = NULL;
+#else
    st = (DecState *)speex_alloc(sizeof(DecState)+4000*sizeof(spx_sig_t));
+   st->stack = ((char*)st) + sizeof(DecState);
+#endif
+   if (!st)
+      return NULL;
+
    st->mode=m;
 
-   st->stack = ((char*)st) + sizeof(DecState);
 
    st->encode_submode = 1;
 #ifdef EPIC_48K
@@ -953,25 +965,25 @@
    st->lpc_enh_enabled=0;
 
 
-   st->inBuf = PUSH(st->stack, st->frameSize, spx_sig_t);
+   st->inBuf = speex_alloc((st->frameSize)*sizeof(spx_sig_t));
    st->frame = st->inBuf;
-   st->excBuf = PUSH(st->stack, st->frameSize + st->max_pitch + 1, spx_sig_t);
+   st->excBuf = speex_alloc((st->frameSize + st->max_pitch + 1)*sizeof(spx_sig_t));
    st->exc = st->excBuf + st->max_pitch + 1;
    for (i=0;i<st->frameSize;i++)
       st->inBuf[i]=0;
    for (i=0;i<st->frameSize + st->max_pitch + 1;i++)
       st->excBuf[i]=0;
-   st->innov = PUSH(st->stack, st->frameSize, spx_sig_t);
+   st->innov = speex_alloc((st->frameSize)*sizeof(spx_sig_t));
 
-   st->interp_qlpc = PUSH(st->stack, st->lpcSize+1, spx_coef_t);
-   st->qlsp = PUSH(st->stack, st->lpcSize, spx_lsp_t);
-   st->old_qlsp = PUSH(st->stack, st->lpcSize, spx_lsp_t);
-   st->interp_qlsp = PUSH(st->stack, st->lpcSize, spx_lsp_t);
-   st->mem_sp = PUSH(st->stack, 5*st->lpcSize, spx_mem_t);
-   st->comb_mem = PUSHS(st->stack, CombFilterMem);
+   st->interp_qlpc = speex_alloc((st->lpcSize+1)*sizeof(spx_coef_t));
+   st->qlsp = speex_alloc((st->lpcSize)*sizeof(spx_lsp_t));
+   st->old_qlsp = speex_alloc((st->lpcSize)*sizeof(spx_lsp_t));
+   st->interp_qlsp = speex_alloc((st->lpcSize)*sizeof(spx_lsp_t));
+   st->mem_sp = speex_alloc((5*st->lpcSize)*sizeof(spx_mem_t));
+   st->comb_mem = speex_alloc(sizeof(CombFilterMem));
    comb_filter_mem_init (st->comb_mem);
 
-   st->pi_gain = PUSH(st->stack, st->nbSubframes, spx_word32_t);
+   st->pi_gain = speex_alloc((st->nbSubframes)*sizeof(spx_word32_t));
    st->last_pitch = 40;
    st->count_lost=0;
    st->pitch_gain_buf[0] = st->pitch_gain_buf[1] = st->pitch_gain_buf[2] = 0;

Modified: trunk/speex/libspeex/sb_celp.c
===================================================================
--- trunk/speex/libspeex/sb_celp.c	2005-04-25 07:16:23 UTC (rev 9180)
+++ trunk/speex/libspeex/sb_celp.c	2005-04-25 08:12:04 UTC (rev 9181)
@@ -244,57 +244,57 @@
    st->gamma2=mode->gamma2;
    st->first=1;
 
-   st->x0d=PUSH(st->stack, st->frame_size, spx_sig_t);
-   st->x1d=PUSH(st->stack, st->frame_size, spx_sig_t);
-   st->high=PUSH(st->stack, st->full_frame_size, spx_sig_t);
-   st->y0=PUSH(st->stack, st->full_frame_size, spx_sig_t);
-   st->y1=PUSH(st->stack, st->full_frame_size, spx_sig_t);
+   st->x0d=speex_alloc((st->frame_size)*sizeof(spx_sig_t));
+   st->x1d=speex_alloc((st->frame_size)*sizeof(spx_sig_t));
+   st->high=speex_alloc((st->full_frame_size)*sizeof(spx_sig_t));
+   st->y0=speex_alloc((st->full_frame_size)*sizeof(spx_sig_t));
+   st->y1=speex_alloc((st->full_frame_size)*sizeof(spx_sig_t));
 
-   st->h0_mem=PUSH(st->stack, QMF_ORDER, spx_word16_t);
-   st->h1_mem=PUSH(st->stack, QMF_ORDER, spx_word16_t);
-   st->g0_mem=PUSH(st->stack, QMF_ORDER, spx_word32_t);
-   st->g1_mem=PUSH(st->stack, QMF_ORDER, spx_word32_t);
+   st->h0_mem=speex_alloc((QMF_ORDER)*sizeof(spx_word16_t));
+   st->h1_mem=speex_alloc((QMF_ORDER)*sizeof(spx_word16_t));
+   st->g0_mem=speex_alloc((QMF_ORDER)*sizeof(spx_word32_t));
+   st->g1_mem=speex_alloc((QMF_ORDER)*sizeof(spx_word32_t));
 
-   st->buf=PUSH(st->stack, st->windowSize, spx_sig_t);
-   st->excBuf=PUSH(st->stack, st->bufSize, spx_sig_t);
+   st->buf=speex_alloc((st->windowSize)*sizeof(spx_sig_t));
+   st->excBuf=speex_alloc((st->bufSize)*sizeof(spx_sig_t));
    st->exc = st->excBuf + st->bufSize - st->windowSize;
 
-   st->res=PUSH(st->stack, st->frame_size, spx_sig_t);
-   st->sw=PUSH(st->stack, st->frame_size, spx_sig_t);
-   st->target=PUSH(st->stack, st->frame_size, spx_sig_t);
+   st->res=speex_alloc((st->frame_size)*sizeof(spx_sig_t));
+   st->sw=speex_alloc((st->frame_size)*sizeof(spx_sig_t));
+   st->target=speex_alloc((st->frame_size)*sizeof(spx_sig_t));
    /*Asymmetric "pseudo-Hamming" window*/
    {
       int part1, part2;
       part1 = st->subframeSize*7/2;
       part2 = st->subframeSize*5/2;
-      st->window = PUSH(st->stack, st->windowSize, spx_word16_t);
+      st->window = speex_alloc((st->windowSize)*sizeof(spx_word16_t));
       for (i=0;i<part1;i++)
          st->window[i]=(spx_word16_t)(SIG_SCALING*(.54-.46*cos(M_PI*i/part1)));
       for (i=0;i<part2;i++)
          st->window[part1+i]=(spx_word16_t)(SIG_SCALING*(.54+.46*cos(M_PI*i/part2)));
    }
 
-   st->lagWindow = PUSH(st->stack, st->lpcSize+1, spx_word16_t);
+   st->lagWindow = speex_alloc((st->lpcSize+1)*sizeof(spx_word16_t));
    for (i=0;i<st->lpcSize+1;i++)
       st->lagWindow[i]=16384*exp(-.5*sqr(2*M_PI*st->lag_factor*i));
 
-   st->autocorr = PUSH(st->stack, st->lpcSize+1, spx_word16_t);
-   st->lpc = PUSH(st->stack, st->lpcSize+1, spx_coef_t);
-   st->bw_lpc1 = PUSH(st->stack, st->lpcSize+1, spx_coef_t);
-   st->bw_lpc2 = PUSH(st->stack, st->lpcSize+1, spx_coef_t);
-   st->lsp = PUSH(st->stack, st->lpcSize, spx_lsp_t);
-   st->qlsp = PUSH(st->stack, st->lpcSize, spx_lsp_t);
-   st->old_lsp = PUSH(st->stack, st->lpcSize, spx_lsp_t);
-   st->old_qlsp = PUSH(st->stack, st->lpcSize, spx_lsp_t);
-   st->interp_lsp = PUSH(st->stack, st->lpcSize, spx_lsp_t);
-   st->interp_qlsp = PUSH(st->stack, st->lpcSize, spx_lsp_t);
-   st->interp_lpc = PUSH(st->stack, st->lpcSize+1, spx_coef_t);
-   st->interp_qlpc = PUSH(st->stack, st->lpcSize+1, spx_coef_t);
-   st->pi_gain = PUSH(st->stack, st->nbSubframes, spx_word32_t);
+   st->autocorr = speex_alloc((st->lpcSize+1)*sizeof(spx_word16_t));
+   st->lpc = speex_alloc((st->lpcSize+1)*sizeof(spx_coef_t));
+   st->bw_lpc1 = speex_alloc((st->lpcSize+1)*sizeof(spx_coef_t));
+   st->bw_lpc2 = speex_alloc((st->lpcSize+1)*sizeof(spx_coef_t));
+   st->lsp = speex_alloc((st->lpcSize)*sizeof(spx_lsp_t));
+   st->qlsp = speex_alloc((st->lpcSize)*sizeof(spx_lsp_t));
+   st->old_lsp = speex_alloc((st->lpcSize)*sizeof(spx_lsp_t));
+   st->old_qlsp = speex_alloc((st->lpcSize)*sizeof(spx_lsp_t));
+   st->interp_lsp = speex_alloc((st->lpcSize)*sizeof(spx_lsp_t));
+   st->interp_qlsp = speex_alloc((st->lpcSize)*sizeof(spx_lsp_t));
+   st->interp_lpc = speex_alloc((st->lpcSize+1)*sizeof(spx_coef_t));
+   st->interp_qlpc = speex_alloc((st->lpcSize+1)*sizeof(spx_coef_t));
+   st->pi_gain = speex_alloc((st->nbSubframes)*sizeof(spx_word32_t));
 
-   st->mem_sp = PUSH(st->stack, st->lpcSize, spx_mem_t);
-   st->mem_sp2 = PUSH(st->stack, st->lpcSize, spx_mem_t);
-   st->mem_sw = PUSH(st->stack, st->lpcSize, spx_mem_t);
+   st->mem_sp = speex_alloc((st->lpcSize)*sizeof(spx_mem_t));
+   st->mem_sp2 = speex_alloc((st->lpcSize)*sizeof(spx_mem_t));
+   st->mem_sw = speex_alloc((st->lpcSize)*sizeof(spx_mem_t));
 
    st->vbr_quality = 8;
    st->vbr_enabled = 0;
@@ -804,24 +804,24 @@
    st->first=1;
 
 
-   st->x0d=PUSH(st->stack, st->frame_size, spx_sig_t);
-   st->x1d=PUSH(st->stack, st->frame_size, spx_sig_t);
-   st->high=PUSH(st->stack, st->full_frame_size, spx_sig_t);
-   st->y0=PUSH(st->stack, st->full_frame_size, spx_sig_t);
-   st->y1=PUSH(st->stack, st->full_frame_size, spx_sig_t);
+   st->x0d=speex_alloc((st->frame_size)*sizeof(spx_sig_t));
+   st->x1d=speex_alloc((st->frame_size)*sizeof(spx_sig_t));
+   st->high=speex_alloc((st->full_frame_size)*sizeof(spx_sig_t));
+   st->y0=speex_alloc((st->full_frame_size)*sizeof(spx_sig_t));
+   st->y1=speex_alloc((st->full_frame_size)*sizeof(spx_sig_t));
 
-   st->g0_mem=PUSH(st->stack, QMF_ORDER, spx_word32_t);
-   st->g1_mem=PUSH(st->stack, QMF_ORDER, spx_word32_t);
+   st->g0_mem=speex_alloc((QMF_ORDER)*sizeof(spx_word32_t));
+   st->g1_mem=speex_alloc((QMF_ORDER)*sizeof(spx_word32_t));
 
-   st->exc=PUSH(st->stack, st->frame_size, spx_sig_t);
+   st->exc=speex_alloc((st->frame_size)*sizeof(spx_sig_t));
 
-   st->qlsp = PUSH(st->stack, st->lpcSize, spx_lsp_t);
-   st->old_qlsp = PUSH(st->stack, st->lpcSize, spx_lsp_t);
-   st->interp_qlsp = PUSH(st->stack, st->lpcSize, spx_lsp_t);
-   st->interp_qlpc = PUSH(st->stack, st->lpcSize+1, spx_coef_t);
+   st->qlsp = speex_alloc((st->lpcSize)*sizeof(spx_lsp_t));
+   st->old_qlsp = speex_alloc((st->lpcSize)*sizeof(spx_lsp_t));
+   st->interp_qlsp = speex_alloc((st->lpcSize)*sizeof(spx_lsp_t));
+   st->interp_qlpc = speex_alloc((st->lpcSize+1)*sizeof(spx_coef_t));
 
-   st->pi_gain = PUSH(st->stack, st->nbSubframes, spx_word32_t);
-   st->mem_sp = PUSH(st->stack, 2*st->lpcSize, spx_mem_t);
+   st->pi_gain = speex_alloc((st->nbSubframes)*sizeof(spx_word32_t));
+   st->mem_sp = speex_alloc((2*st->lpcSize)*sizeof(spx_mem_t));
    
    st->lpc_enh_enabled=0;
 

Modified: trunk/speex/libspeex/stack_alloc.h
===================================================================
--- trunk/speex/libspeex/stack_alloc.h	2005-04-25 07:16:23 UTC (rev 9180)
+++ trunk/speex/libspeex/stack_alloc.h	2005-04-25 08:12:04 UTC (rev 9181)
@@ -34,6 +34,10 @@
 #ifndef STACK_ALLOC_H
 #define STACK_ALLOC_H
 
+#ifdef USE_ALLOCA
+#include <alloca.h>
+#endif
+
 #ifdef ENABLE_VALGRIND
 
 #include <valgrind/memcheck.h>



More information about the commits mailing list