Exemplo n.º 1
0
/* evpushargs - evaluate and push a list of arguments */
LOCAL int evpushargs(LVAL fun, LVAL args)
{
    LVAL *newfp;
    int argc;
    
    /* protect the argument list */
    xlprot1(args);

    /* build a new argument stack frame */
    newfp = xlsp;
    pusharg(cvfixnum((FIXTYPE)(newfp - xlfp)));
    pusharg(fun);
    pusharg(NIL); /* will be argc */

    /* evaluate and push each argument */
    for (argc = 0; consp(args); args = cdr(args), ++argc)
        pusharg(xleval(car(args)));

    /* establish the new stack frame */
    newfp[2] = cvfixnum((FIXTYPE)argc);
    xlfp = newfp;
    
    /* restore the stack */
    xlpop();

    /* return the number of arguments */
    return (argc);
}
Exemplo n.º 2
0
/* splitlist - split the list around the pivot */
LOCAL void splitlist(LVAL pivot, LVAL list, LVAL *psmaller, LVAL *plarger, LVAL fcn)
{
    LVAL next;

    xlprot1(list); // protect list from gc
    // the rplacd disconnects list, and next is the only 
    // reference to it, but next is immediately assigned to list
    // before dotest2 which is where gc might run.
    
    /* initialize the result lists */
    *psmaller = *plarger = NIL;
    
    /* split the list */
    for (; consp(list); list = next) {
        next = cdr(list);
        if (dotest2(car(list),car(pivot),fcn)) {
            rplacd(list,*psmaller);
            *psmaller = list;
        }
        else {
            rplacd(list,*plarger);
            *plarger = list;
        }
    }
    xlpop();
}
Exemplo n.º 3
0
void nyx_set_input_audio(nyx_audio_callback callback,
                         void *userdata,
                         int num_channels,
                         long len, double rate)
{
   LVAL val;
   int ch;

   nyx_set_audio_params(rate, len);

   if (num_channels > 1) {
      val = newvector(num_channels);
   }

   xlprot1(val);

   for (ch = 0; ch < num_channels; ch++) {
      nyx_susp_type susp;
      sound_type snd;

      falloc_generic(susp, nyx_susp_node, "nyx_set_input_audio");

      susp->callback = callback;
      susp->userdata = userdata;
      susp->len = len;
      susp->channel = ch;

      susp->susp.fetch = nyx_susp_fetch;
      susp->susp.keep_fetch = NULL;
      susp->susp.free = nyx_susp_free;
      susp->susp.mark = NULL;
      susp->susp.print_tree = nyx_susp_print_tree;
      susp->susp.name = "nyx";
      susp->susp.toss_cnt = 0;
      susp->susp.current = 0;
      susp->susp.sr = rate;
      susp->susp.t0 = 0.0;
      susp->susp.log_stop_cnt = 0;
      
      snd = sound_create((snd_susp_type) susp, 0.0, rate, 1.0);
      if (num_channels > 1) {
         setelement(val, ch, cvsound(snd));
      }
      else {
         val = cvsound(snd);
      }
   }

   setvalue(xlenter("S"), val);

   xlpop();
}
Exemplo n.º 4
0
table_type get_window_samples(LVAL window, sample_type **samples, long *len)
{
    table_type result = NULL;
    if (soundp(window)) {
        sound_type window_sound = getsound(window);
        xlprot1(window); /* maybe not necessary */
        result = sound_to_table(window_sound);
        xlpop();
        *samples = result->samples;
        *len = (long) (result->length + 0.5);
    }
    return result;
}
Exemplo n.º 5
0
/* xsendmsg - send a message to an object */
LOCAL LVAL xsendmsg(LVAL obj, LVAL cls, LVAL sym)
{
    LVAL msg=NULL,msgcls,method,val,p;

    /* look for the message in the class or superclasses */
    for (msgcls = cls; msgcls; ) {

        /* lookup the message in this class */
        for (p = getivar(msgcls,MESSAGES); p; p = cdr(p))
            if ((msg = car(p)) && car(msg) == sym)
                goto send_message;

        /* look in class's superclass */
        msgcls = getivar(msgcls,SUPERCLASS);
    }

    /* message not found */
    xlerror("no method for this message",sym);

send_message:

    /* insert the value for 'self' (overwrites message selector) */
    *--xlargv = obj;
    ++xlargc;
    
    /* invoke the method */
    if ((method = cdr(msg)) == NULL)
        xlerror("bad method",method);
    switch (ntype(method)) {
    case SUBR:
        val = (*getsubr(method))();
        break;
    case CLOSURE:
        if (gettype(method) != s_lambda)
            xlerror("bad method",method);
        val = evmethod(obj,msgcls,method);
        break;
    default:
        xlerror("bad method",method);
    }

    /* after creating an object, send it the ":isnew" message */
    if (car(msg) == k_new && val) {
        xlprot1(val);
        xsendmsg(val,getclass(val),k_isnew);
        xlpop();
    }
    
    /* return the result value */
    return (val);
}
Exemplo n.º 6
0
double sound_max(LVAL snd_expr, long n)
{
    LVAL s_as_lval;
    sound_type s = NULL;
    long blocklen;
    sample_block_values_type sbufp;
    register double maximum = 0;

    s_as_lval = xleval(snd_expr);
    /* BE CAREFUL - DO NOT ALLOW GC TO RUN WHILE LVAL IS UNPROTECTED */
    if (exttypep(s_as_lval, a_sound)) {
        /* if snd_expr was simply a symbol, then s now points to
        a shared sound_node.  If we read samples from it, then
        the sound bound to the symbol will be destroyed, so
        copy it first.  If snd_expr was a real expression that
        computed a new value, then the next garbage collection
        will reclaim the sound_node.  We need to make the new
        sound reachable by the garbage collector to that any
        lisp data reachable from the sound do not get collected.
        To make the sound reachable, we need to allocate a node,
        and the GC might run, so we need to protect the OLD s
        but then make it unreachable.
        We will let the GC collect the sound in the end.
        */
        xlprot1(s_as_lval);
        s = sound_copy(getsound(s_as_lval));
        s_as_lval = cvsound(s);	/* destroys only ref. to original */
        /* printf("sound_max: copy is %x, lval %x\n", s, s_as_lval); */
        while (n > 0) {
            long togo, j;
            sample_block_type sampblock = 
              sound_get_next(s, &blocklen);
            if (sampblock == zero_block || blocklen == 0) {
                break;
            }
            togo = MIN(blocklen, n);
            sbufp = sampblock->samples;
            for (j = 0; j < togo; j++) {
                register double samp = *sbufp++;
                if (samp > maximum) maximum = samp;
                else if (-samp > maximum) maximum = -samp;
            }
            n -= togo;
        }
        xlpop();
    } else {
        xlerror("sound_max: expression did not return a sound",
                 s_as_lval);
    }
    return maximum * s->scale;
}
Exemplo n.º 7
0
void nyx_init()
{
   if (nyx_first_time) {
      char *argv[1];
      argv[0] = "nyquist";
      xlisp_main_init(1, argv);

      nyx_os_cb = NULL;
      nyx_output_cb = NULL;
      
      nyx_first_time = 0;

#if defined(NYX_FULL_COPY) && NYX_FULL_COPY
      // Save a copy of the original obarray's contents.
      nyx_save_obarray();
#else
      // Permanently protect the original obarray value.  This is needed since
      // it would be unreferenced in the new obarray and would be garbage
      // collected.  We want to keep it around so we can make copies of it to 
      // refresh the execution state.
      xlprot1(nyx_obarray);
      nyx_obarray = getvalue(obarray);
#endif
   }

#if !defined(NYX_FULL_COPY) || !NYX_FULL_COPY
   // Create a copy of the original obarray
   nyx_copy_obarray();
#endif

   // Keep nyx_result from being garbage-collected
   xlprot1(nyx_result);

#if defined(NYX_MEMORY_STATS) && NYX_MEMORY_STATS
   printf("\nnyx_init\n");
   xmem();
#endif
}
Exemplo n.º 8
0
nyx_rval nyx_eval_expression(const char *expr_string)
{
   LVAL expr = NULL;

   nyx_expr_string = expr_string;
   nyx_expr_len = strlen(nyx_expr_string);
   nyx_expr_pos = 0;

   nyx_result = NULL;
   nyx_parse_error_flag = 0;

   xlprot1(expr);

   /* setup the error return */
   xlbegin(&nyx_cntxt,CF_TOPLEVEL|CF_CLEANUP|CF_BRKLEVEL,(LVAL)1);
   if (setjmp(nyx_cntxt.c_jmpbuf))
      goto finish;

   while(nyx_expr_pos < nyx_expr_len) {
      expr = NULL;

      /* read an expression */
      if (!xlread(getvalue(s_stdin), &expr, FALSE))
         break;

      #if 0
      /* save the input expression (so the user can refer to it
         as +, ++, or +++) */
      xlrdsave(expr);
      #endif
      
      /* evaluate the expression */
      nyx_result = xleval(expr);
   }

   xlflush();

 finish:
   xlend(&nyx_cntxt);

   xlpop(); /* unprotect expr */

   /* reset the globals to their initial state */
   obarray = nyx_old_obarray;
   setvalue(xlenter("S"), NULL);
   gc();

   return nyx_get_type(nyx_result);
}
Exemplo n.º 9
0
// Make a copy of the original obarray, leaving the original in place
LOCAL void nyx_save_obarray()
{
   LVAL newarray;
   int i;

   // This provide permanent protection for nyx_obarray as we do not want it
   // to be garbage-collected.
   xlprot1(nyx_obarray);
   nyx_obarray = getvalue(obarray);

   // Create and set the new vector.  This allows us to use xlenter() to
   // properly add the new symbol.  Probably slower than adding directly,
   // but guarantees proper hashing.
   newarray = newvector(HSIZE);
   setvalue(obarray, newarray);

   // Scan all obarray vectors
   for (i = 0; i < HSIZE; i++) {
      LVAL sym;

      // Scan all elements
      for (sym = getelement(nyx_obarray, i); sym; sym = cdr(sym)) {
         LVAL syma = car(sym);
         char *name = (char *) getstring(getpname(syma));
         LVAL nsym = xlenter(name);

         // Ignore *OBARRAY* since there's no need to copy it
         if (strcmp(name, "*OBARRAY*") == 0) {
            continue;
         }

         // Ignore *SCRATCH* since it's allowed to be updated
         if (strcmp(name, "*SCRATCH*") == 0) {
            continue;
         }

         // Duplicate the symbol's values
         setvalue(nsym, nyx_dup_value(getvalue(syma)));
         setplist(nsym, nyx_dup_value(getplist(syma)));
         setfunction(nsym, nyx_dup_value(getfunction(syma)));
      }
   }

   // Swap the obarrays, so that the original is put back into service
   setvalue(obarray, nyx_obarray);
   nyx_obarray = newarray;
}
Exemplo n.º 10
0
void nyx_init()
{
   if (nyx_first_time) {
      char *argv[1];
      argv[0] = "nyquist";
      xlisp_main_init(1, argv);

      nyx_output_len = 0;
      nyx_output_pos = 0;
      nyx_output_string = NULL;
      
      nyx_first_time = 0;
   }

   /* keep nyx_result from being garbage-collected */
   xlprot1(nyx_result);

   nyx_save_obarray();
}
Exemplo n.º 11
0
LVAL xlc_snd_read(void)
{
    unsigned char * arg1 = getstring(xlgastring());
    double arg2 = testarg2(xlgaanynum());
    double arg3 = testarg2(xlgaanynum());
    long arg4 = getfixnum(xlgafixnum());
    long arg5 = getfixnum(xlgafixnum());
    long arg6 = getfixnum(xlgafixnum());
    long arg7 = getfixnum(xlgafixnum());
    long arg8 = getfixnum(xlgafixnum());
    double arg9 = testarg2(xlgaanynum());
    double arg10 = testarg2(xlgaanynum());
    long arg11 = 0;
    long arg12 = 0;
    LVAL result;

    xllastarg();
    xlprot1(result);
    result = snd_make_read(arg1, arg2, arg3, &arg4, &arg5, &arg6, &arg7, &arg8, &arg9, &arg10, &arg11, &arg12);
    {	LVAL *next = &getvalue(RSLT_sym);
	*next = cons(NIL, NIL);
	car(*next) = cvfixnum(arg4);	next = &cdr(*next);
	*next = cons(NIL, NIL);
	car(*next) = cvfixnum(arg5);	next = &cdr(*next);
	*next = cons(NIL, NIL);
	car(*next) = cvfixnum(arg6);	next = &cdr(*next);
	*next = cons(NIL, NIL);
	car(*next) = cvfixnum(arg7);	next = &cdr(*next);
	*next = cons(NIL, NIL);
	car(*next) = cvfixnum(arg8);	next = &cdr(*next);
	*next = cons(NIL, NIL);
	car(*next) = cvflonum(arg9);	next = &cdr(*next);
	*next = cons(NIL, NIL);
	car(*next) = cvflonum(arg10);	next = &cdr(*next);
	*next = cons(NIL, NIL);
	car(*next) = cvfixnum(arg11);	next = &cdr(*next);
	*next = cons(NIL, NIL);
	car(*next) = cvfixnum(arg12);
    }
    xlpop();
    return (result);
}
Exemplo n.º 12
0
/* clanswer - define a method for answering a message */
LVAL clanswer(void)
{
    LVAL self,msg,fargs,code,mptr;

    /* message symbol, formal argument list and code */
    self = xlgaobject();
    msg = xlgasymbol();
    fargs = xlgalist();
    code = xlgalist();
    xllastarg();

    /* make a new message list entry */
    mptr = entermsg(self,msg);

    /* setup the message node */
    xlprot1(fargs);
    fargs = cons(s_self,fargs); /* add 'self' as the first argument */
    rplacd(mptr,xlclose(msg,s_lambda,fargs,code,NIL,NIL));
    xlpop();

    /* return the object */
    return (self);
}
Exemplo n.º 13
0
static LVAL elementlist P1C(LVAL, x)
{
  LVAL next, last, result;
  
  if (!compoundp(x)) result = consa(x);
  else {
    xlprot1(x);
    x = compounddataseq(x);
    x = (listp(x)) ? copylist(x) : coerce_to_list(x);
    if (all_simple(x)) result = x;
    else {
      for (next = x; consp(next); next = cdr(next))
        rplaca(next, elementlist(car(next)));
      result = car(x);
      last = lastcdr(car(x));
      for (next = cdr(x); consp(next); next = cdr(next)) {
        rplacd(last, car(next));
        last = lastcdr(car(next));
      }
    }
    xlpop();
  }
  return(result);
}
Exemplo n.º 14
0
nyx_rval nyx_eval_expression(const char *expr_string)
{
   LVAL expr = NULL;

#if defined(NYX_MEMORY_STATS) && NYX_MEMORY_STATS
   printf("\nnyx_eval_expression before\n");
   xmem();
#endif

   nyx_result = NULL;
   nyx_result_type = nyx_error;

   // Check argument
   if (!expr_string || !strlen(expr_string)) {
      return nyx_get_type(nyx_result);
   }

   nyx_expr_string = expr_string;
   nyx_expr_len = strlen(nyx_expr_string);
   nyx_expr_pos = 0;

   // Protect the expression from being garbage collected
   xlprot1(expr);

   // Setup a new context
   xlbegin(&nyx_cntxt, CF_TOPLEVEL|CF_CLEANUP|CF_BRKLEVEL|CF_ERROR, s_true);

   // Set the context jump destination
   if (setjmp(nyx_cntxt.c_jmpbuf)) {
      // If the script is cancelled or some other condition occurs that causes
      // the script to exit and return to this level, then we don't need to
      // restore the previous context.
      goto finish;
   }

   while (nyx_expr_pos < nyx_expr_len) {
      expr = NULL;

      // Read an expression
      if (!xlread(getvalue(s_stdin), &expr, FALSE)) {
         break;
      }

      #if 0
      /* save the input expression (so the user can refer to it
         as +, ++, or +++) */
      xlrdsave(expr);
      #endif

      // Evaluate the expression
      nyx_result = xleval(expr);
   }

   // This will unwind the xlisp context and restore internals to a point just
   // before we issued our xlbegin() above.  This is important since the internal
   // xlisp stacks will contain pointers to invalid objects otherwise.
   //
   // Also note that execution will jump back up to the statement following the
   // setjmp() above.
   xljump(&nyx_cntxt, CF_TOPLEVEL, NIL);
   // Never reached

 finish:

   xlflush();

   xlpop(); // unprotect expr

   gc();

#if defined(NYX_MEMORY_STATS) && NYX_MEMORY_STATS
   printf("\nnyx_eval_expression after\n");
   xmem();
#endif

   return nyx_get_type(nyx_result);
}
Exemplo n.º 15
0
sample_type sound_save_array(LVAL sa, long n, snd_type snd, 
                             char *buf, long *ntotal, snd_type player)
{
    long i, chans;
    long buflen;
    sound_state_type state;
    double start_time = HUGE_VAL;
    float *float_bufp;
    LVAL sa_copy;
    long debug_unit;    /* print messages at intervals of this many samples */
    long debug_count;   /* next point at which to print a message */
    sample_type max_sample = 0.0F;
    cvtfn_type cvtfn;

    *ntotal = 0;

    /* THE ALGORITHM: first merge floating point samples from N channels
     * into consecutive multi-channel frames in buf.  Then, treat buf
     * as just one channel and use one of the cvt_to_* functions to
     * convert the data IN PLACE in the buffer (this is ok because the
     * converted data will never take more space than the original 32-bit
     * floats, so the converted data will not overwrite any floats before
     * the floats are converted
     */

    /* if snd_expr was simply a symbol, then sa now points to
        a shared sound_node.  If we read samples from it, then
        the sounds bound to the symbol will be destroyed, so
        copy it first.  If snd_expr was a real expression that
        computed a new value, then the next garbage collection
        will reclaim the sound array.  See also sound_save_sound()
    */
    chans = getsize(sa);
    if (chans > MAX_SND_CHANNELS) {
        xlerror("sound_save: too many channels", sa);
        free(buf);
        snd_close(snd);
    }
    xlprot1(sa);
    sa_copy = newvector(chans);
    xlprot1(sa_copy);

    /* Why do we copy the array into an xlisp array instead of just
     * the state[i] array? Because some of these sounds may reference
     * the lisp heap. We must put the sounds in an xlisp array so that
     * the gc will find and mark them. xlprot1(sa_copy) makes the array
     * visible to gc.
     */
    for (i = 0; i < chans; i++) {
        sound_type s = getsound(getelement(sa, i));
        setelement(sa_copy, i, cvsound(sound_copy(s)));
    }
    sa = sa_copy;	/* destroy original reference to allow GC */

    state = (sound_state_type) malloc(sizeof(sound_state_node) * chans);
    for (i = 0; i < chans; i++) {
        state[i].sound = getsound(getelement(sa, i));
        state[i].scale = state[i].sound->scale;
D       nyquist_printf("save scale factor %d = %g\n", (int)i, state[i].scale);
        state[i].terminated = false;
        state[i].cnt = 0;   /* force a fetch */
        start_time = min(start_time, state[i].sound->t0);
    }

    for (i = 0; i < chans; i++) {
        if (state[i].sound->t0 > start_time)
            sound_prepend_zeros(state[i].sound, start_time);
    }

    /* for debugging */
/*    printing_this_sound = s;*/

    cvtfn = find_cvt_to_fn(snd, buf);

#ifdef MACINTOSH
    if (player) {
        gprintf(TRANS, "Playing audio: Click and hold mouse button to stop playback.\n");
    }
#endif

    debug_unit = debug_count = (long) max(snd->format.srate, 10000.0);

    while (n > 0) {
        /* keep the following information for each sound:
            has it terminated?
            pointer to samples
            number of samples remaining in block
           scan to find the minimum remaining samples and
           output that many in an inner loop.  Stop outer
           loop if all sounds have terminated
         */
        int terminated = true;
        int togo = n;
        int j;
        float peak;

        oscheck();

        for (i = 0; i < chans; i++) {
            if (state[i].cnt == 0) {
                if (sndwrite_trace) {
                    nyquist_printf("CALLING SOUND_GET_NEXT "
                                   "ON CHANNEL %d (%p)\n",
                                   (int)i, state[i].sound);
                    sound_print_tree(state[i].sound);
                }
                state[i].ptr = sound_get_next(state[i].sound,
                                   &(state[i].cnt))->samples;
                if (sndwrite_trace) {
                    nyquist_printf("RETURNED FROM CALL TO SOUND_GET_NEXT "
                                   "ON CHANNEL %d\n", (int)i);
                }
                if (state[i].ptr == zero_block->samples) {
                    state[i].terminated = true;
                }
            }
            if (!state[i].terminated) terminated = false;
            togo = min(togo, state[i].cnt);
        }

        if (terminated) break;

        float_bufp = (float *) buf;
        for (j = 0; j < togo; j++) {
            for (i = 0; i < chans; i++) {
                double s = *(state[i].ptr++) * state[i].scale; 
                *float_bufp++ = (float) s;
            }
        }
        // we're treating sound as mono for the conversion, so multiply
        // togo by chans to get proper number of samples, and divide by
        // chans to convert back to frame count required by snd_write
        buflen = (*cvtfn)((void *) buf, (void *) buf, togo * chans, 1.0F, 
                          &peak) / chans;
        if (peak > max_sample) max_sample = peak;
#ifdef MACINTOSH
        if (Button()) {
            if (player) {
                snd_reset(player);
            }
            gprintf(TRANS, "\n\nStopping playback...\n\n\n");
            break;
        }
#endif

        if (snd->u.file.file != -1) snd_write(snd, (void *) buf, buflen);
        if (player) write_to_audio(player, (void *) buf, buflen);

        n -= togo;
        for (i = 0; i < chans; i++) {
            state[i].cnt -= togo;
        }
        *ntotal += togo;
        if (*ntotal > debug_count) {
            gprintf(TRANS, " %d ", *ntotal);
            fflush(stdout);
            debug_count += debug_unit;
        }
    }
    gprintf(TRANS, "total samples: %d x %d channels\n",
           *ntotal, chans);

    /* references to sounds are shared by sa_copy and state[].
     * here, we dispose of state[], allowing GC to do the
     * sound_unref call that frees the sounds. (Freeing them now
     * would be a bug.)
     */
    free(state);
    xlpop();
    return max_sample;
}
Exemplo n.º 16
0
sample_type sound_save_sound(LVAL s_as_lval, long n, SF_INFO *sf_info, 
        SNDFILE *sndfile, float *buf, long *ntotal, PaStream *audio_stream)
{
    long blocklen;
    sound_type s;
    int i;
    sample_type *samps;
    long debug_unit;    /* print messages at intervals of this many samples */
    long debug_count;   /* next point at which to print a message */
    sample_type max_sample = 0.0F;
    sample_type threshold = 0.0F;
    /* jlh    cvtfn_type cvtfn; */
    *ntotal = 0;
    /* if snd_expr was simply a symbol, then s now points to
        a shared sound_node.  If we read samples from it, then
        the sound bound to the symbol will be destroyed, so
        copy it first.  If snd_expr was a real expression that
        computed a new value, then the next garbage collection
        will reclaim the sound_node.  We need to make the new
        sound reachable by the garbage collector to that any
        lisp data reachable from the sound do not get collected.
        To make the sound reachable, we need to allocate a node,
        and the GC might run, so we need to protect the OLD s
        but then make it unreachable.
        We will let the GC collect the sound in the end.
    */
    xlprot1(s_as_lval);
    s = sound_copy(getsound(s_as_lval));
    s_as_lval = cvsound(s);	/* destroys only ref. to original */

    /* for debugging */
/*    printing_this_sound = s;*/


    debug_unit = debug_count = (long) max(sf_info->samplerate, 10000.0);

    sound_frames = 0;
    sound_srate = sf_info->samplerate;

    while (n > 0) {
        long togo;
        sample_block_type sampblock = sound_get_next(s, &blocklen);
        oscheck();
#ifdef SNAPSHOTS
        stdputstr(".");
        if (sound_created_flag) {
            stdputstr("SNAPSHOT: ");
            sound_print_tree(printing_this_sound);
            sound_created_flag = false;
        }
        fflush(stdout);
#endif
        if (sampblock == zero_block || blocklen == 0) {
            break;
        }
        togo = min(blocklen, n);
        if (s->scale != 1) { /* copy/scale samples into buf */
            for (i = 0; i < togo; i++) {
                buf[i] = s->scale * sampblock->samples[i];
            }
            samps = buf;
        } else {
            samps = sampblock->samples;
        }
        if (is_pcm(sf_info)) {
            for (i = 0; i < togo; i++) {
                sample_type s = samps[i];
                COMPUTE_MAXIMUM_AND_WRAP(samps[i]);
            }
        } else {
            for (i = 0; i < togo; i++) {
                sample_type s = samps[i];
                COMPUTE_MAXIMUM();
            }
        }
        if (sndfile) {
            sf_writef_float(sndfile, samps, togo);
        }
        if (audio_stream) {
            Pa_WriteStream(audio_stream, samps, togo);
            sound_frames += togo;
        }

        n -= togo;
        *ntotal += togo;
        if (*ntotal > debug_count) {
            gprintf(TRANS, " %ld ", *ntotal);
            fflush(stdout);
            debug_count += debug_unit;
        }
    }
    gprintf(TRANS, "\ntotal samples: %ld\n", *ntotal);
    xlpop();
    return max_sample;
}
Exemplo n.º 17
0
sample_type sound_save_array(LVAL sa, long n, SF_INFO *sf_info, 
        SNDFILE *sndfile, float *buf, long *ntotal, PaStream *audio_stream)
{
    long i, chans;
    float *float_bufp;
    sound_state_type state;
    double start_time = HUGE_VAL;
    LVAL sa_copy;
    long debug_unit;    /* print messages at intervals of this many samples */
    long debug_count;   /* next point at which to print a message */
    sample_type max_sample = 0.0F;
    sample_type threshold = 0.0F;
    /*    cvtfn_type cvtfn; jlh */

    *ntotal = 0;

    /* THE ALGORITHM: first merge floating point samples from N channels
     * into consecutive multi-channel frames in buf.  Then, treat buf
     * as just one channel and use one of the cvt_to_* functions to
     * convert the data IN PLACE in the buffer (this is ok because the
     * converted data will never take more space than the original 32-bit
     * floats, so the converted data will not overwrite any floats before
     * the floats are converted
     */

    /* if snd_expr was simply a symbol, then sa now points to
        a shared sound_node.  If we read samples from it, then
        the sounds bound to the symbol will be destroyed, so
        copy it first.  If snd_expr was a real expression that
        computed a new value, then the next garbage collection
        will reclaim the sound array.  See also sound_save_sound()
    */

    chans = getsize(sa);
    if (chans > MAX_SND_CHANNELS) {
        xlerror("sound_save: too many channels", sa);
        free(buf);
        sf_close(sndfile);
    }
    xlprot1(sa);
    sa_copy = newvector(chans);
    xlprot1(sa_copy);

    /* Why do we copy the array into an xlisp array instead of just
     * the state[i] array? Because some of these sounds may reference
     * the lisp heap. We must put the sounds in an xlisp array so that
     * the gc will find and mark them. xlprot1(sa_copy) makes the array
     * visible to gc.
     */
    for (i = 0; i < chans; i++) {
        sound_type s = getsound(getelement(sa, i));
        setelement(sa_copy, i, cvsound(sound_copy(s)));
    }
    sa = sa_copy;	/* destroy original reference to allow GC */

    state = (sound_state_type) malloc(sizeof(sound_state_node) * chans);
    for (i = 0; i < chans; i++) {
        state[i].sound = getsound(getelement(sa, i));
        state[i].scale = state[i].sound->scale;
D       nyquist_printf("save scale factor %ld = %g\n", i, state[i].scale);
        state[i].terminated = false;
        state[i].cnt = 0;   /* force a fetch */
        start_time = min(start_time, state[i].sound->t0);
    }

    for (i = 0; i < chans; i++) {
        if (state[i].sound->t0 > start_time)
            sound_prepend_zeros(state[i].sound, start_time);
    }

    debug_unit = debug_count = (long) max(sf_info->samplerate, 10000.0);

    sound_frames = 0;
    sound_srate = sf_info->samplerate;
    while (n > 0) {
        /* keep the following information for each sound:
            has it terminated?
            pointer to samples
            number of samples remaining in block
           scan to find the minimum remaining samples and
           output that many in an inner loop.  Stop outer
           loop if all sounds have terminated
         */
        int terminated = true;
        int togo = n;
        int j;

        oscheck();

        for (i = 0; i < chans; i++) {
            if (state[i].cnt == 0) {
                if (sndwrite_trace) {
                    nyquist_printf("CALLING SOUND_GET_NEXT ON CHANNEL %ld (%lx)\n",
				   i, (unsigned long) state[i].sound); /* jlh 64 bit issue */
                    sound_print_tree(state[i].sound);
                }
                state[i].ptr = sound_get_next(state[i].sound,
                                   &(state[i].cnt))->samples;
                if (sndwrite_trace) {
                    nyquist_printf("RETURNED FROM CALL TO SOUND_GET_NEXT ON CHANNEL %ld\n", i);
                }
                if (state[i].ptr == zero_block->samples) {
                    state[i].terminated = true;
                }
            }
            if (!state[i].terminated) terminated = false;
            togo = min(togo, state[i].cnt);
        }

        if (terminated) break;

        float_bufp = (float *) buf;
        if (is_pcm(sf_info)) {
            for (j = 0; j < togo; j++) {
                for (i = 0; i < chans; i++) {
                    float s = (float) (*(state[i].ptr++) * (float) state[i].scale);
                    COMPUTE_MAXIMUM_AND_WRAP(s);
                    *float_bufp++ = s;
                }
            }
        } else {
            for (j = 0; j < togo; j++) {
                for (i = 0; i < chans; i++) {
                    float s = (float) (*(state[i].ptr++) * (float) state[i].scale);
                    COMPUTE_MAXIMUM();
                    *float_bufp++ = s;
                }
            }
        }
        /* Here we have interleaved floats. Before converting to the sound
           file format, call PortAudio to play them. */
        if (audio_stream) {
            PaError err = Pa_WriteStream(audio_stream, buf, togo);
            if (err) {
                printf("Pa_WriteStream error %d\n", err);
            }
            sound_frames += togo;
        }
        if (sndfile) sf_writef_float(sndfile, buf, togo);

        n -= togo;
        for (i = 0; i < chans; i++) {
            state[i].cnt -= togo;
        }
        *ntotal += togo;
        if (*ntotal > debug_count) {
            gprintf(TRANS, " %ld ", *ntotal);
            fflush(stdout);
            debug_count += debug_unit;
        }
    }
    gprintf(TRANS, "total samples: %ld x %ld channels\n",
           *ntotal, chans);

    /* references to sounds are shared by sa_copy and state[].
     * here, we dispose of state[], allowing GC to do the
     * sound_unref call that frees the sounds. (Freeing them now
     * would be a bug.)
     */
    free(state);
    xlpop();
    return max_sample;
}
Exemplo n.º 18
0
// Copy a node (recursively if appropriate)
LOCAL LVAL nyx_dup_value(LVAL val)
{
   LVAL nval = val;

   // Protect old and new values
   xlprot1(val);
   xlprot1(nval);

   // Copy the node
   if (val != NIL) {
      switch (ntype(val))
      {
         case FIXNUM:
            nval = cvfixnum(getfixnum(val));
         break;

         case FLONUM:
            nval = cvflonum(getflonum(val));
         break;

         case CHAR:
            nval = cvchar(getchcode(val));
         break;

         case STRING:
            nval = cvstring((char *) getstring(val));
         break;

         case VECTOR:
         {
            int len = getsize(val);
            int i;

            nval = newvector(len);
            nval->n_type = ntype(val);

            for (i = 0; i < len; i++) {
               if (getelement(val, i) == val) {
                  setelement(nval, i, val);
               }
               else {
                  setelement(nval, i, nyx_dup_value(getelement(val, i)));
               }
            }
         }
         break;

         case CONS:
            nval = nyx_dup_value(cdr(val));
            nval = cons(nyx_dup_value(car(val)), nval);
         break;

         case SUBR:
         case FSUBR:
            nval = cvsubr(getsubr(val), ntype(val), getoffset(val));
         break;

         // Symbols should never be copied since their addresses are cached
         // all over the place.
         case SYMBOL:
            nval = val;
         break;

         // Streams are not copied (although USTREAM could be) and reference
         // the original value.
         case USTREAM:
         case STREAM:
            nval = val;
         break;

         // Externals aren't copied because I'm not entirely certain they can be.
         case EXTERN:
            nval = val;
         break;

         // For all other types, just allow them to reference the original
         // value.  Probably not the right thing to do, but easier.
         case OBJECT:
         case CLOSURE:
         default:
            nval = val;
         break;
      }
   }

   xlpop();
   xlpop();

   return nval;
}
Exemplo n.º 19
0
void nyx_set_input_audio(nyx_audio_callback callback,
                         void *userdata,
                         int num_channels,
                         long len, double rate)
{
   sample_type      scale_factor = 1.0;
   time_type        t0 = 0.0;
   nyx_susp_type   *susp;
   sound_type      *snd;
   double           stretch_len;
   LVAL             warp;
   int              ch;

   susp = (nyx_susp_type *)malloc(num_channels * sizeof(nyx_susp_type));
   snd = (sound_type *)malloc(num_channels * sizeof(sound_type));

   for(ch=0; ch < num_channels; ch++) {
      falloc_generic(susp[ch], nyx_susp_node, "nyx_set_input_audio");

      susp[ch]->callback = callback;
      susp[ch]->userdata = userdata;
      susp[ch]->len = len;
      susp[ch]->channel = ch;

      susp[ch]->susp.sr = rate;
      susp[ch]->susp.t0 = t0;
      susp[ch]->susp.mark = NULL;
      susp[ch]->susp.print_tree = nyx_susp_print_tree;
      susp[ch]->susp.current = 0;
      susp[ch]->susp.fetch = nyx_susp_fetch;
      susp[ch]->susp.free = nyx_susp_free;
      susp[ch]->susp.name = "nyx";
      
      snd[ch] = sound_create((snd_susp_type)susp[ch], t0, 
                             rate, 
                             scale_factor);
   }

   /* Bind the sample rate to the "*sound-srate*" global */
   setvalue(xlenter("*SOUND-SRATE*"), cvflonum(rate));

   /* Bind selection len to "len" global */
   setvalue(xlenter("LEN"), cvflonum(len));

   if (len > 0)
      stretch_len = len / rate;
   else
      stretch_len = 1.0;

   /* Set the "*warp*" global based on the length of the audio */
   xlprot1(warp);
   warp = cons(cvflonum(0),                    /* time offset */
               cons(cvflonum(stretch_len),     /* time stretch */
                    cons(NULL,                 /* cont. time warp */
                         NULL)));
   setvalue(xlenter("*WARP*"), warp);
   xlpop();

   if (num_channels > 1) {
      LVAL array = newvector(num_channels);
      for(ch=0; ch<num_channels; ch++)
         setelement(array, ch, cvsound(snd[ch]));

      setvalue(xlenter("S"), array);
   }
   else {
      LVAL s = cvsound(snd[0]);

      setvalue(xlenter("S"), s);
   }
}
Exemplo n.º 20
0
sample_type sound_save_sound(LVAL s_as_lval, long n, snd_type snd,
                             char *buf, long *ntotal, snd_type player)
{
    long blocklen;
    long buflen;
    sound_type s;
    long debug_unit;    /* print messages at intervals of this many samples */
    long debug_count;   /* next point at which to print a message */
    sample_type max_sample = 0.0F;
    cvtfn_type cvtfn;
    *ntotal = 0;

    /* if snd_expr was simply a symbol, then s now points to
        a shared sound_node.  If we read samples from it, then
        the sound bound to the symbol will be destroyed, so
        copy it first.  If snd_expr was a real expression that
        computed a new value, then the next garbage collection
        will reclaim the sound_node.  We need to make the new
        sound reachable by the garbage collector to that any
        lisp data reachable from the sound do not get collected.
        To make the sound reachable, we need to allocate a node,
        and the GC might run, so we need to protect the OLD s
        but then make it unreachable.
        We will let the GC collect the sound in the end.
    */
    xlprot1(s_as_lval);
    s = sound_copy(getsound(s_as_lval));
    s_as_lval = cvsound(s);	/* destroys only ref. to original */

    /* for debugging */
/*    printing_this_sound = s;*/


    debug_unit = debug_count = (long) max(snd->format.srate, 10000.0);

    cvtfn = find_cvt_to_fn(snd, buf);

#ifdef MACINTOSH
    if (player) {
        gprintf(TRANS, "Playing audio: Click and hold mouse button to stop playback.\n");
    }
#endif

    while (n > 0) {
        long togo;
        float peak;
        sample_block_type sampblock = sound_get_next(s, &blocklen);
        oscheck();
#ifdef SNAPSHOTS
        stdputstr(".");
        if (sound_created_flag) {
            stdputstr("SNAPSHOT: ");
            sound_print_tree(printing_this_sound);
            sound_created_flag = false;
        }
        fflush(stdout);
#endif
        if (sampblock == zero_block || blocklen == 0) {
            break;
        }
        togo = min(blocklen, n);

        buflen = (*cvtfn)((void *) buf, (void *) sampblock->samples,
                          togo, s->scale, &peak);
        if (peak > max_sample) max_sample = peak;

#ifdef MACINTOSH
        if (Button()) {
            if (player) {
                snd_reset(player);
            }
            gprintf(TRANS, "\n\nStopping playback...\n\n\n");
            break;
        }
#endif

        if (snd->u.file.file != -1) snd_write(snd, (void *) buf, buflen);
        if (player) write_to_audio(player, (void *) buf, buflen);

        n -= togo;
        *ntotal += togo;
        if (*ntotal > debug_count) {
            gprintf(TRANS, " %d ", *ntotal);
            fflush(stdout);
            debug_count += debug_unit;
        }
    }
    gprintf(TRANS, "\ntotal samples: %d\n", *ntotal);
    xlpop();
    return max_sample;
}