Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: e28db25801
Fetching contributors…

Cannot retrieve contributors at this time

1345 lines (1098 sloc) 30.064 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 "FFT_UGens.h"
#define TWOPI 6.28318530717952646f
struct PV_OutOfPlace : Unit
{
int m_numbins;
float *m_tempbuf;
};
struct PV_MagSmear : PV_OutOfPlace
{
};
struct PV_MagShift : PV_OutOfPlace
{
};
struct PV_BinShift : PV_OutOfPlace
{
};
struct PV_PhaseShift : Unit
{
float m_phase_integral;
};
struct PV_Diffuser : Unit
{
int m_numbins;
float m_prevtrig, *m_shift;
bool m_triggered;
};
struct PV_MagFreeze : Unit
{
int m_numbins;
float *m_mags, m_dc, m_nyq;
};
struct PV_RandWipe : Unit
{
int *m_ordering, m_numbins;
float m_prevtrig;
bool m_triggered;
};
struct PV_RandComb : Unit
{
int *m_ordering, m_numbins;
float m_prevtrig;
bool m_triggered;
};
struct PV_BinScramble : Unit
{
int *m_from, *m_to, m_numbins;
float m_prevtrig;
float *m_tempbuf;
bool m_triggered;
};
struct PV_Conj : PV_Unit {};
//////////////////////////////////////////////////////////////////////////////////////////////////
extern "C"
{
void PV_PhaseShift_Ctor(PV_PhaseShift *unit);
void PV_PhaseShift_next(PV_PhaseShift *unit, int inNumSamples);
void PV_PhaseShift90_Ctor(PV_Unit *unit);
void PV_PhaseShift90_next(PV_Unit *unit, int inNumSamples);
void PV_PhaseShift270_Ctor(PV_Unit *unit);
void PV_PhaseShift270_next(PV_Unit *unit, int inNumSamples);
void PV_MagClip_Ctor(PV_Unit *unit);
void PV_MagClip_next(PV_Unit *unit, int inNumSamples);
void PV_MagAbove_Ctor(PV_Unit *unit);
void PV_MagAbove_next(PV_Unit *unit, int inNumSamples);
void PV_MagBelow_Ctor(PV_Unit *unit);
void PV_MagBelow_next(PV_Unit *unit, int inNumSamples);
void PV_Min_Ctor(PV_Unit *unit);
void PV_Min_next(PV_Unit *unit, int inNumSamples);
void PV_Max_Ctor(PV_Unit *unit);
void PV_Max_next(PV_Unit *unit, int inNumSamples);
void PV_Mul_Ctor(PV_Unit *unit);
void PV_Mul_next(PV_Unit *unit, int inNumSamples);
void PV_Div_Ctor(PV_Unit *unit);
void PV_Div_next(PV_Unit *unit, int inNumSamples);
void PV_Add_Ctor(PV_Unit *unit);
void PV_Add_next(PV_Unit *unit, int inNumSamples);
void PV_RectComb_Ctor(PV_Unit *unit);
void PV_RectComb_next(PV_Unit *unit, int inNumSamples);
void PV_RectComb2_Ctor(PV_Unit *unit);
void PV_RectComb2_next(PV_Unit *unit, int inNumSamples);
void PV_MagSquared_Ctor(PV_Unit *unit);
void PV_MagSquared_next(PV_Unit *unit, int inNumSamples);
void PV_MagMul_Ctor(PV_Unit *unit);
void PV_MagMul_next(PV_Unit *unit, int inNumSamples);
void PV_MagDiv_Ctor(PV_Unit *unit);
void PV_MagDiv_next(PV_Unit *unit, int inNumSamples);
void PV_Copy_Ctor(PV_Unit *unit);
void PV_Copy_next(PV_Unit *unit, int inNumSamples);
void PV_CopyPhase_Ctor(PV_Unit *unit);
void PV_CopyPhase_next(PV_Unit *unit, int inNumSamples);
void PV_MagSmear_Ctor(PV_MagSmear *unit);
void PV_MagSmear_Dtor(PV_MagSmear *unit);
void PV_MagSmear_next(PV_MagSmear *unit, int inNumSamples);
void PV_BinShift_Ctor(PV_BinShift *unit);
void PV_BinShift_Dtor(PV_BinShift *unit);
void PV_BinShift_next(PV_BinShift *unit, int inNumSamples);
void PV_MagShift_Ctor(PV_MagShift *unit);
void PV_MagShift_Dtor(PV_MagShift *unit);
void PV_MagShift_next(PV_MagShift *unit, int inNumSamples);
void PV_MagNoise_Ctor(PV_Unit *unit);
void PV_MagNoise_next(PV_Unit *unit, int inNumSamples);
void PV_BrickWall_Ctor(PV_Unit *unit);
void PV_BrickWall_next(PV_Unit *unit, int inNumSamples);
void PV_BinWipe_Ctor(PV_Unit *unit);
void PV_BinWipe_next(PV_Unit *unit, int inNumSamples);
void PV_LocalMax_Ctor(PV_Unit *unit);
void PV_LocalMax_next(PV_Unit *unit, int inNumSamples);
void PV_RandComb_Ctor(PV_RandComb *unit);
void PV_RandComb_Dtor(PV_RandComb *unit);
void PV_RandComb_next(PV_RandComb *unit, int inNumSamples);
void PV_RandWipe_Ctor(PV_RandWipe *unit);
void PV_RandWipe_Dtor(PV_RandWipe *unit);
void PV_RandWipe_next(PV_RandWipe *unit, int inNumSamples);
void PV_Diffuser_Ctor(PV_Diffuser *unit);
void PV_Diffuser_Dtor(PV_Diffuser *unit);
void PV_Diffuser_next(PV_Diffuser *unit, int inNumSamples);
void PV_MagFreeze_Ctor(PV_MagFreeze *unit);
void PV_MagFreeze_Dtor(PV_MagFreeze *unit);
void PV_MagFreeze_next(PV_MagFreeze *unit, int inNumSamples);
void PV_BinScramble_Ctor(PV_BinScramble *unit);
void PV_BinScramble_Dtor(PV_BinScramble *unit);
void PV_BinScramble_next(PV_BinScramble *unit, int inNumSamples);
void PV_Conj_Ctor(PV_Unit *unit);
void PV_Conj_next(PV_Unit *unit, int inNumSamples);
/* spectral feature extractors? :
bin freq
bin magnitude
bin phase
bin laden ;-}
average magnitude over a range of bins
max magnitude over a range of bins
max magnitude bin freq
*/
}
//////////////////////////////////////////////////////////////////////////////////////////////////
//SCPolarBuf* ToPolarApx(SndBuf *buf);
/*
SCPolarBuf* ToPolarApx(SndBuf *buf)
{
if (buf->coord == coord_Complex) {
SCComplexBuf* p = (SCComplexBuf*)buf->data;
int numbins = buf->samples - 2 >> 1;
for (int i=0; i<numbins; ++i) {
p->bin[i].ToPolarApxInPlace();
}
buf->coord = coord_Polar;
}
return (SCPolarBuf*)buf->data;
}
*/
//SCComplexBuf* ToComplexApx(SndBuf *buf);
/*
SCComplexBuf* ToComplexApx(SndBuf *buf)
{
if (buf->coord == coord_Polar) {
SCPolarBuf* p = (SCPolarBuf*)buf->data;
int numbins = buf->samples - 2 >> 1;
for (int i=0; i<numbins; ++i) {
p->bin[i].ToComplexApxInPlace();
}
buf->coord = coord_Complex;
}
return (SCComplexBuf*)buf->data;
}
*/
/////////////////////////////////////////////////////////////////////////////////////////////
void PV_MagAbove_next(PV_Unit *unit, int inNumSamples)
{
PV_GET_BUF
SCPolarBuf *p = ToPolarApx(buf);
float thresh = ZIN0(1);
if(std::abs(p->dc ) < thresh) p->dc = 0.f;
if(std::abs(p->nyq) < thresh) p->nyq = 0.f;
for (int i=0; i<numbins; ++i) {
float mag = p->bin[i].mag;
if (mag < thresh) p->bin[i].mag = 0.f;
}
}
void PV_MagAbove_Ctor(PV_Unit *unit)
{
SETCALC(PV_MagAbove_next);
ZOUT0(0) = ZIN0(0);
}
void PV_MagBelow_next(PV_Unit *unit, int inNumSamples)
{
PV_GET_BUF
SCPolarBuf *p = ToPolarApx(buf);
float thresh = ZIN0(1);
if(std::abs(p->dc ) > thresh) p->dc = 0.f;
if(std::abs(p->nyq) > thresh) p->nyq = 0.f;
for (int i=0; i<numbins; ++i) {
float mag = p->bin[i].mag;
if (mag > thresh) p->bin[i].mag = 0.f;
}
}
void PV_MagBelow_Ctor(PV_Unit *unit)
{
SETCALC(PV_MagBelow_next);
ZOUT0(0) = ZIN0(0);
}
void PV_MagClip_next(PV_Unit *unit, int inNumSamples)
{
PV_GET_BUF
SCPolarBuf *p = ToPolarApx(buf);
float thresh = ZIN0(1);
if(std::abs(p->dc ) > thresh) p->dc = p->dc < 0.f ? -thresh : thresh;
if(std::abs(p->nyq) > thresh) p->nyq = p->nyq < 0.f ? -thresh : thresh;
for (int i=0; i<numbins; ++i) {
float mag = p->bin[i].mag;
if (mag > thresh) p->bin[i].mag = thresh;
}
}
void PV_MagClip_Ctor(PV_Unit *unit)
{
SETCALC(PV_MagClip_next);
ZOUT0(0) = ZIN0(0);
}
void PV_LocalMax_next(PV_Unit *unit, int inNumSamples)
{
PV_GET_BUF
SCPolarBuf *p = ToPolarApx(buf);
float thresh = ZIN0(1);
float dc, nyq, mag;
// DC is only compared with the one above it
dc = std::abs(p->dc);
mag = p->bin[0].mag;
if(dc < thresh || dc < mag) p->dc = 0.f;
// 0th bin compared against DC and 1th
if(mag < thresh || mag < dc || mag < p->bin[1].mag) p->bin[0].mag = 0.f;
// All the middling bins
for (int i=1; i<numbins-1; ++i) {
float mag = p->bin[i].mag;
if (mag < thresh || mag < p->bin[i-1].mag || mag < p->bin[i+1].mag) {
p->bin[i].mag = 0.f;
}
}
// Penultimate is compared against the one below and the nyq
nyq = std::abs(p->nyq);
mag = p->bin[numbins-1].mag;
if(mag < thresh || mag < nyq || mag < p->bin[numbins-2].mag) p->bin[numbins-1].mag = 0.f;
// Nyquist compared against penultimate
if(nyq < thresh || nyq < mag) p->nyq = 0.f;
}
void PV_LocalMax_Ctor(PV_Unit *unit)
{
SETCALC(PV_LocalMax_next);
ZOUT0(0) = ZIN0(0);
}
void PV_MagSmear_next(PV_MagSmear *unit, int inNumSamples)
{
PV_GET_BUF
MAKE_TEMP_BUF
SCPolarBuf *p = ToPolarApx(buf);
SCPolarBuf *q = (SCPolarBuf*)unit->m_tempbuf;
int width = (int)ZIN0(1);
width = sc_clip(width, 0, numbins-1);
float scale = 1.f / (2*width+1);
q->dc = p->dc;
q->nyq = p->nyq;
for (int j=0; j<numbins; j++) {
float sum = 0.0;
for (int pos = j-width; pos <= j+width; pos++) {
if (pos >= 0 && pos < numbins) {
sum += p->bin[pos].mag;
}
}
q->bin[j].Set( sum * scale, p->bin[j].phase );
}
for (int i=0; i<numbins; i++) {
p->bin[i] = q->bin[i];
}
}
void PV_MagSmear_Ctor(PV_MagSmear *unit)
{
SETCALC(PV_MagSmear_next);
ZOUT0(0) = ZIN0(0);
unit->m_tempbuf = 0;
}
void PV_MagSmear_Dtor(PV_MagSmear *unit)
{
RTFree(unit->mWorld, unit->m_tempbuf);
}
void PV_BinShift_next(PV_BinShift *unit, int inNumSamples)
{
PV_GET_BUF
MAKE_TEMP_BUF
// get shift and stretch params
float stretch = ZIN0(1);
float shift = ZIN0(2);
float interp = ZIN0(3);
SCComplexBuf *p = ToComplexApx(buf);
SCComplexBuf *q = (SCComplexBuf*)unit->m_tempbuf;
// initialize output buf to zeroes
for (int i=0; i<numbins; ++i) {
q->bin[i] = 0.f;
}
float fpos;
int i;
q->dc = p->dc;
q->nyq = p->nyq;
if(interp > 0){
for (i=0, fpos = shift; i < numbins; ++i, fpos += stretch) {
int32 fpos0 = (int32)std::floor(fpos);
int32 fpos1 = fpos0+1;
float beta = fpos - std::floor(fpos);
float alpha = 1.0f - beta;
if (fpos0 >= 0 && fpos0 < numbins) {
q->bin[fpos0] += alpha * p->bin[i];
}
if (fpos1 >= 0 && fpos1 < numbins) {
q->bin[fpos1] += beta * p->bin[i];
}
}
} else {
for (i=0, fpos = shift; i < numbins; ++i, fpos += stretch) {
int32 pos = (int32)(fpos + 0.5);
if (pos >= 0 && pos < numbins) {
q->bin[pos] += p->bin[i];
}
}
}
memcpy(p->bin, q->bin, numbins * sizeof(SCComplex));
}
void PV_BinShift_Ctor(PV_BinShift *unit)
{
SETCALC(PV_BinShift_next);
ZOUT0(0) = ZIN0(0);
unit->m_tempbuf = 0;
}
void PV_BinShift_Dtor(PV_BinShift *unit)
{
RTFree(unit->mWorld, unit->m_tempbuf);
}
void PV_MagShift_next(PV_MagShift *unit, int inNumSamples)
{
PV_GET_BUF
MAKE_TEMP_BUF
// get shift and stretch params
float stretch = ZIN0(1);
float shift = ZIN0(2);
SCPolarBuf *p = ToPolarApx(buf);
SCPolarBuf *q = (SCPolarBuf*)unit->m_tempbuf;
// initialize output buf to zeroes
for (int i=0; i<numbins; ++i) {
q->bin[i].mag = 0.f;
q->bin[i].phase = p->bin[i].phase;
}
float fpos;
int i;
q->dc = p->dc;
q->nyq = p->nyq;
for (i=0, fpos = shift; i < numbins; ++i, fpos += stretch) {
int32 pos = (int32)(fpos + 0.5);
if (pos >= 0 && pos < numbins) {
q->bin[pos].mag += p->bin[i].mag;
}
}
memcpy(p->bin, q->bin, numbins * sizeof(SCComplex));
}
void PV_MagShift_Ctor(PV_MagShift *unit)
{
SETCALC(PV_MagShift_next);
ZOUT0(0) = ZIN0(0);
unit->m_tempbuf = 0;
}
void PV_MagShift_Dtor(PV_MagShift *unit)
{
RTFree(unit->mWorld, unit->m_tempbuf);
}
void PV_MagNoise_next(PV_Unit *unit, int inNumSamples)
{
PV_GET_BUF
RGET
if (buf->coord == coord_Complex) {
SCComplexBuf *p = (SCComplexBuf*)buf->data;
for (int i=0; i<numbins; ++i) {
float r = frand2(s1, s2, s3);
p->bin[i].real *= r;
p->bin[i].imag *= r;
}
p->dc *= frand2(s1, s2, s3);
p->nyq *= frand2(s1, s2, s3);
} else {
SCPolarBuf *p = (SCPolarBuf*)buf->data;
for (int i=0; i<numbins; ++i) {
float r = frand2(s1, s2, s3);
p->bin[i].mag *= r;
}
p->dc *= frand2(s1, s2, s3);
p->nyq *= frand2(s1, s2, s3);
}
RPUT
}
void PV_MagNoise_Ctor(PV_Unit *unit)
{
SETCALC(PV_MagNoise_next);
ZOUT0(0) = ZIN0(0);
}
void PV_PhaseShift_next(PV_PhaseShift *unit, int inNumSamples)
{
PV_GET_BUF
SCPolarBuf *p = ToPolarApx(buf);
float shift = ZIN0(1);
int integrate = ZIN0(2);
float ashift = shift;
if (integrate > 0) {
ashift += unit->m_phase_integral;
unit->m_phase_integral = fmod(ashift, TWOPI);
}
for (int i=0; i<numbins; ++i) {
p->bin[i].phase += ashift;
}
}
void PV_PhaseShift_Ctor(PV_PhaseShift *unit)
{
SETCALC(PV_PhaseShift_next);
ZOUT0(0) = ZIN0(0);
unit->m_phase_integral = 0;
}
void PV_PhaseShift90_next(PV_Unit *unit, int inNumSamples)
{
PV_GET_BUF
SCComplexBuf *p = ToComplexApx(buf);
for (int i=0; i<numbins; ++i) {
float temp = p->bin[i].real;
p->bin[i].real = -p->bin[i].imag;
p->bin[i].imag = temp;
}
}
void PV_PhaseShift90_Ctor(PV_Unit *unit)
{
SETCALC(PV_PhaseShift90_next);
ZOUT0(0) = ZIN0(0);
}
void PV_PhaseShift270_next(PV_Unit *unit, int inNumSamples)
{
PV_GET_BUF
SCComplexBuf *p = ToComplexApx(buf);
for (int i=0; i<numbins; ++i) {
float temp = p->bin[i].real;
p->bin[i].real = p->bin[i].imag;
p->bin[i].imag = -temp;
}
}
void PV_PhaseShift270_Ctor(PV_Unit *unit)
{
SETCALC(PV_PhaseShift270_next);
ZOUT0(0) = ZIN0(0);
}
void PV_MagSquared_next(PV_Unit *unit, int inNumSamples)
{
PV_GET_BUF
SCPolarBuf *p = ToPolarApx(buf);
p->dc = p->dc * p->dc;
p->nyq = p->nyq * p->nyq;
for (int i=0; i<numbins; ++i) {
float mag = p->bin[i].mag;
p->bin[i].mag = mag * mag;
}
}
void PV_MagSquared_Ctor(PV_Unit *unit)
{
SETCALC(PV_MagSquared_next);
ZOUT0(0) = ZIN0(0);
}
void PV_BrickWall_next(PV_Unit *unit, int inNumSamples)
{
PV_GET_BUF
SCComplexBuf *p = (SCComplexBuf*)buf->data;
int wipe = (int)(ZIN0(1) * numbins);
if (wipe > 0) {
wipe = sc_min(wipe, numbins);
p->dc = 0.f;
for (int i=0; i < wipe; ++i) {
p->bin[i] = 0.f;
}
if(wipe==numbins) p->nyq = 0.f;
} else if (wipe < 0) {
wipe = sc_max(wipe, -numbins);
if(wipe==-numbins) p->dc = 0.f;
for (int i=numbins+wipe; i < numbins; ++i) {
p->bin[i] = 0.f;
}
p->nyq = 0.f;
}
}
void PV_BrickWall_Ctor(PV_Unit *unit)
{
SETCALC(PV_BrickWall_next);
ZOUT0(0) = ZIN0(0);
}
void PV_BinWipe_next(PV_Unit *unit, int inNumSamples)
{
PV_GET_BUF2
SCComplexBuf *p = (SCComplexBuf*)buf1->data;
SCComplexBuf *q = (SCComplexBuf*)buf2->data;
int wipe = (int)(ZIN0(2) * numbins);
if (wipe > 0) {
wipe = sc_min(wipe, numbins);
p->dc = q->dc;
for (int i=0; i < wipe; ++i) {
p->bin[i] = q->bin[i];
}
if(wipe==numbins) p->nyq = q->nyq;
} else if (wipe < 0) {
wipe = sc_max(wipe, -numbins);
if(wipe==-numbins) p->dc = q->dc;
for (int i=numbins+wipe; i < numbins; ++i) {
p->bin[i] = q->bin[i];
}
p->nyq = q->nyq;
}
}
void PV_BinWipe_Ctor(PV_Unit *unit)
{
SETCALC(PV_BinWipe_next);
ZOUT0(0) = ZIN0(0);
}
void PV_MagMul_next(PV_Unit *unit, int inNumSamples)
{
PV_GET_BUF2
SCPolarBuf *p = ToPolarApx(buf1);
SCPolarBuf *q = ToPolarApx(buf2);
p->dc *= q->dc;
p->nyq *= q->nyq;
for (int i=0; i<numbins; ++i) {
p->bin[i].mag *= q->bin[i].mag;
}
}
void PV_MagMul_Ctor(PV_Unit *unit)
{
SETCALC(PV_MagMul_next);
ZOUT0(0) = ZIN0(0);
}
void PV_MagDiv_next(PV_Unit *unit, int inNumSamples)
{
PV_GET_BUF2
SCPolarBuf *p = ToPolarApx(buf1);
SCPolarBuf *q = ToPolarApx(buf2);
float zeroed = ZIN0(2);
p->dc /= sc_max(q->dc, zeroed);
p->nyq /= sc_max(q->nyq, zeroed);
for (int i=0; i<numbins; ++i) {
p->bin[i].mag /= sc_max(q->bin[i].mag, zeroed);
}
}
void PV_MagDiv_Ctor(PV_Unit *unit)
{
SETCALC(PV_MagDiv_next);
ZOUT0(0) = ZIN0(0);
}
void PV_Copy_next(PV_Unit *unit, int inNumSamples)
{
float fbufnum1 = ZIN0(0);
float fbufnum2 = ZIN0(1);
if (fbufnum1 < 0.f || fbufnum2 < 0.f) { ZOUT0(0) = -1.f; return; }
ZOUT0(0) = fbufnum2;
uint32 ibufnum1 = (int)fbufnum1;
uint32 ibufnum2 = (int)fbufnum2;
World *world = unit->mWorld;
SndBuf *buf1;
SndBuf *buf2;
if (ibufnum1 >= world->mNumSndBufs) {
int localBufNum = ibufnum1 - world->mNumSndBufs;
Graph *parent = unit->mParent;
if(localBufNum <= parent->localBufNum) {
buf1 = parent->mLocalSndBufs + localBufNum;
} else {
buf1 = world->mSndBufs;
}
} else {
buf1 = world->mSndBufs + ibufnum1;
}
if (ibufnum2 >= world->mNumSndBufs) {
int localBufNum = ibufnum2 - world->mNumSndBufs;
Graph *parent = unit->mParent;
if(localBufNum <= parent->localBufNum) {
buf2 = parent->mLocalSndBufs + localBufNum;
} else {
buf2 = world->mSndBufs;
}
} else {
buf2 = world->mSndBufs + ibufnum2;
}
if (buf1->samples != buf2->samples) return;
// copy to buf2
LOCK_SNDBUF2_SHARED_EXCLUSIVE(buf1, buf2);
buf2->coord = buf1->coord;
memcpy(buf2->data, buf1->data, buf1->samples * sizeof(float));
}
void PV_Copy_Ctor(PV_Unit *unit)
{
SETCALC(PV_Copy_next);
ZOUT0(0) = ZIN0(1);
}
void PV_CopyPhase_next(PV_Unit *unit, int inNumSamples)
{
PV_GET_BUF2
SCPolarBuf *p = ToPolarApx(buf1);
SCPolarBuf *q = ToPolarApx(buf2);
if((p->dc > 0.f) == (q->dc < 0.f)) p->dc = -p->dc ;
if((p->nyq > 0.f) == (q->nyq < 0.f)) p->nyq = -p->nyq;
for (int i=0; i<numbins; ++i) {
p->bin[i].phase = q->bin[i].phase;
}
}
void PV_CopyPhase_Ctor(PV_Unit *unit)
{
SETCALC(PV_CopyPhase_next);
ZOUT0(0) = ZIN0(0);
}
void PV_Mul_next(PV_Unit *unit, int inNumSamples)
{
PV_GET_BUF2
SCComplexBuf *p = ToComplexApx(buf1);
SCComplexBuf *q = ToComplexApx(buf2);
float preal, realmul, imagmul;
p->dc *= q->dc;
p->nyq *= q->nyq;
for (int i=0; i<numbins; ++i) {
preal = p->bin[i].real;
// Complex multiply using only 3 multiplications rather than 4. http://mathworld.wolfram.com/ComplexMultiplication.html
realmul = (preal * q->bin[i].real);
imagmul = (p->bin[i].imag * q->bin[i].imag);
p->bin[i].real = realmul - imagmul;
p->bin[i].imag = (preal + p->bin[i].imag) * (q->bin[i].real + q->bin[i].imag) - realmul - imagmul;
}
}
void PV_Mul_Ctor(PV_Unit *unit)
{
SETCALC(PV_Mul_next);
ZOUT0(0) = ZIN0(0);
}
void PV_Div_next(PV_Unit *unit, int inNumSamples)
{
PV_GET_BUF2
SCComplexBuf *p = ToComplexApx(buf1);
SCComplexBuf *q = ToComplexApx(buf2);
p->dc /= q->dc;
p->nyq /= q->nyq;
for (int i=0; i<numbins; ++i) {
// See http://gcc.gnu.org/ml/fortran/2004-05/msg00029.html
// Note that hypot has danger of overflow (see URL above),
// however FFT values typically stay within a small range,
// so I'm considering this OK for now.
float hypot = q->bin[i].real * q->bin[i].real + q->bin[i].imag * q->bin[i].imag;
float preal = p->bin[i].real;
p->bin[i].real = (preal * q->bin[i].real + p->bin[i].imag * q->bin[i].imag) / hypot;
p->bin[i].imag = (p->bin[i].imag * q->bin[i].real - preal * q->bin[i].imag) / hypot;
}
}
void PV_Div_Ctor(PV_Unit *unit)
{
SETCALC(PV_Div_next);
ZOUT0(0) = ZIN0(0);
}
void PV_Add_next(PV_Unit *unit, int inNumSamples)
{
PV_GET_BUF2
SCComplexBuf *p = ToComplexApx(buf1);
SCComplexBuf *q = ToComplexApx(buf2);
p->dc += q->dc;
p->nyq += q->nyq;
for (int i=0; i<numbins; ++i) {
p->bin[i].real += q->bin[i].real;
p->bin[i].imag += q->bin[i].imag;
}
}
void PV_Add_Ctor(PV_Unit *unit)
{
SETCALC(PV_Add_next);
ZOUT0(0) = ZIN0(0);
}
void PV_Max_next(PV_Unit *unit, int inNumSamples)
{
PV_GET_BUF2
SCPolarBuf *p = ToPolarApx(buf1);
SCPolarBuf *q = ToPolarApx(buf2);
if(std::abs(q->dc ) > std::abs(p->dc )) p->dc = q->dc ;
if(std::abs(q->nyq) > std::abs(p->nyq)) p->nyq = q->nyq;
for (int i=0; i<numbins; ++i) {
if (q->bin[i].mag > p->bin[i].mag) {
p->bin[i] = q->bin[i];
}
}
}
void PV_Max_Ctor(PV_Unit *unit)
{
SETCALC(PV_Max_next);
ZOUT0(0) = ZIN0(0);
}
void PV_Min_next(PV_Unit *unit, int inNumSamples)
{
PV_GET_BUF2
SCPolarBuf *p = ToPolarApx(buf1);
SCPolarBuf *q = ToPolarApx(buf2);
if(std::abs(q->dc ) < std::abs(p->dc )) p->dc = q->dc ;
if(std::abs(q->nyq) < std::abs(p->nyq)) p->nyq = q->nyq;
for (int i=0; i<numbins; ++i) {
if (q->bin[i].mag < p->bin[i].mag) {
p->bin[i] = q->bin[i];
}
}
}
void PV_Min_Ctor(PV_Unit *unit)
{
SETCALC(PV_Min_next);
ZOUT0(0) = ZIN0(0);
}
void PV_RectComb_next(PV_Unit *unit, int inNumSamples)
{
PV_GET_BUF
float numTeeth = ZIN0(1);
float phase = ZIN0(2);
float width = ZIN0(3);
float freq = numTeeth / (numbins + 1);
SCComplexBuf *p = (SCComplexBuf*)buf->data;
if (phase > width) p->dc = 0.f;
phase += freq;
if (phase >= 1.f) phase -= 1.f;
else if (phase < 0.f) phase += 1.f;
for (int i=0; i < numbins; ++i) {
if (phase > width) p->bin[i] = 0.f;
phase += freq;
if (phase >= 1.f) phase -= 1.f;
else if (phase < 0.f) phase += 1.f;
}
if (phase > width) p->nyq = 0.f;
}
void PV_RectComb_Ctor(PV_Unit *unit)
{
SETCALC(PV_RectComb_next);
ZOUT0(0) = ZIN0(0);
}
void PV_RectComb2_next(PV_Unit *unit, int inNumSamples)
{
PV_GET_BUF2
float numTeeth = ZIN0(2);
float phase = ZIN0(3);
float width = ZIN0(4);
float freq = numTeeth / (numbins + 1);
SCComplexBuf *p = (SCComplexBuf*)buf1->data;
SCComplexBuf *q = (SCComplexBuf*)buf2->data;
if (phase > width) p->dc = q->dc;
phase += freq;
if (phase >= 1.f) phase -= 1.f;
else if (phase < 0.f) phase += 1.f;
for (int i=0; i < numbins; ++i) {
if (phase > width) p->bin[i] = q->bin[i];
phase += freq;
if (phase >= 1.f) phase -= 1.f;
else if (phase < 0.f) phase += 1.f;
}
if (phase > width) p->nyq = q->nyq;
}
void PV_RectComb2_Ctor(PV_Unit *unit)
{
SETCALC(PV_RectComb2_next);
ZOUT0(0) = ZIN0(0);
}
static void PV_RandComb_choose(PV_RandComb* unit)
{
int numbins = unit->m_numbins;
for (int i=0; i<numbins; ++i) {
unit->m_ordering[i] = i;
}
RGET
for (int i=0; i<numbins; ++i) {
int32 j = (int32)(frand(s1,s2,s3) * (numbins - i));
int32 temp = unit->m_ordering[i];
unit->m_ordering[i] = unit->m_ordering[j];
unit->m_ordering[j] = temp;
}
RPUT
}
void PV_RandComb_next(PV_RandComb *unit, int inNumSamples)
{
float trig = ZIN0(2);
if (trig > 0.f && unit->m_prevtrig <= 0.f) unit->m_triggered = true;
unit->m_prevtrig = trig;
PV_GET_BUF
if (!unit->m_ordering) {
unit->m_ordering = (int*)RTAlloc(unit->mWorld, numbins * sizeof(int));
unit->m_numbins = numbins;
PV_RandComb_choose(unit);
} else {
if (numbins != unit->m_numbins) return;
if (unit->m_triggered) {
unit->m_triggered = false;
PV_RandComb_choose(unit);
}
}
int n = (int)(ZIN0(1) * numbins);
n = sc_clip(n, 0, numbins);
SCComplexBuf *p = (SCComplexBuf*)buf->data;
int *ordering = unit->m_ordering;
for (int i=0; i<n; ++i) {
p->bin[ordering[i]] = 0.f;
}
if(n==numbins){
// including dc and nyq in the above shuffle would add too much complexity. but at full "wipe" we should get silence.
p->dc = 0.f;
p->nyq = 0.f;
}
}
void PV_RandComb_Ctor(PV_RandComb* unit)
{
SETCALC(PV_RandComb_next);
ZOUT0(0) = ZIN0(0);
unit->m_ordering = 0;
unit->m_prevtrig = 0.f;
unit->m_triggered = false;
}
void PV_RandComb_Dtor(PV_RandComb* unit)
{
RTFree(unit->mWorld, unit->m_ordering);
}
//////////////////////
static void PV_RandWipe_choose(PV_RandWipe* unit)
{
int numbins = unit->m_numbins;
for (int i=0; i<numbins; ++i) {
unit->m_ordering[i] = i;
}
RGET
for (int i=0; i<numbins; ++i) {
int32 j = (int32)(frand(s1,s2,s3) * (numbins - i));
int32 temp = unit->m_ordering[i];
unit->m_ordering[i] = unit->m_ordering[j];
unit->m_ordering[j] = temp;
}
RPUT
}
void PV_RandWipe_next(PV_RandWipe *unit, int inNumSamples)
{
float trig = ZIN0(3);
if (trig > 0.f && unit->m_prevtrig <= 0.f) unit->m_triggered = true;
unit->m_prevtrig = trig;
PV_GET_BUF2
if (!unit->m_ordering) {
unit->m_ordering = (int*)RTAlloc(unit->mWorld, numbins * sizeof(int));
unit->m_numbins = numbins;
PV_RandWipe_choose(unit);
} else {
if (numbins != unit->m_numbins) return;
if (unit->m_triggered) {
unit->m_triggered = false;
PV_RandWipe_choose(unit);
}
}
int n = (int)(ZIN0(2) * numbins);
n = sc_clip(n, 0, numbins);
SCComplexBuf *p = (SCComplexBuf*)buf1->data;
SCComplexBuf *q = (SCComplexBuf*)buf2->data;
int *ordering = unit->m_ordering;
for (int i=0; i<n; ++i) {
p->bin[ordering[i]] = q->bin[ordering[i]];
}
}
void PV_RandWipe_Ctor(PV_RandWipe* unit)
{
SETCALC(PV_RandWipe_next);
ZOUT0(0) = ZIN0(0);
unit->m_ordering = 0;
unit->m_prevtrig = 0.f;
unit->m_triggered = false;
}
void PV_RandWipe_Dtor(PV_RandWipe* unit)
{
RTFree(unit->mWorld, unit->m_ordering);
}
//////////////////////
static void PV_Diffuser_choose(PV_Diffuser* unit)
{
RGET
for (int i=0; i<unit->m_numbins; ++i) {
unit->m_shift[i] = frand(s1,s2,s3) * twopi;
}
RPUT
}
void PV_Diffuser_next(PV_Diffuser *unit, int inNumSamples)
{
float trig = ZIN0(1);
if (trig > 0.f && unit->m_prevtrig <= 0.f) unit->m_triggered = true;
unit->m_prevtrig = trig;
PV_GET_BUF
if (!unit->m_shift) {
unit->m_shift = (float*)RTAlloc(unit->mWorld, numbins * sizeof(float));
unit->m_numbins = numbins;
PV_Diffuser_choose(unit);
} else {
if (numbins != unit->m_numbins) return;
if (unit->m_triggered) {
unit->m_triggered = false;
PV_Diffuser_choose(unit);
}
}
int n = (int)(ZIN0(1) * numbins);
n = sc_clip(n, 0, numbins);
SCPolarBuf *p = ToPolarApx(buf);
float *shift = unit->m_shift;
for (int i=0; i<n; ++i) {
p->bin[i].phase += shift[i];
}
}
void PV_Diffuser_Ctor(PV_Diffuser* unit)
{
SETCALC(PV_Diffuser_next);
ZOUT0(0) = ZIN0(0);
unit->m_shift = 0;
unit->m_prevtrig = 0.f;
unit->m_triggered = false;
}
void PV_Diffuser_Dtor(PV_Diffuser* unit)
{
RTFree(unit->mWorld, unit->m_shift);
}
//////////////////////
void PV_MagFreeze_next(PV_MagFreeze *unit, int inNumSamples)
{
PV_GET_BUF
float freeze = ZIN0(1);
if (!unit->m_mags) {
unit->m_mags = (float*)RTAlloc(unit->mWorld, numbins * sizeof(float));
unit->m_numbins = numbins;
// The first fft frame must use the else branch below
// so that unit->m_mags gets populated with actual mag data
// before reading; otherwise it might be used uninitialized.
freeze = 0.f;
} else if (numbins != unit->m_numbins) return;
SCPolarBuf *p = ToPolarApx(buf);
float *mags = unit->m_mags;
if (freeze > 0.f) {
for (int i=0; i<numbins; ++i) {
p->bin[i].mag = mags[i];
}
p->dc = unit->m_dc;
p->nyq = unit->m_nyq;
} else {
for (int i=0; i<numbins; ++i) {
mags[i] = p->bin[i].mag;
}
unit->m_dc = p->dc;
unit->m_nyq = p->nyq;
}
}
void PV_MagFreeze_Ctor(PV_MagFreeze* unit)
{
SETCALC(PV_MagFreeze_next);
ZOUT0(0) = ZIN0(0);
unit->m_mags = 0;
}
void PV_MagFreeze_Dtor(PV_MagFreeze* unit)
{
RTFree(unit->mWorld, unit->m_mags);
}
//////////////////////
static void PV_BinScramble_choose(PV_BinScramble* unit)
{
int numbins = unit->m_numbins;
int *to = unit->m_to;
int *from = unit->m_from;
for (int i=0; i<numbins; ++i) {
to[i] = i;
}
RGET
for (int i=0; i<numbins; ++i) {
int32 j = (int32)(frand(s1,s2,s3) * (numbins - i));
int32 temp = to[i];
to[i] = to[j];
to[j] = temp;
}
int32 width = (int32)(ZIN0(2) * numbins);
for (int i=0; i<numbins; ++i) {
int32 k = to[i];
int32 minr = sc_max(0, k-width);
int32 maxr = sc_min(numbins-1, k+width);
int32 j = (int32)(frand(s1,s2,s3) * (maxr - minr) + minr);
from[i] = j;
}
RPUT
}
void PV_BinScramble_next(PV_BinScramble *unit, int inNumSamples)
{
float trig = ZIN0(3);
if (trig > 0.f && unit->m_prevtrig <= 0.f) unit->m_triggered = true;
unit->m_prevtrig = trig;
PV_GET_BUF
if (!unit->m_to) {
unit->m_to = (int*)RTAlloc(unit->mWorld, numbins * 2 * sizeof(int));
unit->m_from = unit->m_to + numbins;
unit->m_numbins = numbins;
unit->m_tempbuf = (float*)RTAlloc(unit->mWorld, buf->samples * sizeof(float));
PV_BinScramble_choose(unit);
} else {
if (numbins != unit->m_numbins) return;
if (unit->m_triggered) {
unit->m_triggered = false;
PV_BinScramble_choose(unit);
}
}
SCComplexBuf *p = (SCComplexBuf*)buf->data;
SCComplexBuf *q = (SCComplexBuf*)unit->m_tempbuf;
float wipe = ZIN0(1);
int32 scrambleBins = (int32)(numbins * sc_clip(wipe, 0.f, 1.f));
int *to = unit->m_to;
int *from = unit->m_from;
for (int j=0; j<scrambleBins; j++) {
q->bin[to[j]] = p->bin[from[j]];
}
for (int j=scrambleBins; j<numbins; j++) {
int32 a = to[j];
q->bin[a] = p->bin[a];
}
q->dc = p->dc;
q->nyq = p->nyq;
memcpy(p->bin, q->bin, numbins * sizeof(SCComplex));
}
void PV_BinScramble_Ctor(PV_BinScramble* unit)
{
SETCALC(PV_BinScramble_next);
ZOUT0(0) = ZIN0(0);
unit->m_to = 0;
unit->m_prevtrig = 0.f;
unit->m_triggered = false;
unit->m_tempbuf = 0;
}
void PV_BinScramble_Dtor(PV_BinScramble* unit)
{
RTFree(unit->mWorld, unit->m_to);
RTFree(unit->mWorld, unit->m_tempbuf);
}
void PV_Conj_Ctor(PV_Unit *unit)
{
SETCALC(PV_Conj_next);
ZOUT0(0) = ZIN0(0);
}
void PV_Conj_next(PV_Unit *unit, int inNumSamples)
{
PV_GET_BUF
SCComplexBuf *p = ToComplexApx(buf);
for (int i=0; i<numbins; ++i) {
p->bin[i].imag = 0.f - p->bin[i].imag;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
#define DefinePVUnit(name) \
(*ft->fDefineUnit)(#name, sizeof(PV_Unit), (UnitCtorFunc)&name##_Ctor, 0, 0);
void initPV(InterfaceTable *inTable)
{
DefinePVUnit(PV_MagAbove);
DefinePVUnit(PV_MagBelow);
DefinePVUnit(PV_MagClip);
DefinePVUnit(PV_MagMul);
DefinePVUnit(PV_MagDiv);
DefinePVUnit(PV_MagSquared);
DefinePVUnit(PV_MagNoise);
DefinePVUnit(PV_Copy);
DefinePVUnit(PV_CopyPhase);
DefinePVUnit(PV_PhaseShift);
DefinePVUnit(PV_PhaseShift90);
DefinePVUnit(PV_PhaseShift270);
DefinePVUnit(PV_Min);
DefinePVUnit(PV_Max);
DefinePVUnit(PV_Mul);
DefinePVUnit(PV_Div);
DefinePVUnit(PV_Add);
DefinePVUnit(PV_RectComb);
DefinePVUnit(PV_RectComb2);
DefinePVUnit(PV_BrickWall);
DefinePVUnit(PV_BinWipe);
DefinePVUnit(PV_LocalMax);
DefinePVUnit(PV_Conj);
DefineDtorUnit(PV_BinScramble);
DefineDtorUnit(PV_MagSmear);
DefineDtorUnit(PV_MagShift);
DefineDtorUnit(PV_BinShift);
DefineDtorUnit(PV_RandWipe);
DefineDtorUnit(PV_Diffuser);
DefineDtorUnit(PV_RandComb);
DefineDtorUnit(PV_MagFreeze);
}
Jump to Line
Something went wrong with that request. Please try again.