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.