This is sound.c in view mode; [Download] [Up]
/* * FILE: sound.c * BY: Christopher Lee Fraley (cf0v@spice.cs.cmu.edu) * DESC: file for i/f'ing C sound functions to LISP * * 1.0 (23-SEP-88) - created. (cf0v) * 1.1 (10-OCT-88) - modified data structure. (cf0v) * 2.0 (10-NOV-88) - moved srate to SoundType; changed critical members of * SoundType to double; corrected flatten. SoundType.to * is now re-defined so SoundType.to is referenced from * the begining of the sound instead of end of sound, * (I.e. Normally, to==len/srate.) (cf0v) * 2.1 ( 1-FEB-89) - added s_osc(), s_env() functions. (cf0v) * 3.0 (13-FEB-89) - moved all sound manipulation functions to "fugue.c", * leaving only those required by X-Lisp to implement * a new type, and primitives such as s_create(), * s_copy(), and s_flatten(). (cf0v) * 4.0 (11-MAY-89) - finally found malloc problems! cvsound() now increments * refCount, while the create functions create sounds * with refCount set to zero. (cf0v) */ #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <math.h> #include "xlisp.h" #include "sound.h" static int readint(); static void writeint(); xtype_desc sound_desc; static LVAL a_sound; /* The SOUND Type: */ int soundp(s) LVAL s; { return (exttypep(s, a_sound)); } LVAL cvsound(s) SoundPtr s; { s->refCount += 1; return (cvextern(sound_desc, (unsigned char *) s)); } void sample_free(sample) SamplePtr sample; { if (--(sample->refCount) == 0) { free((char *)sample->data); free((char *)sample); } } void nodes_free(node) NodePtr node; { NodePtr next; for (; node!=NULL; node=next) { next = node->next; sound_free(node->sound); free((char *)node); } } SoundPtr s_silence(s) SoundPtr s; { switch (s->tag) { case SILENCE: break; case SAMPLES: sample_free(s->ptr.sample); break; case SUMNODES: nodes_free(s->ptr.node); break; } s->tag = SILENCE; return (s); } void sound_free(s) SoundPtr s; { if (--(s->refCount) > 0) return; free((char *)s_silence(s)); } SDataPtr sdata_create(size) int size; { SDataPtr data; if (NULL == (data=(SDataPtr)malloc((unsigned)(size + 2) * sizeof(SDataType)))) xlerror("insufficient memory - sound.c:sdata_create()"); /* two extra samples provide zeros for interpolation: */ data[0] = 0.0; data[size + 1] = 0.0; return (data); } SoundPtr s_create() { SoundPtr s; if (NULL == (s = (SoundPtr) malloc(sizeof(SoundType)))) xlerror("insufficient memory - sound.c:s_create()"); s->scale = 1.0; s->from = 0.0; s->to = 0.0; s->logicalTo = 0.0; s->shift = 0.0; s->stretch = 1.0; s->srate = SRATE; s->tag = SILENCE; s->refCount = 0; return (s); } NodePtr n_create(s1) SoundPtr s1; { NodePtr n; if (NULL == (n = (NodePtr) malloc(sizeof(NodeType)))) xlerror("insufficient memory - sound.c:n_create()"); n->sound = s1; s1->refCount += 1; n->next = NULL; return (n); } void n_add(n1, s1) NodePtr n1; SoundPtr s1; { n1->next = n_create(s1); } SamplePtr spl_create(data, size, srate) SDataPtr data; unsigned int size; float srate; { SamplePtr spl; if (NULL == (spl = (SamplePtr) malloc(sizeof(SampleType)))) xlerror("insufficient memory - sound.c:spl_create()"); spl->refCount = 1; spl->length = size; spl->srate = srate; spl->data = data; return (spl); } SoundPtr s_copy(s1) SoundPtr s1; { NodePtr n, *dest; SoundPtr s; s = s_create(); s->scale = s1->scale; s->from = s1->from; s->to = s1->to; s->shift = s1->shift; s->stretch = s1->stretch; s->logicalTo = s1->logicalTo; s->srate = s1->srate; s->tag = s1->tag; switch (s1->tag) { case SILENCE: break; case SAMPLES: s->ptr.sample = s1->ptr.sample; s->ptr.sample->refCount += 1; break; case SUMNODES: for (dest= &(s->ptr.node), n=s1->ptr.node; n!=NULL; n=n->next, dest= &((*dest)->next)) *dest = n_create(n->sound); break; default: s->tag = SILENCE; break; } return (s); } int extent(s1, begin, end) SoundPtr s1; double *begin, *end; { *begin = (s1->from + s1->shift) * s1->stretch; *end = (s1->to + s1->shift) * s1->stretch; if ((*begin >= *end) || (s1->tag == SILENCE)) return (FALSE); return (TRUE); } void s_extent(s1, begin, end) SoundPtr s1; double *begin, *end; { if (!extent(s1, begin, end)) *begin = *end = 0.0; } /* * Diagram for transform: * * xform args: * +----------+ * | scale | * | from, to | * | shift | * | stretch | destS * +----------+ +-------------+ +----------------+ * | | effScale | | 1.0 | * | ===> | effFrom, To | ===> | 0.0, len/srate | * | | effShift | | destS->shift | * | | effStretch | | 1.0 | * +--------------+ +-------------+ +----------------+ * | s1->scale | | | * | s1->from, to | V V * | s1->shift | ... SAMPLE * | s1->stretch | * +--------------+ * | * V * SOURCE * */ static void xform(destS, s1, scale, from, to, shift, stretch) SoundPtr destS, s1; double scale, from, to, shift, stretch; { NodePtr node; double effScale, effFrom, effTo, effStretch, effShift, srcSrate, destSrate; double equivStretch, srcStep, srcIndex, srcIndexEnd, d, f; SDataPtr src, dest, srcEnd; int destEndIndex, destIndex; if (s1->tag == SILENCE) return; effScale = s1->scale * scale; effFrom = MAX(s1->from, from/s1->stretch - s1->shift); effTo = MIN(s1->to, to/s1->stretch - s1->shift); if (effTo <= effFrom) return; effShift = s1->shift + shift / s1->stretch; effStretch = stretch * s1->stretch; switch (s1->tag) { case SUMNODES: for (node=s1->ptr.node; node!=NULL; node=node->next) xform(destS, node->sound, effScale, effFrom, effTo, effShift, effStretch); return; case SAMPLES: srcSrate = s1->ptr.sample->srate; destSrate = destS->ptr.sample->srate; equivStretch = effStretch * destSrate / srcSrate; src = s1->ptr.sample->data; dest = destS->ptr.sample->data; destEndIndex = destS->ptr.sample->length; destIndex = ((effFrom+effShift)*effStretch - destS->shift) * destSrate + 0.5; if (destIndex < 0) destIndex = 0; dest += destIndex + 1; /* skip initial zero */ if (APPROX(equivStretch, 1.0)) { /* If no interpolation is needed: */ int srcIndex, srcEndIndex, temp; srcIndex = effFrom * srcSrate + 0.5; if (srcIndex < 0) srcIndex = 0; srcEndIndex = MIN((int)(effTo*srcSrate+0.5), s1->ptr.sample->length); temp = (srcEndIndex - srcIndex) - (destEndIndex - destIndex); if (temp > 0) srcEndIndex == temp; srcEnd = src + srcEndIndex + 1; /* skip initial zero */ src += srcIndex + 1; /* skip initial zero */ for (; src < srcEnd; src++, dest++) *dest += effScale * (*src); return; } else { double srcStep, srcIndex, srcEndIndex; /* printf("xform doing interpolation\n"); */ srcStep = 1.0 / equivStretch; srcIndex = 1 + (effFrom * srcSrate); /* skip initial zero */ if (srcIndex < 1.0) srcIndex = 1.0; srcEndIndex = 1 + MIN(effTo * srcSrate, (double)(s1->ptr.sample->length)); for( ; srcIndex < srcEndIndex; srcIndex += srcStep, dest++) { d = srcIndex - floor(srcIndex); f = 1.0 - d; *dest += effScale * (f * src[(int) srcIndex] + d * src[((int) srcIndex) + 1]); } return; } default: return; /* Invalid tag */ } } SoundPtr s_flatten(s1) SoundPtr s1; { unsigned int len; double begin, end, srate; SamplePtr sample; SDataPtr data; SoundPtr s; switch (s1->tag) { case SILENCE: return (s1); break; case SAMPLES: if (APPROX(s1->stretch, 1.0) && APPROX(s1->scale, 1.0) && APPROXLT(s1->from, 0.0) && APPROXLT((s1->ptr.sample->length-0.5)/s1->ptr.sample->srate, s1->to) && APPROX(s1->ptr.sample->srate, s1->srate)) return (s1); /* FALL-THROUGH! */ case SUMNODES: if (!extent(s1, &begin, &end)) return (s_silence(s1)); break; default: return (s1); } s = s_copy(s1); s_silence(s1); /* free s1 of sound and/or addends */ srate = s1->srate; len = (end - begin) * srate + 0.5; data = sdata_create(len); sample = spl_create(data, len, srate); s1->scale = 1.0; s1->from = 0.0; s1->to = len/srate; s1->shift = begin; s1->stretch = 1.0; s1->tag = SAMPLES; s1->ptr.sample = sample; /* printf("flatten calling xform\n"); */ xform(s1, s, 1.0, (double)NEGINFINITY, (double)INFINITY, 0.0, 1.0); sound_free(s); return (s1); } SoundPtr s_compose(array, srate) LVAL array; double srate; { SDataPtr data; SamplePtr sample; SoundPtr s; LVAL temp; int i, size; if (!vectorp(array)) xlerror("Bad argument type; (s-compose VECTOR)"); size = getsize(array); data = sdata_create(size); sample = spl_create(data, size, srate); s = s_create(); s->to = s->logicalTo = (double)size / srate; s->srate = srate; s->tag = SAMPLES; s->ptr.sample = sample; for (i=0; i<size; i++, data++) { temp = getelement(array, i); if (floatp(temp)) *data = getflonum(temp); else if (fixp(temp)) *data = getfixnum(temp); else xlerror("Bad argument type; s-compose VECTOR contains non-number"); } return (s); } SoundPtr s_constant(val, length) double val, length; { SDataPtr data; SamplePtr sample; SoundPtr s; data = sdata_create(2); sample = spl_create(data, 2, 2.0/length); *data = val; *(data+1) = val; s = s_create(); s->to = s->logicalTo = length; s->srate = 2.0 / length; s->tag = SAMPLES; s->ptr.sample = sample; return (s); } static void sound_print(fptr, s) LVAL fptr; SoundPtr s; { char buf[100]; double begin, end; if (s == NULL) { xlputstr(fptr, "{SOUND: silence[%g]}", s->logicalTo); return; } (void)sprintf(buf, "{SOUND: {%x} ", s); xlputstr(fptr, buf); switch (s->tag) { case SILENCE: (void)sprintf(buf, " silence}"); break; case SAMPLES: if (!extent(s, &begin, &end)) (void)sprintf(buf, " sample[silence|%g]}", s->logicalTo); else (void)sprintf(buf, " sample[%g:%g|%g]@%g}", begin, end, s->logicalTo, s->srate); break; case SUMNODES: if (!extent(s, &begin, &end)) (void)sprintf(buf, " node[silence|%g]}", s->logicalTo); else (void)sprintf(buf, " node[%g:%g|%g]@%g}", begin, end, s->logicalTo, s->srate); break; default: (void)sprintf(buf, " illegal[%d]}", s->tag); } xlputstr(fptr, buf); } static void sound_save(fp, s) FILE *fp; SoundPtr s; { printf("sound_save called\n"); } static unsigned char *sound_restore(fp) FILE *fp; { SoundPtr s; printf("sound_restore called\n"); s = s_create(); return ((unsigned char *)s); } void test_init() { sound_desc = create_desc("SOUND", sound_free, sound_print, sound_save, sound_restore); } void test_symbols() { a_sound = xlenter("SOUND"); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.