Skip to content
Permalink
master
Go to file
 
 
Cannot retrieve contributors at this time
306 lines (249 sloc) 8.19 KB
/* -*- mode: c++; indent-tabs-mode: nil; c-basic-offset: 4 -*-
vim: et sta sw=4:
skUG - SuperCollider UGen Library
Copyright (c) 2005-2008 Stefan Kersten. All rights reserved.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA
*/
#include <SC_PlugIn.h>
#include <math.h>
static InterfaceTable *ft;
struct FM7Op
{
int32 m_phase;
float m_freq;
float m_phasemod;
float m_amp;
float m_mem;
};
struct FM7 : public Unit
{
static const int kNumOps = 6;
static const int kNumOps2 = kNumOps * kNumOps;
enum {
kFreq = 0,
kPhase,
kAmp,
kNumControls
};
double m_cpstoinc;
double m_radtoinc;
int32 m_lomask;
FM7Op m_ops[kNumOps];
float m_mod[kNumOps2];
};
extern "C"
{
void FM7_Ctor(FM7 *unit);
void FM7_next_kk(FM7 *unit, int inNumSamples);
void FM7_next_ki(FM7 *unit, int inNumSamples);
};
#define FM7_OP_INDEX(i) ((i) * FM7::kNumControls)
#define FM7_FREQ_INDEX(i) (FM7_OP_INDEX(i) + FM7::kFreq)
#define FM7_PHASE_INDEX(i) (FM7_OP_INDEX(i) + FM7::kPhase)
#define FM7_AMP_INDEX(i) (FM7_OP_INDEX(i) + FM7::kAmp)
#define FM7_MOD_BASE (FM7::kNumControls * FM7::kNumOps)
#define FM7_DECLARE(i) \
int32 phase##i; \
float phasemodx##i; \
float freq##i; \
float freqinc##i; \
float phasemod##i; \
float phasemodinc##i; \
float amp##i; \
float ampinc##i; \
float mem##i; \
float *zout##i
#define FM7_IMPORT(ops, i) \
{ \
FM7Op *op = (ops) + i; \
phase##i = op->m_phase; \
freq##i = op->m_freq; \
float nextfreq = ZIN0(FM7_FREQ_INDEX(i)); \
freqinc##i = CALCSLOPE(nextfreq, freq##i); \
phasemod##i = op->m_phasemod; \
float nextphasemod = ZIN0(FM7_PHASE_INDEX(i)); \
phasemodinc##i = CALCSLOPE(nextphasemod, phasemod##i); \
amp##i = op->m_amp; \
float nextamp = ZIN0(FM7_AMP_INDEX(i)); \
ampinc##i = CALCSLOPE(nextamp, amp##i); \
mem##i = op->m_mem; \
zout##i = ZOUT(i); \
}
#define FM7_EXPORT(ops, i) \
{ \
FM7Op *op = (ops) + i; \
op->m_phase = phase##i; \
op->m_freq = freq##i; \
op->m_phasemod = phasemod##i; \
op->m_amp = amp##i; \
op->m_mem = mem##i; \
}
#define FM7_PHASE_MOD(mod, j) \
((mod)[j] * mem##j)
#define FM7_MOD_NEXT(i, mod) \
phasemodx##i = phasemod##i + \
FM7_PHASE_MOD(mod, 0) + FM7_PHASE_MOD(mod, 1) + \
FM7_PHASE_MOD(mod, 2) + FM7_PHASE_MOD(mod, 3) + \
FM7_PHASE_MOD(mod, 4) + FM7_PHASE_MOD(mod, 5)
#define FM7_OP_NEXT(i, t0, t1, tmask, radtoinc, cpstoinc) \
mem##i = amp##i * \
lookupi1((t0), (t1), \
phase##i + (int32)(phasemodx##i * (radtoinc)), \
(tmask)); \
ZXP(zout##i) = mem##i; \
phase##i += (int32)(freq##i * (cpstoinc)); \
freq##i += freqinc##i; \
phasemod##i += phasemodinc##i; \
amp##i += ampinc##i;
void FM7_next_kk(FM7 *unit, int inNumSamples)
{
const int32 lomask = unit->m_lomask;
const float cpstoinc = unit->m_cpstoinc;
const float radtoinc = unit->m_radtoinc;
FM7Op *ops = unit->m_ops;
float *table0 = ft->mSineWavetable;
float *table1 = table0 + 1;
float* mod0 = unit->m_mod;
float* mod1 = mod0 + FM7::kNumOps;
float* mod2 = mod1 + FM7::kNumOps;
float* mod3 = mod2 + FM7::kNumOps;
float* mod4 = mod3 + FM7::kNumOps;
float* mod5 = mod4 + FM7::kNumOps;
float modinc[FM7::kNumOps2];
FM7_DECLARE(0);
FM7_IMPORT(ops, 0);
FM7_DECLARE(1);
FM7_IMPORT(ops, 1);
FM7_DECLARE(2);
FM7_IMPORT(ops, 2);
FM7_DECLARE(3);
FM7_IMPORT(ops, 3);
FM7_DECLARE(4);
FM7_IMPORT(ops, 4);
FM7_DECLARE(5);
FM7_IMPORT(ops, 5);
for (int i=0, mi = FM7_MOD_BASE; i < FM7::kNumOps2; i++, mi++) {
float next = ZIN0(mi);
modinc[i] = CALCSLOPE(next, mod0[i]);
}
LooP(inNumSamples) {
FM7_MOD_NEXT(0, mod0);
FM7_MOD_NEXT(1, mod1);
FM7_MOD_NEXT(2, mod2);
FM7_MOD_NEXT(3, mod3);
FM7_MOD_NEXT(4, mod4);
FM7_MOD_NEXT(5, mod5);
FM7_OP_NEXT(0, table0, table1, lomask, radtoinc, cpstoinc);
FM7_OP_NEXT(1, table0, table1, lomask, radtoinc, cpstoinc);
FM7_OP_NEXT(2, table0, table1, lomask, radtoinc, cpstoinc);
FM7_OP_NEXT(3, table0, table1, lomask, radtoinc, cpstoinc);
FM7_OP_NEXT(4, table0, table1, lomask, radtoinc, cpstoinc);
FM7_OP_NEXT(5, table0, table1, lomask, radtoinc, cpstoinc);
for (int i=0; i < FM7::kNumOps2; i++) mod0[i] += modinc[i];
}
FM7_EXPORT(ops, 0);
FM7_EXPORT(ops, 1);
FM7_EXPORT(ops, 2);
FM7_EXPORT(ops, 3);
FM7_EXPORT(ops, 4);
FM7_EXPORT(ops, 5);
}
void FM7_next_ki(FM7 *unit, int inNumSamples)
{
const int32 lomask = unit->m_lomask;
const float cpstoinc = unit->m_cpstoinc;
const float radtoinc = unit->m_radtoinc;
FM7Op *ops = unit->m_ops;
float *table0 = ft->mSineWavetable;
float *table1 = table0 + 1;
float *mod0 = unit->m_mod;
float* mod1 = mod0 + FM7::kNumOps;
float* mod2 = mod1 + FM7::kNumOps;
float* mod3 = mod2 + FM7::kNumOps;
float* mod4 = mod3 + FM7::kNumOps;
float* mod5 = mod4 + FM7::kNumOps;
FM7_DECLARE(0);
FM7_IMPORT(ops, 0);
FM7_DECLARE(1);
FM7_IMPORT(ops, 1);
FM7_DECLARE(2);
FM7_IMPORT(ops, 2);
FM7_DECLARE(3);
FM7_IMPORT(ops, 3);
FM7_DECLARE(4);
FM7_IMPORT(ops, 4);
FM7_DECLARE(5);
FM7_IMPORT(ops, 5);
LooP(inNumSamples) {
FM7_MOD_NEXT(0, mod0);
FM7_MOD_NEXT(1, mod1);
FM7_MOD_NEXT(2, mod2);
FM7_MOD_NEXT(3, mod3);
FM7_MOD_NEXT(4, mod4);
FM7_MOD_NEXT(5, mod5);
FM7_OP_NEXT(0, table0, table1, lomask, radtoinc, cpstoinc);
FM7_OP_NEXT(1, table0, table1, lomask, radtoinc, cpstoinc);
FM7_OP_NEXT(2, table0, table1, lomask, radtoinc, cpstoinc);
FM7_OP_NEXT(3, table0, table1, lomask, radtoinc, cpstoinc);
FM7_OP_NEXT(4, table0, table1, lomask, radtoinc, cpstoinc);
FM7_OP_NEXT(5, table0, table1, lomask, radtoinc, cpstoinc);
}
FM7_EXPORT(ops, 0);
FM7_EXPORT(ops, 1);
FM7_EXPORT(ops, 2);
FM7_EXPORT(ops, 3);
FM7_EXPORT(ops, 4);
FM7_EXPORT(ops, 5);
}
void FM7_Ctor(FM7 *unit)
{
int modRate = calc_ScalarRate;
for (int i=0, mi=FM7_MOD_BASE; i < FM7::kNumOps2; i++, mi++) {
if (INRATE(mi) != calc_ScalarRate) {
modRate = calc_BufRate;
break;
}
}
if (modRate == calc_ScalarRate) {
SETCALC(FM7_next_ki);
} else {
SETCALC(FM7_next_kk);
}
// Initialize fixed point table lookup arithmetic
int tableSize = ft->mSineSize;
unit->m_cpstoinc = tableSize * SAMPLEDUR * 65536.;
unit->m_radtoinc = tableSize * rtwopi * 65536.;
unit->m_lomask = (tableSize - 1) << 3;
FM7Op *ops = unit->m_ops;
float *mod = unit->m_mod;
for (int i=0, mi=FM7_MOD_BASE; i < FM7::kNumOps; i++) {
FM7Op *op = ops + i;
op->m_phase = 0;
// op->m_phase = (int32)(ZIN0(FM7_PHASE_INDEX(i)) * unit->m_radtoinc);
op->m_freq = ZIN0(FM7_FREQ_INDEX(i));
op->m_phasemod = ZIN0(FM7_PHASE_INDEX(i));
op->m_amp = ZIN0(FM7_AMP_INDEX(i));
op->m_mem = 0.f;
for (int j=0; j < FM7::kNumOps; j++, mi++) {
*mod++ = ZIN0(mi);
}
}
FM7_next_ki(unit, 1);
}
PluginLoad(FM7)
{
ft = inTable;
DefineSimpleUnit(FM7);
}
// EOF