Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
tree: e28db25801
Fetching contributors…

Cannot retrieve contributors at this time

640 lines (515 sloc) 14.933 kB
/*
SuperCollider real time audio synthesis system
Copyright (c) 2002 James McCartney. All rights reserved.
http://www.audiosynth.com
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "PyrSymbol.h"
#include "PyrKernel.h"
#include "PyrObject.h"
#include "PyrPrimitive.h"
#include "PyrSignal.h"
#include "PyrSignalPrim.h"
#include "PyrMessage.h"
#include "SC_Constants.h"
#include "SCBase.h"
#include "clz.h"
extern "C" {
#include "fftlib.h"
}
#include <stdlib.h>
#include <string.h>
#include <math.h>
int prSignalFill(struct VMGlobals *g, int numArgsPushed)
{
PyrSlot *a, *b;
int err;
float value;
a = g->sp - 1;
b = g->sp;
err = slotFloatVal(b, &value);
if (err != errNone) return err;
signal_fill(slotRawObject(a), value);
return errNone;
}
int prSignalScale(struct VMGlobals *g, int numArgsPushed)
{
PyrSlot *a, *b;
int err;
float value;
a = g->sp - 1;
b = g->sp;
err = slotFloatVal(b, &value);
if (err != errNone) return err;
signal_scale(slotRawObject(a), value);
return errNone;
}
int prSignalOffset(struct VMGlobals *g, int numArgsPushed)
{
PyrSlot *a, *b;
int err;
float value;
a = g->sp - 1;
b = g->sp;
err = slotFloatVal(b, &value);
if (err != errNone) return err;
signal_offset(slotRawObject(a), value);
return errNone;
}
int prSignalString(struct VMGlobals *g, int numArgsPushed)
{
PyrSlot *a;
PyrString *string;
PyrObject *signal;
float *x;
char str[128];
a = g->sp;
slotString(a, str);
signal = slotRawObject(a);
if (signal->size) {
x = (float*)(signal->slots);
sprintf(str, "%s[%g .. %g]", slotRawSymbol(&signal->classptr->name)->name,
x[0], x[signal->size-1]);
} else {
sprintf(str, "%s[none]", slotRawSymbol(&signal->classptr->name)->name);
}
string = newPyrString(g->gc, str, 0, true);
SetObject(a, string);
return errNone;
}
int prSignalPeak(struct VMGlobals *g, int numArgsPushed)
{
PyrSlot *a;
a = g->sp;
SetFloat(a, signal_findpeak(slotRawObject(a)));
return errNone;
}
int prSignalNormalize(struct VMGlobals *g, int numArgsPushed)
{
PyrSlot *a, *b, *c;
int err, start, end;
a = g->sp - 2;
b = g->sp - 1;
c = g->sp;
err = slotIntVal(b, &start);
if (err) {
if (IsNil(c)) start = 0;
else return err;
}
err = slotIntVal(c, &end);
if (err) {
if (IsNil(c)) end = slotRawObject(a)->size;
else return err;
}
signal_normalize_range(slotRawObject(a), start, end);
return errNone;
}
int prSignalNormalizeTransferFn(struct VMGlobals *g, int numArgsPushed)
{
PyrSlot *a;
a = g->sp;
signal_normalize_transfer_fn(slotRawObject(a));
return errNone;
}
int prSignalIntegral(struct VMGlobals *g, int numArgsPushed)
{
PyrSlot *a;
a = g->sp;
SetFloat(a, signal_integral(slotRawObject(a)));
return errNone;
}
int prSignalInvert(struct VMGlobals *g, int numArgsPushed)
{
PyrSlot *a, *b, *c;
int err, start, end;
a = g->sp - 2;
b = g->sp - 1;
c = g->sp;
err = slotIntVal(b, &start);
if (err) {
if (IsNil(c)) start = 0;
else return err;
}
err = slotIntVal(c, &end);
if (err) {
if (IsNil(c)) end = slotRawObject(a)->size;
else return err;
}
signal_invert_range(slotRawObject(a), start, end);
return errNone;
}
int prSignalReverse(struct VMGlobals *g, int numArgsPushed)
{
PyrSlot *a, *b, *c;
int err, start, end;
a = g->sp - 2;
b = g->sp - 1;
c = g->sp;
err = slotIntVal(b, &start);
if (err) {
if (IsNil(b)) start = 0;
else return err;
}
err = slotIntVal(c, &end);
if (err) {
if (IsNil(c)) end = slotRawObject(a)->size;
else return err;
}
signal_reverse_range(slotRawObject(a), start, end);
return errNone;
}
int prSignalRotate(struct VMGlobals *g, int numArgsPushed)
{
PyrSlot *a, *b;
int err, rot;
a = g->sp - 1;
b = g->sp;
err = slotIntVal(b, &rot);
if (err) return err;
SetRaw(a, signal_rotate(g, slotRawObject(a), rot));
return errNone;
}
int prSignalOverDub(struct VMGlobals *g, int numArgsPushed)
{
PyrSlot *a, *b, *c;
int err;
int index;
a = g->sp - 2;
b = g->sp - 1;
c = g->sp;
if (NotObj(b) || !isKindOf(slotRawObject(b), class_signal)) return errWrongType;
err = slotIntVal(c, &index);
if (err) return errWrongType;
signal_overdub(g, slotRawObject(a), slotRawObject(b), index);
return errNone;
}
int prSignalOverWrite(struct VMGlobals *g, int numArgsPushed)
{
PyrSlot *a, *b, *c;
int err;
int index;
a = g->sp - 2;
b = g->sp - 1;
c = g->sp;
if (NotObj(b) || !isKindOf(slotRawObject(b), class_signal)) return errWrongType;
err = slotIntVal(c, &index);
if (err) return errWrongType;
signal_overwrite(g, slotRawObject(a), slotRawObject(b), index);
return errNone;
}
int prSignalFade(struct VMGlobals *g, int numArgsPushed)
{
PyrSlot *a, *b, *c, *d, *e;
int err;
int start, end;
float lvl0, lvl1;
a = g->sp - 4;
b = g->sp - 3;
c = g->sp - 2;
d = g->sp - 1;
e = g->sp;
err = slotIntVal(b, &start);
if (err) {
if (IsNil(b)) start = 0;
else return err;
}
err = slotIntVal(c, &end);
if (err) {
if (IsNil(c)) end = slotRawObject(a)->size;
else return err;
}
err = slotFloatVal(d, &lvl0);
if (err) return err;
err = slotFloatVal(e, &lvl1);
if (err) return err;
signal_fade_range(slotRawObject(a), start, end, lvl0, lvl1);
return errNone;
}
int prSignalAddHarmonic(struct VMGlobals *g, int numArgsPushed)
{
PyrSlot *a, *b, *c, *d;
int err;
float harmonic, amp;
double phase, step;
PyrObject *signal;
float *out;
a = g->sp - 3;
b = g->sp - 2;
c = g->sp - 1;
d = g->sp;
err = slotFloatVal(b, &harmonic);
if (err) return errWrongType;
err = slotFloatVal(c, &amp);
if (err) return errWrongType;
err = slotDoubleVal(d, &phase);
if (err) return errWrongType;
signal = slotRawObject(a);
out = (float*)(signal->slots) - 1;
step = twopi * harmonic / signal->size;
UNROLL_CODE(signal->size, out, *++out += sin(phase) * amp; phase += step; );
return errNone;
}
int prSignalAddChebyshev(struct VMGlobals *g, int numArgsPushed);
int prSignalAddChebyshev(struct VMGlobals *g, int numArgsPushed)
{
PyrSlot *a, *b, *c;
int err;
float harmonic, amp;
double x, step;
PyrObject *signal;
float *out;
a = g->sp - 2;
b = g->sp - 1;
c = g->sp;
err = slotFloatVal(b, &harmonic);
if (err) return errWrongType;
err = slotFloatVal(c, &amp);
if (err) return errWrongType;
signal = slotRawObject(a);
out = (float*)(signal->slots) - 1;
x = -1.0;
step = 2.0 / (signal->size - 1);
UNROLL_CODE(signal->size, out, *++out += cos(harmonic * acos(x)) * amp; x += step; );
return errNone;
}
//////////////////////////////////////////////////////////////////////////////
void signalAsWavetable(float *signal, float *wavetable, int size)
{
int i, imax;
float *in, *out;
float val1, val2;
in = signal;
out = wavetable - 1;
imax = size-1;
for (i=0; i<imax; ++i) {
val1 = in[i];
val2 = in[i+1];
*++out = 2.f * val1 - val2;
*++out = val2 - val1;
}
val1 = in[imax];
val2 = in[0];
*++out = 2.f * val1 - val2;
*++out = val2 - val1;
}
void wavetableAsSignal(float *wavetable, float *signal, int size)
{
int i, imax;
float *in, *out;
in = wavetable;
out = signal - 1;
imax = size;
for (i=0; i<size; ++i) {
*++out = in[0] + in[1];
in += 2;
}
}
//////////////////////////////////////////////////////////////////////////////
int prSignalAsWavetable(struct VMGlobals *g, int numArgsPushed)
{
PyrSlot *a;
int size;
PyrObject *signal, *wavetable;
a = g->sp;
signal = slotRawObject(a);
size = signal->size;
if ((size & (size - 1)) != 0) {
error("Signal size not a power of two.\n");
return errFailed;
}
wavetable = newPyrSignal(g, signal->size * 2);
wavetable->classptr = class_wavetable;
signalAsWavetable((float*)signal->slots, (float*)wavetable->slots, signal->size);
SetObject(a, wavetable);
return errNone;
}
int prWavetableAsSignal(struct VMGlobals *g, int numArgsPushed)
{
PyrSlot *a;
PyrObject *signal, *wavetable;
a = g->sp;
wavetable = slotRawObject(a);
signal = newPyrSignal(g, wavetable->size / 2);
wavetableAsSignal((float*)wavetable->slots, (float*)signal->slots, signal->size);
SetObject(a, signal);
return errNone;
}
//class_signal
#if 1
int prSignal_FFT(struct VMGlobals *g, int numArgsPushed);
int prSignal_FFT(struct VMGlobals *g, int numArgsPushed)
{
PyrSlot *a, *b, *c;
int i, M, fftsize, fftbufsize, asize;
float *inreal, *inimag, *fftbuf, *costable, *outreal, *outimag;
PyrObject *fftoutobj, *complexobj, *realobj, *imagobj;
a = g->sp - 2;
b = g->sp - 1;
c = g->sp;
asize = slotRawObject(a)->size;
if (NotNil(b) && !(isKindOfSlot(b, class_signal) && slotRawObject(b)->size == asize)) {
error("Signal::fft imaginary part wrong type or length.\n");
return errFailed;
}
M = LOG2CEIL(asize);
fftsize = 1L << M;
if (!(isKindOfSlot(c, class_floatarray))) {
error("Signal::fft must be provided a table containing 1/4 cycle of a cosine.\n");
return errFailed;
}
if (slotRawObject(c)->size != fftsize/4+1) {
error("Signal::fft cosine table wrong size (%d), expected %d.\n", slotRawObject(c)->size, fftsize/4+1);
return errFailed;
}
costable = (float*)slotRawObject(c)->slots;
fftbufsize = fftsize * 2;
fftoutobj = newPyrSignal(g, fftbufsize);
fftoutobj->size = fftbufsize;
++g->sp; SetObject(g->sp, fftoutobj);
complexobj = instantiateObject(g->gc, s_complex->u.classobj, 0, false, true);
++g->sp; SetObject(g->sp, complexobj);
realobj = newPyrSignal(g, fftbufsize);
SetObject(complexobj->slots + 0, realobj);
g->gc->GCWriteNew(complexobj, realobj);
imagobj = newPyrSignal(g, fftbufsize);
SetObject(complexobj->slots + 1, imagobj);
g->gc->GCWriteNew(complexobj, imagobj);
inreal = (float*)slotRawObject(a)->slots - 1;
if (IsNil(b)) {
fftbuf = (float*)fftoutobj->slots - 1;
for (i=0; i<asize; ++i) {
*++fftbuf = *++inreal;
}
for (i=asize; i<fftsize; ++i) {
*++fftbuf = 0.f;
}
fftbuf = (float*)fftoutobj->slots;
rffts(fftbuf, M, 1, costable);
} else {
inimag = (float*)slotRawObject(b)->slots - 1;
fftbuf = (float*)fftoutobj->slots - 1;
for (i=0; i<asize; ++i) {
*++fftbuf = *++inreal;
*++fftbuf = *++inimag;
}
for (i=asize; i<fftsize; ++i) {
*++fftbuf = 0.f;
*++fftbuf = 0.f;
}
fftbuf = (float*)fftoutobj->slots;
ffts(fftbuf, M, 1, costable);
}
outreal = (float*)realobj->slots - 1;
outimag = (float*)imagobj->slots - 1;
fftbuf = (float*)fftoutobj->slots - 1;
for (i=0; i<fftsize; ++i) {
*++outreal = *++fftbuf;
*++outimag = *++fftbuf;
}
realobj->size = fftsize;
imagobj->size = fftsize;
g->sp -= 2;
SetRaw(a, complexobj);
return errNone;
}
int prSignal_IFFT(struct VMGlobals *g, int numArgsPushed);
int prSignal_IFFT(struct VMGlobals *g, int numArgsPushed)
{
PyrSlot *a, *b, *c;
int i, M, fftsize, fftbufsize, asize;
float *inreal, *inimag, *fftbuf, *costable, *outreal, *outimag;
PyrObject *fftoutobj, *complexobj, *realobj, *imagobj;
a = g->sp - 2;
b = g->sp - 1;
c = g->sp;
asize = slotRawObject(a)->size;
if (!(isKindOfSlot(b, class_signal) && slotRawObject(b)->size == asize)) {
error("Signal::ifft imaginary part wrong type or length.\n");
return errFailed;
}
M = LOG2CEIL(asize);
fftsize = 1L << M;
if (!(isKindOfSlot(c, class_floatarray))) {
error("Signal::ifft must be provided a table containing 1/4 cycle of a cosine.\n");
return errFailed;
}
if (slotRawObject(c)->size != fftsize/4+1) {
error("Signal::ifft cosine table wrong size (%d), expected %d.\n", slotRawObject(c)->size, fftsize/4+1);
return errFailed;
}
costable = (float*)slotRawObject(c)->slots;
fftbufsize = fftsize * 2;
fftoutobj = newPyrSignal(g, fftbufsize);
fftoutobj->size = fftbufsize;
++g->sp; SetObject(g->sp, fftoutobj);
complexobj = instantiateObject(g->gc, s_complex->u.classobj, 0, false, true);
++g->sp; SetObject(g->sp, complexobj);
realobj = newPyrSignal(g, fftbufsize);
SetObject(complexobj->slots + 0, realobj);
g->gc->GCWriteNew(complexobj, realobj);
imagobj = newPyrSignal(g, fftbufsize);
SetObject(complexobj->slots + 1, imagobj);
g->gc->GCWriteNew(complexobj, imagobj);
inreal = (float*)slotRawObject(a)->slots - 1;
inimag = (float*)slotRawObject(b)->slots - 1;
fftbuf = (float*)fftoutobj->slots - 1;
for (i=0; i<asize; ++i) {
*++fftbuf = *++inreal;
*++fftbuf = *++inimag;
}
for (i=asize; i<fftsize; ++i) {
*++fftbuf = 0.f;
*++fftbuf = 0.f;
}
fftbuf = (float*)fftoutobj->slots;
iffts(fftbuf, M, 1, costable);
outreal = (float*)realobj->slots - 1;
outimag = (float*)imagobj->slots - 1;
fftbuf = (float*)fftoutobj->slots - 1;
for (i=0; i<fftsize; ++i) {
*++outreal = *++fftbuf;
*++outimag = *++fftbuf;
}
realobj->size = fftsize;
imagobj->size = fftsize;
g->sp -= 2;
SetRaw(a, complexobj);
return errNone;
}
#endif
void initSignalPrimitives()
{
int base, index;
base = nextPrimitiveIndex();
index = 0;
definePrimitive(base, index++, "_SignalPeak", prSignalPeak, 1, 0);
definePrimitive(base, index++, "_SignalNormalize", prSignalNormalize, 3, 0);
definePrimitive(base, index++, "_SignalNormalizeTransferFn", prSignalNormalizeTransferFn, 1, 0);
definePrimitive(base, index++, "_SignalIntegral", prSignalIntegral, 1, 0);
definePrimitive(base, index++, "_SignalReverse", prSignalReverse, 3, 0);
definePrimitive(base, index++, "_SignalInvert", prSignalInvert, 3, 0);
definePrimitive(base, index++, "_SignalRotate", prSignalRotate, 2, 0);
definePrimitive(base, index++, "_SignalFill", prSignalFill, 2, 0);
definePrimitive(base, index++, "_SignalScale", prSignalScale, 2, 0);
definePrimitive(base, index++, "_SignalOffset", prSignalOffset, 2, 0);
definePrimitive(base, index++, "_SignalOverDub", prSignalOverDub, 3, 0);
definePrimitive(base, index++, "_SignalOverWrite", prSignalOverWrite, 3, 0);
definePrimitive(base, index++, "_SignalFade", prSignalFade, 5, 0);
definePrimitive(base, index++, "_SignalAddHarmonic", prSignalAddHarmonic, 4, 0);
definePrimitive(base, index++, "_SignalAddChebyshev", prSignalAddChebyshev, 3, 0);
definePrimitive(base, index++, "_SignalString", prSignalString, 1, 0);
definePrimitive(base, index++, "_SignalAsWavetable", prSignalAsWavetable, 1, 0);
definePrimitive(base, index++, "_WavetableAsSignal", prWavetableAsSignal, 1, 0);
definePrimitive(base, index++, "_Signal_FFT", prSignal_FFT, 3, 0);
definePrimitive(base, index++, "_Signal_IFFT", prSignal_IFFT, 3, 0);
}
Jump to Line
Something went wrong with that request. Please try again.