/**************************************************************************
 * Copyright 2009-2015 Olivier Belanger                                   *
 *                                                                        *
 * This file is part of pyo, a python module to help digital signal       *
 * processing script creation.                                            *
 *                                                                        *
 * pyo is free software: you can redistribute it and/or modify            *
 * it under the terms of the GNU Lesser General Public License as         *
 * published by the Free Software Foundation, either version 3 of the     *
 * License, or (at your option) any later version.                        *
 *                                                                        *
 * pyo 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 Lesser General Public License for more details.                    *
 *                                                                        *
 * You should have received a copy of the GNU Lesser General Public       *
 * License along with pyo.  If not, see <http://www.gnu.org/licenses/>.   *
 *************************************************************************/

#include <Python.h>
#include "structmember.h"
#include <math.h>
#include "pyomodule.h"
#include "streammodule.h"
#include "servermodule.h"
#include "dummymodule.h"
#include "tablemodule.h"
#include "interpolation.h"

static MYFLT SINE_ARRAY[513] = {0.0, 0.012271538285719925, 0.024541228522912288, 0.036807222941358832, 0.049067674327418015, 0.061320736302208578, 0.073564563599667426, 0.085797312344439894, 0.098017140329560604, 0.11022220729388306, 0.1224106751992162, 0.13458070850712617, 0.14673047445536175, 0.15885814333386145, 0.17096188876030122, 0.18303988795514095, 0.19509032201612825, 0.20711137619221856, 0.2191012401568698, 0.23105810828067111, 0.24298017990326387, 0.25486565960451457, 0.26671275747489837, 0.27851968938505306, 0.29028467725446233, 0.30200594931922808, 0.31368174039889152, 0.32531029216226293, 0.33688985339222005, 0.34841868024943456, 0.35989503653498811, 0.37131719395183754, 0.38268343236508978, 0.3939920400610481, 0.40524131400498986, 0.41642956009763715, 0.42755509343028208, 0.43861623853852766, 0.44961132965460654, 0.46053871095824001, 0.47139673682599764, 0.48218377207912272, 0.49289819222978404, 0.50353838372571758, 0.51410274419322166, 0.52458968267846895, 0.53499761988709715, 0.54532498842204646, 0.55557023301960218, 0.56573181078361312, 0.57580819141784534, 0.58579785745643886, 0.59569930449243336, 0.60551104140432555, 0.61523159058062682, 0.62485948814238634, 0.63439328416364549, 0.64383154288979139, 0.65317284295377676, 0.66241577759017178, 0.67155895484701833, 0.68060099779545302, 0.68954054473706683, 0.69837624940897292, 0.70710678118654746, 0.71573082528381859, 0.72424708295146689, 0.7326542716724127, 0.74095112535495899, 0.74913639452345926, 0.75720884650648446, 0.76516726562245885, 0.77301045336273688, 0.78073722857209438, 0.78834642762660623, 0.79583690460888346, 0.80320753148064483, 0.81045719825259477, 0.81758481315158371, 0.82458930278502529, 0.83146961230254512, 0.83822470555483797, 0.84485356524970701, 0.8513551931052652, 0.85772861000027212, 0.8639728561215867, 0.87008699110871135, 0.87607009419540649, 0.88192126434835494, 0.88763962040285393, 0.89322430119551532, 0.89867446569395382, 0.90398929312344334, 0.90916798309052238, 0.91420975570353069, 0.91911385169005777, 0.92387953251128674, 0.92850608047321548, 0.93299279883473885, 0.93733901191257496, 0.94154406518302081, 0.94560732538052128, 0.94952818059303667, 0.95330604035419375, 0.95694033573220894, 0.96043051941556579, 0.96377606579543984, 0.96697647104485207, 0.97003125319454397, 0.97293995220556007, 0.97570213003852857, 0.97831737071962765, 0.98078528040323043, 0.98310548743121629, 0.98527764238894122, 0.98730141815785843, 0.98917650996478101, 0.99090263542778001, 0.99247953459870997, 0.99390697000235606, 0.99518472667219682, 0.996312612182778, 0.99729045667869021, 0.99811811290014918, 0.99879545620517241, 0.99932238458834954, 0.99969881869620425, 0.9999247018391445, 1.0, 0.9999247018391445, 0.99969881869620425, 0.99932238458834954, 0.99879545620517241, 0.99811811290014918, 0.99729045667869021, 0.996312612182778, 0.99518472667219693, 0.99390697000235606, 0.99247953459870997, 0.99090263542778001, 0.98917650996478101, 0.98730141815785843, 0.98527764238894122, 0.98310548743121629, 0.98078528040323043, 0.97831737071962765, 0.97570213003852857, 0.97293995220556018, 0.97003125319454397, 0.96697647104485207, 0.96377606579543984, 0.9604305194155659, 0.95694033573220894, 0.95330604035419386, 0.94952818059303667, 0.94560732538052139, 0.94154406518302081, 0.93733901191257496, 0.93299279883473885, 0.92850608047321559, 0.92387953251128674, 0.91911385169005777, 0.91420975570353069, 0.90916798309052249, 0.90398929312344345, 0.89867446569395393, 0.89322430119551521, 0.88763962040285393, 0.88192126434835505, 0.8760700941954066, 0.87008699110871146, 0.86397285612158681, 0.85772861000027212, 0.8513551931052652, 0.84485356524970723, 0.83822470555483819, 0.83146961230254546, 0.82458930278502529, 0.81758481315158371, 0.81045719825259477, 0.80320753148064494, 0.79583690460888357, 0.78834642762660634, 0.7807372285720946, 0.7730104533627371, 0.76516726562245907, 0.75720884650648479, 0.74913639452345926, 0.74095112535495899, 0.73265427167241282, 0.724247082951467, 0.71573082528381871, 0.70710678118654757, 0.69837624940897292, 0.68954054473706705, 0.68060099779545324, 0.67155895484701855, 0.66241577759017201, 0.65317284295377664, 0.64383154288979139, 0.63439328416364549, 0.62485948814238634, 0.61523159058062693, 0.60551104140432555, 0.59569930449243347, 0.58579785745643898, 0.57580819141784545, 0.56573181078361345, 0.55557023301960218, 0.54532498842204635, 0.53499761988709715, 0.52458968267846895, 0.51410274419322177, 0.50353838372571758, 0.49289819222978415, 0.48218377207912289, 0.47139673682599781, 0.46053871095824023, 0.44961132965460687, 0.43861623853852755, 0.42755509343028203, 0.41642956009763715, 0.40524131400498986, 0.39399204006104815, 0.38268343236508984, 0.37131719395183765, 0.35989503653498833, 0.34841868024943479, 0.33688985339222027, 0.3253102921622632, 0.31368174039889141, 0.30200594931922803, 0.29028467725446233, 0.27851968938505312, 0.26671275747489848, 0.25486565960451468, 0.24298017990326404, 0.2310581082806713, 0.21910124015687002, 0.20711137619221884, 0.19509032201612858, 0.1830398879551409, 0.17096188876030119, 0.15885814333386145, 0.1467304744553618, 0.13458070850712628, 0.12241067519921635, 0.11022220729388325, 0.09801714032956084, 0.085797312344440158, 0.073564563599667745, 0.061320736302208495, 0.049067674327417973, 0.036807222941358832, 0.024541228522912326, 0.012271538285720007, 1.2246467991473532e-16, -0.012271538285719761, -0.024541228522912083, -0.036807222941358582, -0.049067674327417724, -0.061320736302208245, -0.073564563599667496, -0.085797312344439922, -0.09801714032956059, -0.110222207293883, -0.1224106751992161, -0.13458070850712606, -0.14673047445536158, -0.15885814333386122, -0.17096188876030097, -0.18303988795514067, -0.19509032201612836, -0.20711137619221862, -0.21910124015686983, -0.23105810828067111, -0.24298017990326382, -0.25486565960451446, -0.26671275747489825, -0.27851968938505289, -0.29028467725446216, -0.30200594931922781, -0.31368174039889118, -0.32531029216226304, -0.33688985339222011, -0.34841868024943456, -0.35989503653498811, -0.37131719395183749, -0.38268343236508967, -0.39399204006104793, -0.40524131400498969, -0.41642956009763693, -0.42755509343028181, -0.43861623853852733, -0.44961132965460665, -0.46053871095824006, -0.47139673682599764, -0.48218377207912272, -0.49289819222978393, -0.50353838372571746, -0.51410274419322155, -0.52458968267846873, -0.53499761988709693, -0.54532498842204613, -0.55557023301960196, -0.56573181078361323, -0.57580819141784534, -0.58579785745643886, -0.59569930449243325, -0.60551104140432543, -0.61523159058062671, -0.62485948814238623, -0.63439328416364527, -0.64383154288979128, -0.65317284295377653, -0.66241577759017178, -0.67155895484701844, -0.68060099779545302, -0.68954054473706683, -0.6983762494089728, -0.70710678118654746, -0.71573082528381848, -0.72424708295146667, -0.73265427167241259, -0.74095112535495877, -0.74913639452345904, -0.75720884650648423, -0.76516726562245885, -0.77301045336273666, -0.78073722857209438, -0.78834642762660589, -0.79583690460888334, -0.80320753148064505, -0.81045719825259466, -0.81758481315158371, -0.82458930278502507, -0.83146961230254524, -0.83822470555483775, -0.84485356524970712, -0.85135519310526486, -0.85772861000027201, -0.86397285612158647, -0.87008699110871135, -0.87607009419540671, -0.88192126434835494, -0.88763962040285405, -0.89322430119551521, -0.89867446569395382, -0.90398929312344312, -0.90916798309052238, -0.91420975570353047, -0.91911385169005766, -0.92387953251128652, -0.92850608047321548, -0.93299279883473896, -0.93733901191257485, -0.94154406518302081, -0.94560732538052117, -0.94952818059303667, -0.95330604035419375, -0.95694033573220882, -0.96043051941556568, -0.96377606579543984, -0.96697647104485218, -0.97003125319454397, -0.97293995220556018, -0.97570213003852846, -0.97831737071962765, -0.98078528040323032, -0.98310548743121629, -0.98527764238894111, -0.98730141815785832, -0.9891765099647809, -0.99090263542778001, -0.99247953459871008, -0.99390697000235606, -0.99518472667219693, -0.996312612182778, -0.99729045667869021, -0.99811811290014918, -0.99879545620517241, -0.99932238458834943, -0.99969881869620425, -0.9999247018391445, -1.0, -0.9999247018391445, -0.99969881869620425, -0.99932238458834954, -0.99879545620517241, -0.99811811290014918, -0.99729045667869021, -0.996312612182778, -0.99518472667219693, -0.99390697000235606, -0.99247953459871008, -0.99090263542778001, -0.9891765099647809, -0.98730141815785843, -0.98527764238894122, -0.9831054874312164, -0.98078528040323043, -0.97831737071962777, -0.97570213003852857, -0.97293995220556029, -0.97003125319454397, -0.96697647104485229, -0.96377606579543995, -0.96043051941556579, -0.95694033573220894, -0.95330604035419375, -0.94952818059303679, -0.94560732538052128, -0.94154406518302092, -0.93733901191257496, -0.93299279883473907, -0.92850608047321559, -0.92387953251128663, -0.91911385169005788, -0.91420975570353058, -0.90916798309052249, -0.90398929312344334, -0.89867446569395404, -0.89322430119551532, -0.88763962040285416, -0.88192126434835505, -0.87607009419540693, -0.87008699110871146, -0.8639728561215867, -0.85772861000027223, -0.85135519310526508, -0.84485356524970734, -0.83822470555483797, -0.83146961230254557, -0.82458930278502529, -0.81758481315158404, -0.81045719825259488, -0.80320753148064528, -0.79583690460888368, -0.78834642762660612, -0.78073722857209471, -0.77301045336273688, -0.76516726562245918, -0.75720884650648457, -0.7491363945234597, -0.74095112535495922, -0.73265427167241315, -0.72424708295146711, -0.71573082528381904, -0.70710678118654768, -0.69837624940897269, -0.68954054473706716, -0.68060099779545302, -0.67155895484701866, -0.66241577759017178, -0.65317284295377709, -0.6438315428897915, -0.63439328416364593, -0.62485948814238645, -0.61523159058062737, -0.60551104140432566, -0.59569930449243325, -0.58579785745643909, -0.57580819141784523, -0.56573181078361356, -0.55557023301960218, -0.5453249884220468, -0.53499761988709726, -0.52458968267846939, -0.51410274419322188, -0.50353838372571813, -0.49289819222978426, -0.48218377207912261, -0.47139673682599792, -0.46053871095823995, -0.44961132965460698, -0.43861623853852766, -0.42755509343028253, -0.41642956009763726, -0.40524131400499042, -0.39399204006104827, -0.38268343236509039, -0.37131719395183777, -0.359895036534988, -0.3484186802494349, -0.33688985339222, -0.32531029216226331, -0.31368174039889152, -0.30200594931922853, -0.29028467725446244, -0.27851968938505367, -0.26671275747489859, -0.25486565960451435, -0.24298017990326418, -0.23105810828067103, -0.21910124015687016, -0.20711137619221853, -0.19509032201612872, -0.18303988795514103, -0.17096188876030177, -0.15885814333386158, -0.14673047445536239, -0.13458070850712642, -0.12241067519921603, -0.11022220729388338, -0.09801714032956052, -0.085797312344440282, -0.073564563599667426, -0.06132073630220905, -0.049067674327418091, -0.036807222941359394, -0.024541228522912451, -0.012271538285720572, 0.0};
static MYFLT COSINE_ARRAY[513] = {1.0, 0.9999247018391445, 0.9996988186962042, 0.9993223845883495, 0.9987954562051724, 0.9981181129001492, 0.9972904566786902, 0.996312612182778, 0.9951847266721969, 0.9939069700023561, 0.99247953459871, 0.99090263542778, 0.989176509964781, 0.9873014181578584, 0.9852776423889412, 0.9831054874312163, 0.9807852804032304, 0.9783173707196277, 0.9757021300385286, 0.9729399522055602, 0.970031253194544, 0.9669764710448521, 0.9637760657954398, 0.9604305194155658, 0.9569403357322088, 0.9533060403541939, 0.9495281805930367, 0.9456073253805213, 0.9415440651830208, 0.937339011912575, 0.932992798834739, 0.9285060804732156, 0.9238795325112867, 0.9191138516900578, 0.9142097557035307, 0.9091679830905224, 0.9039892931234433, 0.8986744656939538, 0.8932243011955153, 0.8876396204028539, 0.881921264348355, 0.8760700941954066, 0.8700869911087115, 0.8639728561215868, 0.8577286100002721, 0.8513551931052652, 0.8448535652497071, 0.8382247055548381, 0.8314696123025452, 0.8245893027850253, 0.8175848131515837, 0.8104571982525948, 0.8032075314806449, 0.7958369046088836, 0.7883464276266063, 0.7807372285720945, 0.773010453362737, 0.765167265622459, 0.7572088465064846, 0.7491363945234594, 0.7409511253549591, 0.7326542716724128, 0.724247082951467, 0.7157308252838186, 0.7071067811865476, 0.6983762494089729, 0.6895405447370669, 0.6806009977954531, 0.6715589548470183, 0.6624157775901718, 0.6531728429537768, 0.6438315428897915, 0.6343932841636455, 0.6248594881423865, 0.6152315905806268, 0.6055110414043255, 0.5956993044924335, 0.5857978574564389, 0.5758081914178453, 0.5657318107836132, 0.5555702330196023, 0.5453249884220465, 0.5349976198870973, 0.5245896826784688, 0.5141027441932217, 0.5035383837257176, 0.4928981922297841, 0.48218377207912283, 0.4713967368259978, 0.46053871095824, 0.4496113296546066, 0.4386162385385277, 0.4275550934302822, 0.4164295600976373, 0.40524131400498986, 0.3939920400610481, 0.38268343236508984, 0.3713171939518376, 0.3598950365349883, 0.3484186802494345, 0.33688985339222005, 0.325310292162263, 0.3136817403988916, 0.3020059493192282, 0.29028467725446233, 0.27851968938505306, 0.2667127574748984, 0.2548656596045146, 0.24298017990326398, 0.23105810828067128, 0.21910124015686977, 0.20711137619221856, 0.19509032201612833, 0.18303988795514106, 0.17096188876030136, 0.1588581433338614, 0.14673047445536175, 0.13458070850712622, 0.12241067519921628, 0.11022220729388318, 0.09801714032956077, 0.08579731234443988, 0.07356456359966745, 0.06132073630220865, 0.049067674327418126, 0.03680722294135899, 0.024541228522912264, 0.012271538285719944, 6.123031769111886e-17, -0.012271538285719823, -0.024541228522912142, -0.036807222941358866, -0.04906767432741801, -0.06132073630220853, -0.07356456359966733, -0.08579731234443976, -0.09801714032956065, -0.11022220729388306, -0.12241067519921615, -0.1345807085071261, -0.14673047445536164, -0.15885814333386128, -0.17096188876030124, -0.18303988795514092, -0.1950903220161282, -0.20711137619221845, -0.21910124015686966, -0.23105810828067114, -0.24298017990326387, -0.2548656596045145, -0.2667127574748983, -0.27851968938505295, -0.29028467725446216, -0.3020059493192281, -0.3136817403988914, -0.32531029216226287, -0.33688985339221994, -0.3484186802494344, -0.35989503653498817, -0.3713171939518375, -0.3826834323650897, -0.393992040061048, -0.40524131400498975, -0.416429560097637, -0.42755509343028186, -0.4386162385385274, -0.4496113296546067, -0.46053871095824006, -0.4713967368259977, -0.4821837720791227, -0.492898192229784, -0.5035383837257175, -0.5141027441932217, -0.5245896826784687, -0.534997619887097, -0.5453249884220462, -0.555570233019602, -0.5657318107836132, -0.5758081914178453, -0.5857978574564389, -0.5956993044924334, -0.6055110414043254, -0.6152315905806267, -0.6248594881423862, -0.6343932841636454, -0.6438315428897913, -0.6531728429537765, -0.6624157775901719, -0.6715589548470184, -0.680600997795453, -0.6895405447370669, -0.6983762494089728, -0.7071067811865475, -0.7157308252838186, -0.7242470829514668, -0.7326542716724127, -0.7409511253549589, -0.7491363945234591, -0.7572088465064846, -0.765167265622459, -0.773010453362737, -0.7807372285720945, -0.7883464276266062, -0.7958369046088835, -0.8032075314806448, -0.8104571982525947, -0.8175848131515836, -0.8245893027850251, -0.8314696123025453, -0.8382247055548381, -0.8448535652497071, -0.8513551931052652, -0.857728610000272, -0.8639728561215867, -0.8700869911087113, -0.8760700941954065, -0.8819212643483549, -0.8876396204028538, -0.8932243011955152, -0.8986744656939539, -0.9039892931234433, -0.9091679830905224, -0.9142097557035307, -0.9191138516900578, -0.9238795325112867, -0.9285060804732155, -0.9329927988347388, -0.9373390119125748, -0.9415440651830207, -0.9456073253805212, -0.9495281805930367, -0.9533060403541939, -0.9569403357322088, -0.9604305194155658,
                                  -0.9637760657954398, -0.9669764710448521, -0.970031253194544, -0.9729399522055601, -0.9757021300385285, -0.9783173707196275, -0.9807852804032304, -0.9831054874312163, -0.9852776423889412, -0.9873014181578584, -0.989176509964781, -0.99090263542778, -0.99247953459871, -0.9939069700023561, -0.9951847266721968, -0.996312612182778, -0.9972904566786902, -0.9981181129001492, -0.9987954562051724, -0.9993223845883495, -0.9996988186962042, -0.9999247018391445, -1.0, -0.9999247018391445, -0.9996988186962042, -0.9993223845883495, -0.9987954562051724, -0.9981181129001492, -0.9972904566786902, -0.996312612182778, -0.9951847266721969, -0.9939069700023561, -0.99247953459871, -0.99090263542778, -0.989176509964781, -0.9873014181578584, -0.9852776423889413, -0.9831054874312164, -0.9807852804032304, -0.9783173707196277, -0.9757021300385286, -0.9729399522055602, -0.970031253194544, -0.9669764710448522, -0.96377606579544, -0.9604305194155659, -0.9569403357322089, -0.953306040354194, -0.9495281805930368, -0.9456073253805213, -0.9415440651830208, -0.937339011912575, -0.932992798834739, -0.9285060804732156, -0.9238795325112868, -0.9191138516900578, -0.9142097557035307, -0.9091679830905225, -0.9039892931234434, -0.898674465693954, -0.8932243011955153, -0.8876396204028539, -0.881921264348355, -0.8760700941954066, -0.8700869911087115, -0.8639728561215868, -0.8577286100002721, -0.8513551931052653, -0.8448535652497072, -0.8382247055548382, -0.8314696123025455, -0.8245893027850253, -0.8175848131515837, -0.8104571982525948, -0.8032075314806449, -0.7958369046088836, -0.7883464276266063, -0.7807372285720946, -0.7730104533627371, -0.7651672656224591, -0.7572088465064848, -0.7491363945234593, -0.7409511253549591, -0.7326542716724128, -0.724247082951467, -0.7157308252838187, -0.7071067811865477, -0.698376249408973, -0.689540544737067, -0.6806009977954532, -0.6715589548470187, -0.662415777590172, -0.6531728429537771, -0.6438315428897915, -0.6343932841636459, -0.6248594881423865, -0.6152315905806273, -0.6055110414043257, -0.5956993044924331, -0.5857978574564391, -0.5758081914178452, -0.5657318107836135, -0.5555702330196022, -0.5453249884220468, -0.5349976198870973, -0.5245896826784694, -0.5141027441932218, -0.503538383725718, -0.4928981922297842, -0.48218377207912255, -0.47139673682599786, -0.4605387109582399, -0.44961132965460693, -0.4386162385385276, -0.4275550934302825, -0.4164295600976372, -0.40524131400499036, -0.3939920400610482, -0.38268343236509034, -0.37131719395183777, -0.35989503653498794, -0.34841868024943484, -0.33688985339221994, -0.3253102921622633, -0.31368174039889146, -0.30200594931922853, -0.29028467725446244, -0.2785196893850536, -0.26671275747489853, -0.25486565960451435, -0.24298017990326412, -0.23105810828067094, -0.2191012401568701, -0.20711137619221848, -0.19509032201612866, -0.18303988795514095, -0.1709618887603017, -0.15885814333386153, -0.1467304744553623, -0.13458070850712636, -0.12241067519921596, -0.11022220729388331, -0.09801714032956045, -0.08579731234444023, -0.07356456359966736, -0.061320736302208995, -0.04906767432741803, -0.03680722294135933, -0.02454122852291239, -0.012271538285720512, -1.836909530733566e-16, 0.012271538285720144, 0.02454122852291202, 0.036807222941358964, 0.04906767432741766, 0.06132073630220863, 0.07356456359966698, 0.08579731234443985, 0.09801714032956009, 0.11022220729388293, 0.1224106751992156, 0.13458070850712597, 0.14673047445536194, 0.15885814333386117, 0.17096188876030133, 0.1830398879551406, 0.1950903220161283, 0.20711137619221812, 0.21910124015686974, 0.23105810828067058, 0.24298017990326376, 0.25486565960451396, 0.2667127574748982, 0.2785196893850533, 0.29028467725446205, 0.30200594931922814, 0.31368174039889113, 0.3253102921622629, 0.3368898533922196, 0.3484186802494345, 0.3598950365349876, 0.3713171939518374, 0.38268343236509, 0.3939920400610479, 0.40524131400499, 0.4164295600976369, 0.42755509343028214, 0.43861623853852727, 0.4496113296546066, 0.46053871095823956, 0.4713967368259976, 0.4821837720791222, 0.49289819222978387, 0.5035383837257178, 0.5141027441932216, 0.5245896826784691, 0.5349976198870969, 0.5453249884220465, 0.5555702330196018, 0.5657318107836131, 0.5758081914178449, 0.5857978574564388, 0.5956993044924329, 0.6055110414043253, 0.615231590580627, 0.6248594881423861, 0.6343932841636456, 0.6438315428897912, 0.6531728429537768, 0.6624157775901715, 0.6715589548470183, 0.6806009977954527, 0.6895405447370668, 0.6983762494089724, 0.7071067811865474, 0.7157308252838188, 0.7242470829514667, 0.7326542716724129, 0.7409511253549589, 0.7491363945234594, 0.7572088465064842, 0.7651672656224588, 0.7730104533627367, 0.7807372285720944, 0.7883464276266059, 0.7958369046088833, 0.803207531480645, 0.8104571982525947, 0.8175848131515837, 0.8245893027850251, 0.8314696123025452, 0.8382247055548377,
                                  0.844853565249707, 0.8513551931052649, 0.857728610000272, 0.8639728561215864, 0.8700869911087113, 0.8760700941954067, 0.8819212643483548, 0.8876396204028539, 0.8932243011955151, 0.8986744656939538, 0.9039892931234431, 0.9091679830905224, 0.9142097557035305, 0.9191138516900577, 0.9238795325112865, 0.9285060804732155, 0.932992798834739, 0.9373390119125748, 0.9415440651830208, 0.9456073253805212, 0.9495281805930367, 0.9533060403541936, 0.9569403357322088, 0.9604305194155657, 0.9637760657954398, 0.9669764710448522, 0.970031253194544, 0.9729399522055602, 0.9757021300385285, 0.9783173707196277, 0.9807852804032303, 0.9831054874312163, 0.9852776423889411, 0.9873014181578583, 0.9891765099647809, 0.99090263542778, 0.99247953459871, 0.9939069700023561, 0.9951847266721969, 0.996312612182778, 0.9972904566786902, 0.9981181129001492, 0.9987954562051724, 0.9993223845883494, 0.9996988186962042, 0.9999247018391445, 1.0
                                  };
static MYFLT ONE_OVER_512 = 1.0 / 512.0;
static const MYFLT ROSSLER_SCALE     = 0.054;
static const MYFLT ROSSLER_ALT_SCALE = 0.0569;
static const MYFLT LORENZ_SCALE     = 0.044;
static const MYFLT LORENZ_ALT_SCALE = 0.0328;
static const MYFLT CHENLEE_SCALE     = 0.02;
static const MYFLT CHENLEE_ALT_SCALE = 0.02;

static MYFLT
_clip(MYFLT x)
{
    if (x < 0.0)
        return 0.0;
    else if (x >= 1.0)
        return 1.0;
    else
        return x;
}

static MYFLT
Sine_clip(MYFLT x)
{
    if (x < 0)
    {
        x += ((int)(-x * ONE_OVER_512) + 1) * 512;
    }
    else if (x >= 512)
    {
        x -= (int)(x * ONE_OVER_512) * 512;
    }

    return x;
}

/* Sine object */
typedef struct
{
    pyo_audio_HEAD
    PyObject *freq;
    Stream *freq_stream;
    PyObject *phase;
    Stream *phase_stream;
    int modebuffer[4];
    MYFLT pointerPos;
} Sine;

static void
Sine_readframes_ii(Sine *self)
{
    MYFLT inc, fr, ph, pos;
    int i, ipart;

    fr = PyFloat_AS_DOUBLE(self->freq);
    ph = PyFloat_AS_DOUBLE(self->phase) * 512;
    inc = fr * 512 / self->sr;

    for (i = 0; i < self->bufsize; i++)
    {
        self->pointerPos = Sine_clip(self->pointerPos);
        pos = self->pointerPos + ph;

        if (pos >= 512)
            pos -= 512;

        ipart = (int)pos;
        self->data[i] = SINE_ARRAY[ipart] + (SINE_ARRAY[ipart + 1] - SINE_ARRAY[ipart]) * (pos - ipart);
        self->pointerPos += inc;
    }
}

static void
Sine_readframes_ai(Sine *self)
{
    MYFLT inc, ph, pos, fac;
    int i, ipart;

    MYFLT *fr = Stream_getData((Stream *)self->freq_stream);
    ph = PyFloat_AS_DOUBLE(self->phase) * 512;

    fac = 512 / self->sr;

    for (i = 0; i < self->bufsize; i++)
    {
        inc = fr[i] * fac;
        self->pointerPos = Sine_clip(self->pointerPos);
        pos = self->pointerPos + ph;

        if (pos >= 512)
            pos -= 512;

        ipart = (int)pos;
        self->data[i] = SINE_ARRAY[ipart] + (SINE_ARRAY[ipart + 1] - SINE_ARRAY[ipart]) * (pos - ipart);
        self->pointerPos += inc;
    }
}

static void
Sine_readframes_ia(Sine *self)
{
    MYFLT inc, fr, pos;
    int i, ipart;

    fr = PyFloat_AS_DOUBLE(self->freq);
    MYFLT *ph = Stream_getData((Stream *)self->phase_stream);
    inc = fr * 512 / self->sr;

    for (i = 0; i < self->bufsize; i++)
    {
        self->pointerPos = Sine_clip(self->pointerPos);
        pos = self->pointerPos + ph[i] * 512;

        if (pos >= 512)
            pos -= 512;

        ipart = (int)pos;
        self->data[i] = SINE_ARRAY[ipart] + (SINE_ARRAY[ipart + 1] - SINE_ARRAY[ipart]) * (pos - ipart);
        self->pointerPos += inc;
    }
}

static void
Sine_readframes_aa(Sine *self)
{
    MYFLT inc, pos, fac;
    int i, ipart;

    MYFLT *fr = Stream_getData((Stream *)self->freq_stream);
    MYFLT *ph = Stream_getData((Stream *)self->phase_stream);

    fac = 512 / self->sr;

    for (i = 0; i < self->bufsize; i++)
    {
        inc = fr[i] * fac;
        self->pointerPos = Sine_clip(self->pointerPos);
        pos = self->pointerPos + ph[i] * 512;

        if (pos >= 512)
            pos -= 512;

        ipart = (int)pos;
        self->data[i] = SINE_ARRAY[ipart] + (SINE_ARRAY[ipart + 1] - SINE_ARRAY[ipart]) * (pos - ipart);
        self->pointerPos += inc;
    }
}

static void Sine_postprocessing_ii(Sine *self) { POST_PROCESSING_II };
static void Sine_postprocessing_ai(Sine *self) { POST_PROCESSING_AI };
static void Sine_postprocessing_ia(Sine *self) { POST_PROCESSING_IA };
static void Sine_postprocessing_aa(Sine *self) { POST_PROCESSING_AA };
static void Sine_postprocessing_ireva(Sine *self) { POST_PROCESSING_IREVA };
static void Sine_postprocessing_areva(Sine *self) { POST_PROCESSING_AREVA };
static void Sine_postprocessing_revai(Sine *self) { POST_PROCESSING_REVAI };
static void Sine_postprocessing_revaa(Sine *self) { POST_PROCESSING_REVAA };
static void Sine_postprocessing_revareva(Sine *self) { POST_PROCESSING_REVAREVA };

static void
Sine_setProcMode(Sine *self)
{
    int procmode, muladdmode;
    procmode = self->modebuffer[2] + self->modebuffer[3] * 10;
    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;

    switch (procmode)
    {
        case 0:
            self->proc_func_ptr = Sine_readframes_ii;
            break;

        case 1:
            self->proc_func_ptr = Sine_readframes_ai;
            break;

        case 10:
            self->proc_func_ptr = Sine_readframes_ia;
            break;

        case 11:
            self->proc_func_ptr = Sine_readframes_aa;
            break;
    }

    switch (muladdmode)
    {
        case 0:
            self->muladd_func_ptr = Sine_postprocessing_ii;
            break;

        case 1:
            self->muladd_func_ptr = Sine_postprocessing_ai;
            break;

        case 2:
            self->muladd_func_ptr = Sine_postprocessing_revai;
            break;

        case 10:
            self->muladd_func_ptr = Sine_postprocessing_ia;
            break;

        case 11:
            self->muladd_func_ptr = Sine_postprocessing_aa;
            break;

        case 12:
            self->muladd_func_ptr = Sine_postprocessing_revaa;
            break;

        case 20:
            self->muladd_func_ptr = Sine_postprocessing_ireva;
            break;

        case 21:
            self->muladd_func_ptr = Sine_postprocessing_areva;
            break;

        case 22:
            self->muladd_func_ptr = Sine_postprocessing_revareva;
            break;
    }
}

static void
Sine_compute_next_data_frame(Sine *self)
{
    (*self->proc_func_ptr)(self);
    (*self->muladd_func_ptr)(self);
}

static int
Sine_traverse(Sine *self, visitproc visit, void *arg)
{
    pyo_VISIT
    Py_VISIT(self->freq);
    Py_VISIT(self->phase);
    return 0;
}

static int
Sine_clear(Sine *self)
{
    pyo_CLEAR
    Py_CLEAR(self->freq);
    Py_CLEAR(self->phase);
    return 0;
}

static void
Sine_dealloc(Sine* self)
{
    pyo_DEALLOC
    Sine_clear(self);
    Py_TYPE(self->stream)->tp_free((PyObject*)self->stream);
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject *
Sine_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    int i;
    PyObject *freqtmp = NULL, *phasetmp = NULL, *multmp = NULL, *addtmp = NULL;

    Sine *self;
    self = (Sine *)type->tp_alloc(type, 0);

    self->freq = PyFloat_FromDouble(1000);
    self->phase = PyFloat_FromDouble(0.0);
    self->modebuffer[0] = 0;
    self->modebuffer[1] = 0;
    self->modebuffer[2] = 0;
    self->modebuffer[3] = 0;
    self->pointerPos = 0.;

    INIT_OBJECT_COMMON
    Stream_setFunctionPtr(self->stream, Sine_compute_next_data_frame);
    self->mode_func_ptr = Sine_setProcMode;

    static char *kwlist[] = {"freq", "phase", "mul", "add", NULL};

    if (! PyArg_ParseTupleAndKeywords(args, kwds, "|OOOO", kwlist, &freqtmp, &phasetmp, &multmp, &addtmp))
        Py_RETURN_NONE;

    if (freqtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setFreq", "O", freqtmp);
    }

    if (phasetmp)
    {
        PyObject_CallMethod((PyObject *)self, "setPhase", "O", phasetmp);
    }

    if (multmp)
    {
        PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
    }

    if (addtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
    }

    PyObject_CallMethod(self->server, "addStream", "O", self->stream);

    (*self->mode_func_ptr)(self);

    return (PyObject *)self;
}

static PyObject * Sine_getServer(Sine* self) { GET_SERVER };
static PyObject * Sine_getStream(Sine* self) { GET_STREAM };
static PyObject * Sine_setMul(Sine *self, PyObject *arg) { SET_MUL };
static PyObject * Sine_setAdd(Sine *self, PyObject *arg) { SET_ADD };
static PyObject * Sine_setSub(Sine *self, PyObject *arg) { SET_SUB };
static PyObject * Sine_setDiv(Sine *self, PyObject *arg) { SET_DIV };

static PyObject * Sine_play(Sine *self, PyObject *args, PyObject *kwds) { PLAY };
static PyObject * Sine_out(Sine *self, PyObject *args, PyObject *kwds) { OUT };
static PyObject * Sine_stop(Sine *self, PyObject *args, PyObject *kwds) { STOP };

static PyObject * Sine_multiply(Sine *self, PyObject *arg) { MULTIPLY };
static PyObject * Sine_inplace_multiply(Sine *self, PyObject *arg) { INPLACE_MULTIPLY };
static PyObject * Sine_add(Sine *self, PyObject *arg) { ADD };
static PyObject * Sine_inplace_add(Sine *self, PyObject *arg) { INPLACE_ADD };
static PyObject * Sine_sub(Sine *self, PyObject *arg) { SUB };
static PyObject * Sine_inplace_sub(Sine *self, PyObject *arg) { INPLACE_SUB };
static PyObject * Sine_div(Sine *self, PyObject *arg) { DIV };
static PyObject * Sine_inplace_div(Sine *self, PyObject *arg) { INPLACE_DIV };

static PyObject * Sine_setFreq(Sine *self, PyObject *arg) { SET_PARAM(self->freq, self->freq_stream, 2) }
static PyObject * Sine_setPhase(Sine *self, PyObject *arg) { SET_PARAM(self->phase, self->phase_stream, 3) }

static PyObject *
Sine_reset(Sine *self)
{
    self->pointerPos = 0.0;
    Py_RETURN_NONE;
}

static PyMemberDef Sine_members[] =
{
    {"server", T_OBJECT_EX, offsetof(Sine, server), 0, "Pyo server."},
    {"stream", T_OBJECT_EX, offsetof(Sine, stream), 0, "Stream object."},
    {"freq", T_OBJECT_EX, offsetof(Sine, freq), 0, "Frequency in cycle per second."},
    {"phase", T_OBJECT_EX, offsetof(Sine, phase), 0, "Phase of signal (0 -> 1)"},
    {"mul", T_OBJECT_EX, offsetof(Sine, mul), 0, "Mul factor."},
    {"add", T_OBJECT_EX, offsetof(Sine, add), 0, "Add factor."},
    {NULL}  /* Sentinel */
};

static PyMethodDef Sine_methods[] =
{
    {"getServer", (PyCFunction)Sine_getServer, METH_NOARGS, "Returns server object."},
    {"_getStream", (PyCFunction)Sine_getStream, METH_NOARGS, "Returns stream object."},
    {"play", (PyCFunction)Sine_play, METH_VARARGS | METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
    {"out", (PyCFunction)Sine_out, METH_VARARGS | METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
    {"stop", (PyCFunction)Sine_stop, METH_VARARGS | METH_KEYWORDS, "Stops computing."},
    {"setFreq", (PyCFunction)Sine_setFreq, METH_O, "Sets oscillator frequency in cycle per second."},
    {"setPhase", (PyCFunction)Sine_setPhase, METH_O, "Sets oscillator phase between 0 and 1."},
    {"reset", (PyCFunction)Sine_reset, METH_NOARGS, "Resets pointer position to 0."},
    {"setMul", (PyCFunction)Sine_setMul, METH_O, "Sets Sine mul factor."},
    {"setAdd", (PyCFunction)Sine_setAdd, METH_O, "Sets Sine add factor."},
    {"setSub", (PyCFunction)Sine_setSub, METH_O, "Sets inverse add factor."},
    {"setDiv", (PyCFunction)Sine_setDiv, METH_O, "Sets inverse mul factor."},
    {NULL}  /* Sentinel */
};

static PyNumberMethods Sine_as_number =
{
    (binaryfunc)Sine_add,                      /*nb_add*/
    (binaryfunc)Sine_sub,                 /*nb_subtract*/
    (binaryfunc)Sine_multiply,                 /*nb_multiply*/
    0,                /*nb_remainder*/
    0,                   /*nb_divmod*/
    0,                   /*nb_power*/
    0,                  /*nb_neg*/
    0,                /*nb_pos*/
    0,                  /*(unaryfunc)array_abs*/
    0,                    /*nb_nonzero*/
    0,                    /*nb_invert*/
    0,               /*nb_lshift*/
    0,              /*nb_rshift*/
    0,              /*nb_and*/
    0,              /*nb_xor*/
    0,               /*nb_or*/
    0,                       /*nb_int*/
    0,                      /*nb_long*/
    0,                     /*nb_float*/
    (binaryfunc)Sine_inplace_add,              /*inplace_add*/
    (binaryfunc)Sine_inplace_sub,         /*inplace_subtract*/
    (binaryfunc)Sine_inplace_multiply,         /*inplace_multiply*/
    0,        /*inplace_remainder*/
    0,           /*inplace_power*/
    0,       /*inplace_lshift*/
    0,      /*inplace_rshift*/
    0,      /*inplace_and*/
    0,      /*inplace_xor*/
    0,       /*inplace_or*/
    0,             /*nb_floor_divide*/
    (binaryfunc)Sine_div,                       /*nb_true_divide*/
    0,     /*nb_inplace_floor_divide*/
    (binaryfunc)Sine_inplace_div,                       /*nb_inplace_true_divide*/
    0,                     /* nb_index */
};

PyTypeObject SineType =
{
    PyVarObject_HEAD_INIT(NULL, 0)
    "_pyo.Sine_base",         /*tp_name*/
    sizeof(Sine),         /*tp_basicsize*/
    0,                         /*tp_itemsize*/
    (destructor)Sine_dealloc, /*tp_dealloc*/
    0,                         /*tp_print*/
    0,                         /*tp_getattr*/
    0,                         /*tp_setattr*/
    0,                         /*tp_as_async (tp_compare in Python 2)*/
    0,                         /*tp_repr*/
    &Sine_as_number,             /*tp_as_number*/
    0,                         /*tp_as_sequence*/
    0,                         /*tp_as_mapping*/
    0,                         /*tp_hash */
    0,                         /*tp_call*/
    0,                         /*tp_str*/
    0,                         /*tp_getattro*/
    0,                         /*tp_setattro*/
    0,                         /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,  /*tp_flags*/
    "Sine objects. Generates a sinewave.",           /* tp_doc */
    (traverseproc)Sine_traverse,   /* tp_traverse */
    (inquiry)Sine_clear,           /* tp_clear */
    0,                     /* tp_richcompare */
    0,                     /* tp_weaklistoffset */
    0,                     /* tp_iter */
    0,                     /* tp_iternext */
    Sine_methods,             /* tp_methods */
    Sine_members,             /* tp_members */
    0,                      /* tp_getset */
    0,                         /* tp_base */
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    0,                         /* tp_dictoffset */
    0,      /* tp_init */
    0,                         /* tp_alloc */
    Sine_new,                 /* tp_new */
};


/* FastSine object */
typedef struct
{
    pyo_audio_HEAD
    PyObject *freq;
    Stream *freq_stream;
    int modebuffer[3];
    MYFLT initphase;
    int quality;
    MYFLT pointerPos;
    MYFLT twoPiOnSr;
    MYFLT B;
    MYFLT C;
} FastSine;

static void
FastSine_readframes_low_i(FastSine *self)
{
    int i;
    MYFLT inc, fr, pos, b, c;

    fr = PyFloat_AS_DOUBLE(self->freq);
    inc = fr * self->twoPiOnSr;

    pos = self->pointerPos;
    b = self->B;
    c = self->C;

    for (i = 0; i < self->bufsize; i++)
    {
        if (pos > PI)
            pos -= TWOPI;

        self->data[i] = b * pos + c * pos * MYFABS(pos);
        pos += inc;
    }

    self->pointerPos = pos;
}

static void
FastSine_readframes_low_a(FastSine *self)
{
    int i;
    MYFLT pos, b, c;

    MYFLT *fr = Stream_getData((Stream *)self->freq_stream);

    pos = self->pointerPos;
    b = self->B;
    c = self->C;

    for (i = 0; i < self->bufsize; i++)
    {
        if (pos > PI)
            pos -= TWOPI;

        self->data[i] = b * pos + c * pos * MYFABS(pos);
        pos += fr[i] * self->twoPiOnSr;
    }

    self->pointerPos = pos;
}

static void
FastSine_readframes_high_i(FastSine *self)
{
    int i;
    MYFLT inc, fr, pos, b, c, y;

    fr = PyFloat_AS_DOUBLE(self->freq);
    inc = fr * self->twoPiOnSr;

    pos = self->pointerPos;
    b = self->B;
    c = self->C;

    for (i = 0; i < self->bufsize; i++)
    {
        if (pos > PI)
            pos -= TWOPI;

        y = b * pos + c * pos * MYFABS(pos);
        self->data[i] = y + (y * MYFABS(y) - y) * 0.218;
        pos += inc;
    }

    self->pointerPos = pos;
}

static void
FastSine_readframes_high_a(FastSine *self)
{
    int i;
    MYFLT pos, b, c, y;

    MYFLT *fr = Stream_getData((Stream *)self->freq_stream);

    pos = self->pointerPos;
    b = self->B;
    c = self->C;

    for (i = 0; i < self->bufsize; i++)
    {
        if (pos > PI)
            pos -= TWOPI;

        y = b * pos + c * pos * MYFABS(pos);
        self->data[i] = y + (y * MYFABS(y) - y) * 0.218;
        pos += fr[i] * self->twoPiOnSr;
    }

    self->pointerPos = pos;
}

/*
static void
FastSine_readframes_low_i(FastSine *self) {
    MYFLT inc, fr, pos;
    int i;

    fr = PyFloat_AS_DOUBLE(self->freq);
    inc = fr * self->fourOnSr;

    pos = self->pointerPos;
    for (i=0; i<self->bufsize; i++) {
        if (pos > 2.0)
            pos -= 4.0;

        if (pos < 0) {
            self->data[i] = pos * (pos + 2.0);
        }
        else {
            self->data[i] = pos * (2.0 - pos);
        }
        pos += inc;
    }
    self->pointerPos = pos;
}

static void
FastSine_readframes_low_a(FastSine *self) {
    MYFLT inc, pos;
    int i;

    MYFLT *fr = Stream_getData((Stream *)self->freq_stream);

    pos = self->pointerPos;
    for (i=0; i<self->bufsize; i++) {
        inc = fr[i] * self->fourOnSr;
        if (pos > 2.0)
            pos -= 4.0;

        if (pos < 0) {
            self->data[i] = pos * (pos + 2.0);
        }
        else {
            self->data[i] = pos * (2.0 - pos);
        }
        pos += inc;
    }
    self->pointerPos = pos;
}

static void
FastSine_readframes_high_i(FastSine *self) {
    MYFLT inc, fr, pos, sine;
    int i;

    fr = PyFloat_AS_DOUBLE(self->freq);
    inc = fr * self->fourOnSr;

    pos = self->pointerPos;
    for (i=0; i<self->bufsize; i++) {
        if (pos > 2.0)
            pos -= 4.0;

        if (pos < 0) {
            sine = -pos * (pos + 2.0);
            self->data[i] = -sine * (0.225 * (sine - 1) + 1);
        }
        else {
            sine = pos * (2.0 - pos);
            self->data[i] = sine * (0.225 * (sine - 1) + 1);
        }
        pos += inc;
    }
    self->pointerPos = pos;
}

static void
FastSine_readframes_high_a(FastSine *self) {
    MYFLT inc, pos, sine;
    int i;

    MYFLT *fr = Stream_getData((Stream *)self->freq_stream);

    pos = self->pointerPos;
    for (i=0; i<self->bufsize; i++) {
        inc = fr[i] * self->fourOnSr;
        if (pos > 2.0)
            pos -= 4.0;

        if (pos < 0) {
            sine = -pos * (pos + 2.0);
            self->data[i] = -sine * (0.225 * (sine - 1) + 1);
        }
        else {
            sine = pos * (2.0 - pos);
            self->data[i] = sine * (0.225 * (sine - 1) + 1);
        }
        pos += inc;
    }
    self->pointerPos = pos;
}
*/

static void FastSine_postprocessing_ii(FastSine *self) { POST_PROCESSING_II };
static void FastSine_postprocessing_ai(FastSine *self) { POST_PROCESSING_AI };
static void FastSine_postprocessing_ia(FastSine *self) { POST_PROCESSING_IA };
static void FastSine_postprocessing_aa(FastSine *self) { POST_PROCESSING_AA };
static void FastSine_postprocessing_ireva(FastSine *self) { POST_PROCESSING_IREVA };
static void FastSine_postprocessing_areva(FastSine *self) { POST_PROCESSING_AREVA };
static void FastSine_postprocessing_revai(FastSine *self) { POST_PROCESSING_REVAI };
static void FastSine_postprocessing_revaa(FastSine *self) { POST_PROCESSING_REVAA };
static void FastSine_postprocessing_revareva(FastSine *self) { POST_PROCESSING_REVAREVA };

static void
FastSine_setProcMode(FastSine *self)
{
    int procmode, muladdmode;
    procmode = self->modebuffer[2];
    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;

    switch (procmode)
    {
        case 0:
            if (self->quality == 0)
                self->proc_func_ptr = FastSine_readframes_low_i;
            else if (self->quality == 1)
                self->proc_func_ptr = FastSine_readframes_high_i;

            break;

        case 1:
            if (self->quality == 0)
                self->proc_func_ptr = FastSine_readframes_low_a;
            else if (self->quality == 1)
                self->proc_func_ptr = FastSine_readframes_high_a;

            break;
    }

    switch (muladdmode)
    {
        case 0:
            self->muladd_func_ptr = FastSine_postprocessing_ii;
            break;

        case 1:
            self->muladd_func_ptr = FastSine_postprocessing_ai;
            break;

        case 2:
            self->muladd_func_ptr = FastSine_postprocessing_revai;
            break;

        case 10:
            self->muladd_func_ptr = FastSine_postprocessing_ia;
            break;

        case 11:
            self->muladd_func_ptr = FastSine_postprocessing_aa;
            break;

        case 12:
            self->muladd_func_ptr = FastSine_postprocessing_revaa;
            break;

        case 20:
            self->muladd_func_ptr = FastSine_postprocessing_ireva;
            break;

        case 21:
            self->muladd_func_ptr = FastSine_postprocessing_areva;
            break;

        case 22:
            self->muladd_func_ptr = FastSine_postprocessing_revareva;
            break;
    }
}

static void
FastSine_compute_next_data_frame(FastSine *self)
{
    (*self->proc_func_ptr)(self);
    (*self->muladd_func_ptr)(self);
}

static int
FastSine_traverse(FastSine *self, visitproc visit, void *arg)
{
    pyo_VISIT
    Py_VISIT(self->freq);
    return 0;
}

static int
FastSine_clear(FastSine *self)
{
    pyo_CLEAR
    Py_CLEAR(self->freq);
    return 0;
}

static void
FastSine_dealloc(FastSine* self)
{
    pyo_DEALLOC
    FastSine_clear(self);
    Py_TYPE(self->stream)->tp_free((PyObject*)self->stream);
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject *
FastSine_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    int i;
    PyObject *freqtmp = NULL, *multmp = NULL, *addtmp = NULL;

    FastSine *self;
    self = (FastSine *)type->tp_alloc(type, 0);

    self->freq = PyFloat_FromDouble(1000);
    self->initphase = 0.0;
    self->quality = 1;
    self->modebuffer[0] = 0;
    self->modebuffer[1] = 0;
    self->modebuffer[2] = 0;

    INIT_OBJECT_COMMON
    Stream_setFunctionPtr(self->stream, FastSine_compute_next_data_frame);
    self->mode_func_ptr = FastSine_setProcMode;

    self->twoPiOnSr = TWOPI / self->sr;
    self->B = 4.0 / PI;
    self->C = -4.0 / (PI * PI);

    static char *kwlist[] = {"freq", "initphase", "quality", "mul", "add", NULL};

    if (! PyArg_ParseTupleAndKeywords(args, kwds, TYPE__OFIOO, kwlist, &freqtmp, &self->initphase, &self->quality, &multmp, &addtmp))
        Py_RETURN_NONE;

    if (self->initphase < 0.0)
        self->initphase = 0.0;
    else if (self->initphase > 1.0)
        self->initphase = 1.0;

    self->pointerPos = self->initphase * TWOPI;

    if (self->quality < 0)
        self->quality = 0;
    else if (self->quality > 1)
        self->quality = 1;

    if (freqtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setFreq", "O", freqtmp);
    }

    if (multmp)
    {
        PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
    }

    if (addtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
    }

    PyObject_CallMethod(self->server, "addStream", "O", self->stream);


    (*self->mode_func_ptr)(self);

    return (PyObject *)self;
}

static PyObject * FastSine_getServer(FastSine* self) { GET_SERVER };
static PyObject * FastSine_getStream(FastSine* self) { GET_STREAM };
static PyObject * FastSine_setMul(FastSine *self, PyObject *arg) { SET_MUL };
static PyObject * FastSine_setAdd(FastSine *self, PyObject *arg) { SET_ADD };
static PyObject * FastSine_setSub(FastSine *self, PyObject *arg) { SET_SUB };
static PyObject * FastSine_setDiv(FastSine *self, PyObject *arg) { SET_DIV };

static PyObject * FastSine_play(FastSine *self, PyObject *args, PyObject *kwds) { PLAY };
static PyObject * FastSine_out(FastSine *self, PyObject *args, PyObject *kwds) { OUT };
static PyObject * FastSine_stop(FastSine *self, PyObject *args, PyObject *kwds) { STOP };

static PyObject * FastSine_multiply(FastSine *self, PyObject *arg) { MULTIPLY };
static PyObject * FastSine_inplace_multiply(FastSine *self, PyObject *arg) { INPLACE_MULTIPLY };
static PyObject * FastSine_add(FastSine *self, PyObject *arg) { ADD };
static PyObject * FastSine_inplace_add(FastSine *self, PyObject *arg) { INPLACE_ADD };
static PyObject * FastSine_sub(FastSine *self, PyObject *arg) { SUB };
static PyObject * FastSine_inplace_sub(FastSine *self, PyObject *arg) { INPLACE_SUB };
static PyObject * FastSine_div(FastSine *self, PyObject *arg) { DIV };
static PyObject * FastSine_inplace_div(FastSine *self, PyObject *arg) { INPLACE_DIV };

static PyObject * FastSine_setFreq(FastSine *self, PyObject *arg) { SET_PARAM(self->freq, self->freq_stream, 2); }

static PyObject *
FastSine_setQuality(FastSine *self, PyObject *arg)
{
    int tmp;
    ASSERT_ARG_NOT_NULL

    if (PyLong_Check(arg))
    {
        tmp = PyLong_AsLong(arg);

        if (tmp >= 0 && tmp < 2)
            self->quality = tmp;
    }

    (*self->mode_func_ptr)(self);

    Py_RETURN_NONE;
}

static PyObject *
FastSine_reset(FastSine *self)
{
    self->pointerPos = self->initphase * TWOPI;
    Py_RETURN_NONE;
}

static PyMemberDef FastSine_members[] =
{
    {"server", T_OBJECT_EX, offsetof(FastSine, server), 0, "Pyo server."},
    {"stream", T_OBJECT_EX, offsetof(FastSine, stream), 0, "Stream object."},
    {"freq", T_OBJECT_EX, offsetof(FastSine, freq), 0, "Frequency in cycle per second."},
    {"mul", T_OBJECT_EX, offsetof(FastSine, mul), 0, "Mul factor."},
    {"add", T_OBJECT_EX, offsetof(FastSine, add), 0, "Add factor."},
    {NULL}  /* Sentinel */
};

static PyMethodDef FastSine_methods[] =
{
    {"getServer", (PyCFunction)FastSine_getServer, METH_NOARGS, "Returns server object."},
    {"_getStream", (PyCFunction)FastSine_getStream, METH_NOARGS, "Returns stream object."},
    {"play", (PyCFunction)FastSine_play, METH_VARARGS | METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
    {"out", (PyCFunction)FastSine_out, METH_VARARGS | METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
    {"stop", (PyCFunction)FastSine_stop, METH_VARARGS | METH_KEYWORDS, "Stops computing."},
    {"setFreq", (PyCFunction)FastSine_setFreq, METH_O, "Sets oscillator frequency in cycle per second."},
    {"setQuality", (PyCFunction)FastSine_setQuality, METH_O, "Sets approximation quality."},
    {"reset", (PyCFunction)FastSine_reset, METH_NOARGS, "Resets pointer position to 0."},
    {"setMul", (PyCFunction)FastSine_setMul, METH_O, "Sets FastSine mul factor."},
    {"setAdd", (PyCFunction)FastSine_setAdd, METH_O, "Sets FastSine add factor."},
    {"setSub", (PyCFunction)FastSine_setSub, METH_O, "Sets inverse add factor."},
    {"setDiv", (PyCFunction)FastSine_setDiv, METH_O, "Sets inverse mul factor."},
    {NULL}  /* Sentinel */
};

static PyNumberMethods FastSine_as_number =
{
    (binaryfunc)FastSine_add,                      /*nb_add*/
    (binaryfunc)FastSine_sub,                 /*nb_subtract*/
    (binaryfunc)FastSine_multiply,                 /*nb_multiply*/
    0,                /*nb_remainder*/
    0,                   /*nb_divmod*/
    0,                   /*nb_power*/
    0,                  /*nb_neg*/
    0,                /*nb_pos*/
    0,                  /*(unaryfunc)array_abs*/
    0,                    /*nb_nonzero*/
    0,                    /*nb_invert*/
    0,               /*nb_lshift*/
    0,              /*nb_rshift*/
    0,              /*nb_and*/
    0,              /*nb_xor*/
    0,               /*nb_or*/
    0,                       /*nb_int*/
    0,                      /*nb_long*/
    0,                     /*nb_float*/
    (binaryfunc)FastSine_inplace_add,              /*inplace_add*/
    (binaryfunc)FastSine_inplace_sub,         /*inplace_subtract*/
    (binaryfunc)FastSine_inplace_multiply,         /*inplace_multiply*/
    0,        /*inplace_remainder*/
    0,           /*inplace_power*/
    0,       /*inplace_lshift*/
    0,      /*inplace_rshift*/
    0,      /*inplace_and*/
    0,      /*inplace_xor*/
    0,       /*inplace_or*/
    0,             /*nb_floor_divide*/
    (binaryfunc)FastSine_div,                       /*nb_true_divide*/
    0,     /*nb_inplace_floor_divide*/
    (binaryfunc)FastSine_inplace_div,                       /*nb_inplace_true_divide*/
    0,                     /* nb_index */
};

PyTypeObject FastSineType =
{
    PyVarObject_HEAD_INIT(NULL, 0)
    "_pyo.FastSine_base",         /*tp_name*/
    sizeof(FastSine),         /*tp_basicsize*/
    0,                         /*tp_itemsize*/
    (destructor)FastSine_dealloc, /*tp_dealloc*/
    0,                         /*tp_print*/
    0,                         /*tp_getattr*/
    0,                         /*tp_setattr*/
    0,                         /*tp_as_async (tp_compare in Python 2)*/
    0,                         /*tp_repr*/
    &FastSine_as_number,             /*tp_as_number*/
    0,                         /*tp_as_sequence*/
    0,                         /*tp_as_mapping*/
    0,                         /*tp_hash */
    0,                         /*tp_call*/
    0,                         /*tp_str*/
    0,                         /*tp_getattro*/
    0,                         /*tp_setattro*/
    0,                         /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,  /*tp_flags*/
    "FastSine objects. Generates a sinewave.",           /* tp_doc */
    (traverseproc)FastSine_traverse,   /* tp_traverse */
    (inquiry)FastSine_clear,           /* tp_clear */
    0,                     /* tp_richcompare */
    0,                     /* tp_weaklistoffset */
    0,                     /* tp_iter */
    0,                     /* tp_iternext */
    FastSine_methods,             /* tp_methods */
    FastSine_members,             /* tp_members */
    0,                      /* tp_getset */
    0,                         /* tp_base */
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    0,                         /* tp_dictoffset */
    0,      /* tp_init */
    0,                         /* tp_alloc */
    FastSine_new,                 /* tp_new */
};

/*******************/
/* SineLoop object */
/*******************/
typedef struct
{
    pyo_audio_HEAD
    PyObject *freq;
    Stream *freq_stream;
    PyObject *feedback;
    Stream *feedback_stream;
    int modebuffer[4];
    MYFLT pointerPos;
    MYFLT lastValue;
} SineLoop;

static void
SineLoop_readframes_ii(SineLoop *self)
{
    MYFLT inc, fr, feed, pos;
    int i, ipart;

    fr = PyFloat_AS_DOUBLE(self->freq);
    feed = _clip(PyFloat_AS_DOUBLE(self->feedback)) * 512;
    inc = fr * 512 / self->sr;

    for (i = 0; i < self->bufsize; i++)
    {
        self->pointerPos = Sine_clip(self->pointerPos);
        pos = Sine_clip(self->pointerPos + self->lastValue * feed);
        ipart = (int)pos;
        self->data[i] = self->lastValue = SINE_ARRAY[ipart] + (SINE_ARRAY[ipart + 1] - SINE_ARRAY[ipart]) * (pos - ipart);
        self->pointerPos += inc;
    }
}

static void
SineLoop_readframes_ai(SineLoop *self)
{
    MYFLT inc, feed, pos, fac;
    int i, ipart;

    MYFLT *fr = Stream_getData((Stream *)self->freq_stream);
    feed = _clip(PyFloat_AS_DOUBLE(self->feedback)) * 512;

    fac = 512 / self->sr;

    for (i = 0; i < self->bufsize; i++)
    {
        inc = fr[i] * fac;
        self->pointerPos = Sine_clip(self->pointerPos);
        pos = Sine_clip(self->pointerPos + self->lastValue * feed);
        ipart = (int)pos;
        self->data[i] = self->lastValue = SINE_ARRAY[ipart] + (SINE_ARRAY[ipart + 1] - SINE_ARRAY[ipart]) * (pos - ipart);
        self->pointerPos += inc;
    }
}

static void
SineLoop_readframes_ia(SineLoop *self)
{
    MYFLT inc, fr, feed, pos;
    int i, ipart;

    fr = PyFloat_AS_DOUBLE(self->freq);
    MYFLT *fd = Stream_getData((Stream *)self->feedback_stream);
    inc = fr * 512 / self->sr;

    for (i = 0; i < self->bufsize; i++)
    {
        feed = _clip(fd[i]) * 512;
        self->pointerPos = Sine_clip(self->pointerPos);
        pos = Sine_clip(self->pointerPos + self->lastValue * feed);
        ipart = (int)pos;
        self->data[i] = self->lastValue = SINE_ARRAY[ipart] + (SINE_ARRAY[ipart + 1] - SINE_ARRAY[ipart]) * (pos - ipart);
        self->pointerPos += inc;
    }
}

static void
SineLoop_readframes_aa(SineLoop *self)
{
    MYFLT inc, feed, pos, fac;
    int i, ipart;

    MYFLT *fr = Stream_getData((Stream *)self->freq_stream);
    MYFLT *fd = Stream_getData((Stream *)self->feedback_stream);

    fac = 512 / self->sr;

    for (i = 0; i < self->bufsize; i++)
    {
        inc = fr[i] * fac;
        feed = _clip(fd[i]) * 512;
        self->pointerPos = Sine_clip(self->pointerPos);
        pos = Sine_clip(self->pointerPos + self->lastValue * feed);
        ipart = (int)pos;
        self->data[i] = self->lastValue = SINE_ARRAY[ipart] + (SINE_ARRAY[ipart + 1] - SINE_ARRAY[ipart]) * (pos - ipart);
        self->pointerPos += inc;
    }
}

static void SineLoop_postprocessing_ii(SineLoop *self) { POST_PROCESSING_II };
static void SineLoop_postprocessing_ai(SineLoop *self) { POST_PROCESSING_AI };
static void SineLoop_postprocessing_ia(SineLoop *self) { POST_PROCESSING_IA };
static void SineLoop_postprocessing_aa(SineLoop *self) { POST_PROCESSING_AA };
static void SineLoop_postprocessing_ireva(SineLoop *self) { POST_PROCESSING_IREVA };
static void SineLoop_postprocessing_areva(SineLoop *self) { POST_PROCESSING_AREVA };
static void SineLoop_postprocessing_revai(SineLoop *self) { POST_PROCESSING_REVAI };
static void SineLoop_postprocessing_revaa(SineLoop *self) { POST_PROCESSING_REVAA };
static void SineLoop_postprocessing_revareva(SineLoop *self) { POST_PROCESSING_REVAREVA };

static void
SineLoop_setProcMode(SineLoop *self)
{
    int procmode, muladdmode;
    procmode = self->modebuffer[2] + self->modebuffer[3] * 10;
    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;

    switch (procmode)
    {
        case 0:
            self->proc_func_ptr = SineLoop_readframes_ii;
            break;

        case 1:
            self->proc_func_ptr = SineLoop_readframes_ai;
            break;

        case 10:
            self->proc_func_ptr = SineLoop_readframes_ia;
            break;

        case 11:
            self->proc_func_ptr = SineLoop_readframes_aa;
            break;
    }

    switch (muladdmode)
    {
        case 0:
            self->muladd_func_ptr = SineLoop_postprocessing_ii;
            break;

        case 1:
            self->muladd_func_ptr = SineLoop_postprocessing_ai;
            break;

        case 2:
            self->muladd_func_ptr = SineLoop_postprocessing_revai;
            break;

        case 10:
            self->muladd_func_ptr = SineLoop_postprocessing_ia;
            break;

        case 11:
            self->muladd_func_ptr = SineLoop_postprocessing_aa;
            break;

        case 12:
            self->muladd_func_ptr = SineLoop_postprocessing_revaa;
            break;

        case 20:
            self->muladd_func_ptr = SineLoop_postprocessing_ireva;
            break;

        case 21:
            self->muladd_func_ptr = SineLoop_postprocessing_areva;
            break;

        case 22:
            self->muladd_func_ptr = SineLoop_postprocessing_revareva;
            break;
    }
}

static void
SineLoop_compute_next_data_frame(SineLoop *self)
{
    (*self->proc_func_ptr)(self);
    (*self->muladd_func_ptr)(self);
}

static int
SineLoop_traverse(SineLoop *self, visitproc visit, void *arg)
{
    pyo_VISIT
    Py_VISIT(self->freq);
    Py_VISIT(self->feedback);
    return 0;
}

static int
SineLoop_clear(SineLoop *self)
{
    pyo_CLEAR
    Py_CLEAR(self->freq);
    Py_CLEAR(self->feedback);
    return 0;
}

static void
SineLoop_dealloc(SineLoop* self)
{
    pyo_DEALLOC
    SineLoop_clear(self);
    Py_TYPE(self->stream)->tp_free((PyObject*)self->stream);
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject *
SineLoop_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    int i;
    PyObject *freqtmp = NULL, *feedbacktmp = NULL, *multmp = NULL, *addtmp = NULL;
    SineLoop *self;
    self = (SineLoop *)type->tp_alloc(type, 0);

    self->freq = PyFloat_FromDouble(1000);
    self->feedback = PyFloat_FromDouble(0.0);
    self->modebuffer[0] = 0;
    self->modebuffer[1] = 0;
    self->modebuffer[2] = 0;
    self->modebuffer[3] = 0;
    self->pointerPos = self->lastValue = 0.;

    INIT_OBJECT_COMMON
    Stream_setFunctionPtr(self->stream, SineLoop_compute_next_data_frame);
    self->mode_func_ptr = SineLoop_setProcMode;

    static char *kwlist[] = {"freq", "feedback", "mul", "add", NULL};

    if (! PyArg_ParseTupleAndKeywords(args, kwds, "|OOOO", kwlist, &freqtmp, &feedbacktmp, &multmp, &addtmp))
        Py_RETURN_NONE;

    if (freqtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setFreq", "O", freqtmp);
    }

    if (feedbacktmp)
    {
        PyObject_CallMethod((PyObject *)self, "setFeedback", "O", feedbacktmp);
    }

    if (multmp)
    {
        PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
    }

    if (addtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
    }

    PyObject_CallMethod(self->server, "addStream", "O", self->stream);

    (*self->mode_func_ptr)(self);

    return (PyObject *)self;
}

static PyObject * SineLoop_getServer(SineLoop* self) { GET_SERVER };
static PyObject * SineLoop_getStream(SineLoop* self) { GET_STREAM };
static PyObject * SineLoop_setMul(SineLoop *self, PyObject *arg) { SET_MUL };
static PyObject * SineLoop_setAdd(SineLoop *self, PyObject *arg) { SET_ADD };
static PyObject * SineLoop_setSub(SineLoop *self, PyObject *arg) { SET_SUB };
static PyObject * SineLoop_setDiv(SineLoop *self, PyObject *arg) { SET_DIV };

static PyObject * SineLoop_play(SineLoop *self, PyObject *args, PyObject *kwds) { PLAY };
static PyObject * SineLoop_out(SineLoop *self, PyObject *args, PyObject *kwds) { OUT };
static PyObject * SineLoop_stop(SineLoop *self, PyObject *args, PyObject *kwds) { STOP };

static PyObject * SineLoop_multiply(SineLoop *self, PyObject *arg) { MULTIPLY };
static PyObject * SineLoop_inplace_multiply(SineLoop *self, PyObject *arg) { INPLACE_MULTIPLY };
static PyObject * SineLoop_add(SineLoop *self, PyObject *arg) { ADD };
static PyObject * SineLoop_inplace_add(SineLoop *self, PyObject *arg) { INPLACE_ADD };
static PyObject * SineLoop_sub(SineLoop *self, PyObject *arg) { SUB };
static PyObject * SineLoop_inplace_sub(SineLoop *self, PyObject *arg) { INPLACE_SUB };
static PyObject * SineLoop_div(SineLoop *self, PyObject *arg) { DIV };
static PyObject * SineLoop_inplace_div(SineLoop *self, PyObject *arg) { INPLACE_DIV };

static PyObject * SineLoop_setFreq(SineLoop *self, PyObject *arg) { SET_PARAM(self->freq, self->freq_stream, 2); }
static PyObject * SineLoop_setFeedback(SineLoop *self, PyObject *arg) { SET_PARAM(self->feedback, self->feedback_stream, 3); }

static PyMemberDef SineLoop_members[] =
{
    {"server", T_OBJECT_EX, offsetof(SineLoop, server), 0, "Pyo server."},
    {"stream", T_OBJECT_EX, offsetof(SineLoop, stream), 0, "Stream object."},
    {"freq", T_OBJECT_EX, offsetof(SineLoop, freq), 0, "Frequency in cycle per second."},
    {"feedback", T_OBJECT_EX, offsetof(SineLoop, feedback), 0, "Phase of signal (0 -> 1)"},
    {"mul", T_OBJECT_EX, offsetof(SineLoop, mul), 0, "Mul factor."},
    {"add", T_OBJECT_EX, offsetof(SineLoop, add), 0, "Add factor."},
    {NULL}  /* Sentinel */
};

static PyMethodDef SineLoop_methods[] =
{
    {"getServer", (PyCFunction)SineLoop_getServer, METH_NOARGS, "Returns server object."},
    {"_getStream", (PyCFunction)SineLoop_getStream, METH_NOARGS, "Returns stream object."},
    {"play", (PyCFunction)SineLoop_play, METH_VARARGS | METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
    {"out", (PyCFunction)SineLoop_out, METH_VARARGS | METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
    {"stop", (PyCFunction)SineLoop_stop, METH_VARARGS | METH_KEYWORDS, "Stops computing."},
    {"setFreq", (PyCFunction)SineLoop_setFreq, METH_O, "Sets oscillator frequency in cycle per second."},
    {"setFeedback", (PyCFunction)SineLoop_setFeedback, METH_O, "Sets oscillator feedback between 0 and 1."},
    {"setMul", (PyCFunction)SineLoop_setMul, METH_O, "Sets SineLoop mul factor."},
    {"setAdd", (PyCFunction)SineLoop_setAdd, METH_O, "Sets SineLoop add factor."},
    {"setSub", (PyCFunction)SineLoop_setSub, METH_O, "Sets inverse add factor."},
    {"setDiv", (PyCFunction)SineLoop_setDiv, METH_O, "Sets inverse mul factor."},
    {NULL}  /* Sentinel */
};

static PyNumberMethods SineLoop_as_number =
{
    (binaryfunc)SineLoop_add,                      /*nb_add*/
    (binaryfunc)SineLoop_sub,                 /*nb_subtract*/
    (binaryfunc)SineLoop_multiply,                 /*nb_multiply*/
    0,                /*nb_remainder*/
    0,                   /*nb_divmod*/
    0,                   /*nb_power*/
    0,                  /*nb_neg*/
    0,                /*nb_pos*/
    0,                  /*(unaryfunc)array_abs*/
    0,                    /*nb_nonzero*/
    0,                    /*nb_invert*/
    0,               /*nb_lshift*/
    0,              /*nb_rshift*/
    0,              /*nb_and*/
    0,              /*nb_xor*/
    0,               /*nb_or*/
    0,                       /*nb_int*/
    0,                      /*nb_long*/
    0,                     /*nb_float*/
    (binaryfunc)SineLoop_inplace_add,              /*inplace_add*/
    (binaryfunc)SineLoop_inplace_sub,         /*inplace_subtract*/
    (binaryfunc)SineLoop_inplace_multiply,         /*inplace_multiply*/
    0,        /*inplace_remainder*/
    0,           /*inplace_power*/
    0,       /*inplace_lshift*/
    0,      /*inplace_rshift*/
    0,      /*inplace_and*/
    0,      /*inplace_xor*/
    0,       /*inplace_or*/
    0,             /*nb_floor_divide*/
    (binaryfunc)SineLoop_div,                       /*nb_true_divide*/
    0,     /*nb_inplace_floor_divide*/
    (binaryfunc)SineLoop_inplace_div,                       /*nb_inplace_true_divide*/
    0,                     /* nb_index */
};

PyTypeObject SineLoopType =
{
    PyVarObject_HEAD_INIT(NULL, 0)
    "_pyo.SineLoop_base",         /*tp_name*/
    sizeof(SineLoop),         /*tp_basicsize*/
    0,                         /*tp_itemsize*/
    (destructor)SineLoop_dealloc, /*tp_dealloc*/
    0,                         /*tp_print*/
    0,                         /*tp_getattr*/
    0,                         /*tp_setattr*/
    0,                         /*tp_as_async (tp_compare in Python 2)*/
    0,                         /*tp_repr*/
    &SineLoop_as_number,             /*tp_as_number*/
    0,                         /*tp_as_sequence*/
    0,                         /*tp_as_mapping*/
    0,                         /*tp_hash */
    0,                         /*tp_call*/
    0,                         /*tp_str*/
    0,                         /*tp_getattro*/
    0,                         /*tp_setattro*/
    0,                         /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,  /*tp_flags*/
    "SineLoop objects. Generates a looped sinewave.",           /* tp_doc */
    (traverseproc)SineLoop_traverse,   /* tp_traverse */
    (inquiry)SineLoop_clear,           /* tp_clear */
    0,                     /* tp_richcompare */
    0,                     /* tp_weaklistoffset */
    0,                     /* tp_iter */
    0,                     /* tp_iternext */
    SineLoop_methods,             /* tp_methods */
    SineLoop_members,             /* tp_members */
    0,                      /* tp_getset */
    0,                         /* tp_base */
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    0,                         /* tp_dictoffset */
    0,      /* tp_init */
    0,                         /* tp_alloc */
    SineLoop_new,                 /* tp_new */
};

/***************/
/* Osc objects */
/***************/
static double
Osc_clip(double x, T_SIZE_T size)
{
    if (x < 0)
    {
        x += ((T_SIZE_T)(-x / size) + 1) * size;
    }
    else if (x >= size)
    {
        x -= (T_SIZE_T)(x / size) * size;
    }

    return x;
}

typedef struct
{
    pyo_audio_HEAD
    PyObject *table;
    PyObject *freq;
    Stream *freq_stream;
    PyObject *phase;
    Stream *phase_stream;
    int modebuffer[4];
    double pointerPos;
    int interp; /* 0 = default to 2, 1 = nointerp, 2 = linear, 3 = cos, 4 = cubic */
    MYFLT (*interp_func_ptr)(MYFLT *, T_SIZE_T, MYFLT, T_SIZE_T);
} Osc;

static void
Osc_readframes_ii(Osc *self)
{
    int i;
    MYFLT fr, ph, fpart;
    double inc, pos;
    T_SIZE_T ipart;
    MYFLT *tablelist = TableStream_getData((TableStream *)self->table);
    T_SIZE_T size = TableStream_getSize((TableStream *)self->table);

    fr = PyFloat_AS_DOUBLE(self->freq);
    ph = PyFloat_AS_DOUBLE(self->phase);
    inc = fr * size / self->sr;

    ph *= size;

    for (i = 0; i < self->bufsize; i++)
    {
        self->pointerPos += inc;
        self->pointerPos = Osc_clip(self->pointerPos, size);
        pos = self->pointerPos + ph;

        if (pos >= size)
            pos -= size;

        ipart = (T_SIZE_T)pos;
        fpart = pos - ipart;
        self->data[i] = (*self->interp_func_ptr)(tablelist, ipart, fpart, size);
    }
}

static void
Osc_readframes_ai(Osc *self)
{
    int i;
    MYFLT ph, fpart, sizeOnSr;
    double inc, pos;
    T_SIZE_T ipart;
    MYFLT *tablelist = TableStream_getData((TableStream *)self->table);
    T_SIZE_T size = TableStream_getSize((TableStream *)self->table);

    MYFLT *fr = Stream_getData((Stream *)self->freq_stream);
    ph = PyFloat_AS_DOUBLE(self->phase);
    ph *= size;

    sizeOnSr = size / self->sr;

    for (i = 0; i < self->bufsize; i++)
    {
        inc = fr[i] * sizeOnSr;
        self->pointerPos += inc;
        self->pointerPos = Osc_clip(self->pointerPos, size);
        pos = self->pointerPos + ph;

        if (pos >= size)
            pos -= size;

        ipart = (T_SIZE_T)pos;
        fpart = pos - ipart;
        self->data[i] = (*self->interp_func_ptr)(tablelist, ipart, fpart, size);
    }
}

static void
Osc_readframes_ia(Osc *self)
{
    int i;
    MYFLT fr, pha, fpart;
    double inc, pos;
    T_SIZE_T ipart;
    MYFLT *tablelist = TableStream_getData((TableStream *)self->table);
    T_SIZE_T size = TableStream_getSize((TableStream *)self->table);

    fr = PyFloat_AS_DOUBLE(self->freq);
    MYFLT *ph = Stream_getData((Stream *)self->phase_stream);
    inc = fr * size / self->sr;

    for (i = 0; i < self->bufsize; i++)
    {
        pha = ph[i] * size;
        self->pointerPos += inc;
        self->pointerPos = Osc_clip(self->pointerPos, size);
        pos = self->pointerPos + pha;

        if (pos >= size)
            pos -= size;

        ipart = (T_SIZE_T)pos;
        fpart = pos - ipart;
        self->data[i] = (*self->interp_func_ptr)(tablelist, ipart, fpart, size);
    }
}

static void
Osc_readframes_aa(Osc *self)
{
    int i;
    MYFLT pha, fpart, sizeOnSr;
    double inc, pos;
    T_SIZE_T ipart;
    MYFLT *tablelist = TableStream_getData((TableStream *)self->table);
    T_SIZE_T size = TableStream_getSize((TableStream *)self->table);

    MYFLT *fr = Stream_getData((Stream *)self->freq_stream);
    MYFLT *ph = Stream_getData((Stream *)self->phase_stream);

    sizeOnSr = size / self->sr;

    for (i = 0; i < self->bufsize; i++)
    {
        inc = fr[i] * sizeOnSr;
        pha = ph[i] * size;
        self->pointerPos += inc;
        self->pointerPos = Osc_clip(self->pointerPos, size);
        pos = self->pointerPos + pha;

        if (pos >= size)
            pos -= size;

        ipart = (T_SIZE_T)pos;
        fpart = pos - ipart;
        self->data[i] = (*self->interp_func_ptr)(tablelist, ipart, fpart, size);
    }
}

static void Osc_postprocessing_ii(Osc *self) { POST_PROCESSING_II };
static void Osc_postprocessing_ai(Osc *self) { POST_PROCESSING_AI };
static void Osc_postprocessing_ia(Osc *self) { POST_PROCESSING_IA };
static void Osc_postprocessing_aa(Osc *self) { POST_PROCESSING_AA };
static void Osc_postprocessing_ireva(Osc *self) { POST_PROCESSING_IREVA };
static void Osc_postprocessing_areva(Osc *self) { POST_PROCESSING_AREVA };
static void Osc_postprocessing_revai(Osc *self) { POST_PROCESSING_REVAI };
static void Osc_postprocessing_revaa(Osc *self) { POST_PROCESSING_REVAA };
static void Osc_postprocessing_revareva(Osc *self) { POST_PROCESSING_REVAREVA };

static void
Osc_setProcMode(Osc *self)
{
    int procmode, muladdmode;
    procmode = self->modebuffer[2] + self->modebuffer[3] * 10;
    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;

    switch (procmode)
    {
        case 0:
            self->proc_func_ptr = Osc_readframes_ii;
            break;

        case 1:
            self->proc_func_ptr = Osc_readframes_ai;
            break;

        case 10:
            self->proc_func_ptr = Osc_readframes_ia;
            break;

        case 11:
            self->proc_func_ptr = Osc_readframes_aa;
            break;
    }

    switch (muladdmode)
    {
        case 0:
            self->muladd_func_ptr = Osc_postprocessing_ii;
            break;

        case 1:
            self->muladd_func_ptr = Osc_postprocessing_ai;
            break;

        case 2:
            self->muladd_func_ptr = Osc_postprocessing_revai;
            break;

        case 10:
            self->muladd_func_ptr = Osc_postprocessing_ia;
            break;

        case 11:
            self->muladd_func_ptr = Osc_postprocessing_aa;
            break;

        case 12:
            self->muladd_func_ptr = Osc_postprocessing_revaa;
            break;

        case 20:
            self->muladd_func_ptr = Osc_postprocessing_ireva;
            break;

        case 21:
            self->muladd_func_ptr = Osc_postprocessing_areva;
            break;

        case 22:
            self->muladd_func_ptr = Osc_postprocessing_revareva;
            break;
    }
}

static void
Osc_compute_next_data_frame(Osc *self)
{
    (*self->proc_func_ptr)(self);
    (*self->muladd_func_ptr)(self);
}

static int
Osc_traverse(Osc *self, visitproc visit, void *arg)
{
    pyo_VISIT
    Py_VISIT(self->phase);
    Py_VISIT(self->freq);
    return 0;
}

static int
Osc_clear(Osc *self)
{
    pyo_CLEAR
    Py_CLEAR(self->phase);
    Py_CLEAR(self->freq);
    return 0;
}

static void
Osc_dealloc(Osc* self)
{
    pyo_DEALLOC
    Osc_clear(self);
    Py_TYPE(self->stream)->tp_free((PyObject*)self->stream);
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject *
Osc_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    int i;
    PyObject *tabletmp, *freqtmp = NULL, *phasetmp = NULL, *multmp = NULL, *addtmp = NULL;
    Osc *self;
    self = (Osc *)type->tp_alloc(type, 0);

    self->freq = PyFloat_FromDouble(1000);
    self->phase = PyFloat_FromDouble(0);
    self->modebuffer[0] = 0;
    self->modebuffer[1] = 0;
    self->modebuffer[2] = 0;
    self->modebuffer[3] = 0;
    self->pointerPos = 0.;
    self->interp = 2;

    INIT_OBJECT_COMMON
    Stream_setFunctionPtr(self->stream, Osc_compute_next_data_frame);
    self->mode_func_ptr = Osc_setProcMode;

    static char *kwlist[] = {"table", "freq", "phase", "interp", "mul", "add", NULL};

    if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|OOiOO", kwlist, &tabletmp, &freqtmp, &phasetmp, &self->interp, &multmp, &addtmp))
        Py_RETURN_NONE;

    if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 )
    {
        PyErr_SetString(PyExc_TypeError, "\"table\" argument of Osc must be a PyoTableObject.\n");
        Py_RETURN_NONE;
    }

    self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");

    if (freqtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setFreq", "O", freqtmp);
    }

    if (phasetmp)
    {
        PyObject_CallMethod((PyObject *)self, "setPhase", "O", phasetmp);
    }

    if (multmp)
    {
        PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
    }

    if (addtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
    }

    PyObject_CallMethod(self->server, "addStream", "O", self->stream);

    (*self->mode_func_ptr)(self);

    SET_INTERP_POINTER

    return (PyObject *)self;
}

static PyObject * Osc_getServer(Osc* self) { GET_SERVER };
static PyObject * Osc_getStream(Osc* self) { GET_STREAM };
static PyObject * Osc_setMul(Osc *self, PyObject *arg) { SET_MUL };
static PyObject * Osc_setAdd(Osc *self, PyObject *arg) { SET_ADD };
static PyObject * Osc_setSub(Osc *self, PyObject *arg) { SET_SUB };
static PyObject * Osc_setDiv(Osc *self, PyObject *arg) { SET_DIV };

static PyObject * Osc_play(Osc *self, PyObject *args, PyObject *kwds) { PLAY };
static PyObject * Osc_out(Osc *self, PyObject *args, PyObject *kwds) { OUT };
static PyObject * Osc_stop(Osc *self, PyObject *args, PyObject *kwds) { STOP };

static PyObject * Osc_multiply(Osc *self, PyObject *arg) { MULTIPLY };
static PyObject * Osc_inplace_multiply(Osc *self, PyObject *arg) { INPLACE_MULTIPLY };
static PyObject * Osc_add(Osc *self, PyObject *arg) { ADD };
static PyObject * Osc_inplace_add(Osc *self, PyObject *arg) { INPLACE_ADD };
static PyObject * Osc_sub(Osc *self, PyObject *arg) { SUB };
static PyObject * Osc_inplace_sub(Osc *self, PyObject *arg) { INPLACE_SUB };
static PyObject * Osc_div(Osc *self, PyObject *arg) { DIV };
static PyObject * Osc_inplace_div(Osc *self, PyObject *arg) { INPLACE_DIV };

static PyObject *
Osc_getTable(Osc* self)
{
    Py_INCREF(self->table);
    return self->table;
};

static PyObject *
Osc_setTable(Osc *self, PyObject *arg)
{
    ASSERT_ARG_NOT_NULL

    Py_DECREF(self->table);
    self->table = PyObject_CallMethod((PyObject *)arg, "getTableStream", "");

    Py_RETURN_NONE;
}

static PyObject * Osc_setFreq(Osc *self, PyObject *arg) { SET_PARAM(self->freq, self->freq_stream, 2); }
static PyObject * Osc_setPhase(Osc *self, PyObject *arg) { SET_PARAM(self->phase, self->phase_stream, 3); }

static PyObject *
Osc_setInterp(Osc *self, PyObject *arg)
{
    ASSERT_ARG_NOT_NULL

    if (PyNumber_Check(arg))
    {
        self->interp = PyLong_AsLong(PyNumber_Long(arg));
    }

    SET_INTERP_POINTER

    Py_RETURN_NONE;
}

static PyObject *
Osc_reset(Osc *self)
{
    self->pointerPos = 0.0;
    Py_RETURN_NONE;
}

static PyMemberDef Osc_members[] =
{
    {"server", T_OBJECT_EX, offsetof(Osc, server), 0, "Pyo server."},
    {"stream", T_OBJECT_EX, offsetof(Osc, stream), 0, "Stream object."},
    {"table", T_OBJECT_EX, offsetof(Osc, table), 0, "Waveform table."},
    {"freq", T_OBJECT_EX, offsetof(Osc, freq), 0, "Frequency in cycle per second."},
    {"phase", T_OBJECT_EX, offsetof(Osc, phase), 0, "Oscillator phase."},
    {"mul", T_OBJECT_EX, offsetof(Osc, mul), 0, "Mul factor."},
    {"add", T_OBJECT_EX, offsetof(Osc, add), 0, "Add factor."},
    {NULL}  /* Sentinel */
};

static PyMethodDef Osc_methods[] =
{
    {"getTable", (PyCFunction)Osc_getTable, METH_NOARGS, "Returns waveform table object."},
    {"getServer", (PyCFunction)Osc_getServer, METH_NOARGS, "Returns server object."},
    {"_getStream", (PyCFunction)Osc_getStream, METH_NOARGS, "Returns stream object."},
    {"play", (PyCFunction)Osc_play, METH_VARARGS | METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
    {"out", (PyCFunction)Osc_out, METH_VARARGS | METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
    {"stop", (PyCFunction)Osc_stop, METH_VARARGS | METH_KEYWORDS, "Stops computing."},
    {"setTable", (PyCFunction)Osc_setTable, METH_O, "Sets oscillator table."},
    {"setFreq", (PyCFunction)Osc_setFreq, METH_O, "Sets oscillator frequency in cycle per second."},
    {"setPhase", (PyCFunction)Osc_setPhase, METH_O, "Sets oscillator phase."},
    {"setInterp", (PyCFunction)Osc_setInterp, METH_O, "Sets oscillator interpolation mode."},
    {"reset", (PyCFunction)Osc_reset, METH_NOARGS, "Resets pointer position to 0."},
    {"setMul", (PyCFunction)Osc_setMul, METH_O, "Sets oscillator mul factor."},
    {"setAdd", (PyCFunction)Osc_setAdd, METH_O, "Sets oscillator add factor."},
    {"setSub", (PyCFunction)Osc_setSub, METH_O, "Sets oscillator inverse add factor."},
    {"setDiv", (PyCFunction)Osc_setDiv, METH_O, "Sets inverse mul factor."},
    {NULL}  /* Sentinel */
};

static PyNumberMethods Osc_as_number =
{
    (binaryfunc)Osc_add,                      /*nb_add*/
    (binaryfunc)Osc_sub,                 /*nb_subtract*/
    (binaryfunc)Osc_multiply,                 /*nb_multiply*/
    0,                /*nb_remainder*/
    0,                   /*nb_divmod*/
    0,                   /*nb_power*/
    0,                  /*nb_neg*/
    0,                /*nb_pos*/
    0,                  /*(unaryfunc)array_abs,*/
    0,                    /*nb_nonzero*/
    0,                    /*nb_invert*/
    0,               /*nb_lshift*/
    0,              /*nb_rshift*/
    0,              /*nb_and*/
    0,              /*nb_xor*/
    0,               /*nb_or*/
    0,                       /*nb_int*/
    0,                      /*nb_long*/
    0,                     /*nb_float*/
    (binaryfunc)Osc_inplace_add,              /*inplace_add*/
    (binaryfunc)Osc_inplace_sub,         /*inplace_subtract*/
    (binaryfunc)Osc_inplace_multiply,         /*inplace_multiply*/
    0,        /*inplace_remainder*/
    0,           /*inplace_power*/
    0,       /*inplace_lshift*/
    0,      /*inplace_rshift*/
    0,      /*inplace_and*/
    0,      /*inplace_xor*/
    0,       /*inplace_or*/
    0,             /*nb_floor_divide*/
    (binaryfunc)Osc_div,                       /*nb_true_divide*/
    0,     /*nb_inplace_floor_divide*/
    (binaryfunc)Osc_inplace_div,                       /*nb_inplace_true_divide*/
    0,                     /* nb_index */
};

PyTypeObject OscType =
{
    PyVarObject_HEAD_INIT(NULL, 0)
    "_pyo.Osc_base",         /*tp_name*/
    sizeof(Osc),         /*tp_basicsize*/
    0,                         /*tp_itemsize*/
    (destructor)Osc_dealloc, /*tp_dealloc*/
    0,                         /*tp_print*/
    0,                         /*tp_getattr*/
    0,                         /*tp_setattr*/
    0,                         /*tp_as_async (tp_compare in Python 2)*/
    0,                         /*tp_repr*/
    &Osc_as_number,             /*tp_as_number*/
    0,                         /*tp_as_sequence*/
    0,                         /*tp_as_mapping*/
    0,                         /*tp_hash */
    0,                         /*tp_call*/
    0,                         /*tp_str*/
    0,                         /*tp_getattro*/
    0,                         /*tp_setattro*/
    0,                         /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
    "Osc objects. Generates an oscillatory waveform.",           /* tp_doc */
    (traverseproc)Osc_traverse,   /* tp_traverse */
    (inquiry)Osc_clear,           /* tp_clear */
    0,                     /* tp_richcompare */
    0,                     /* tp_weaklistoffset */
    0,                     /* tp_iter */
    0,                     /* tp_iternext */
    Osc_methods,             /* tp_methods */
    Osc_members,             /* tp_members */
    0,                      /* tp_getset */
    0,                         /* tp_base */
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    0,                         /* tp_dictoffset */
    0,      /* tp_init */
    0,                         /* tp_alloc */
    Osc_new,                 /* tp_new */
};

/**************/
/* OscLoop object */
/**************/
typedef struct
{
    pyo_audio_HEAD
    PyObject *table;
    PyObject *freq;
    Stream *freq_stream;
    PyObject *feedback;
    Stream *feedback_stream;
    int modebuffer[4];
    double pointerPos;
    MYFLT lastValue;
} OscLoop;

static void
OscLoop_readframes_ii(OscLoop *self)
{
    int i;
    MYFLT fr, feed, pos, inc;
    T_SIZE_T ipart;
    MYFLT *tablelist = TableStream_getData((TableStream *)self->table);
    T_SIZE_T size = TableStream_getSize((TableStream *)self->table);

    fr = PyFloat_AS_DOUBLE(self->freq);
    feed = _clip(PyFloat_AS_DOUBLE(self->feedback)) * size;
    inc = fr * size / self->sr;

    for (i = 0; i < self->bufsize; i++)
    {
        self->pointerPos += inc;
        self->pointerPos = Osc_clip(self->pointerPos, size);
        pos = self->pointerPos + (self->lastValue * feed);

        if (pos >= size)
            pos -= size;
        else if (pos < 0)
            pos += size;

        ipart = (T_SIZE_T)pos;
        self->data[i] = self->lastValue = tablelist[ipart] + (tablelist[ipart + 1] - tablelist[ipart]) * (pos - ipart);
    }
}

static void
OscLoop_readframes_ai(OscLoop *self)
{
    int i;
    MYFLT inc, feed, pos, sizeOnSr;
    T_SIZE_T ipart;
    MYFLT *tablelist = TableStream_getData((TableStream *)self->table);
    T_SIZE_T size = TableStream_getSize((TableStream *)self->table);

    MYFLT *fr = Stream_getData((Stream *)self->freq_stream);
    feed = _clip(PyFloat_AS_DOUBLE(self->feedback)) * size;

    sizeOnSr = size / self->sr;

    for (i = 0; i < self->bufsize; i++)
    {
        inc = fr[i] * sizeOnSr;
        self->pointerPos += inc;
        self->pointerPos = Osc_clip(self->pointerPos, size);
        pos = self->pointerPos + (self->lastValue * feed);

        if (pos >= size)
            pos -= size;
        else if (pos < 0)
            pos += size;

        ipart = (T_SIZE_T)pos;
        self->data[i] = self->lastValue = tablelist[ipart] + (tablelist[ipart + 1] - tablelist[ipart]) * (pos - ipart);
    }
}

static void
OscLoop_readframes_ia(OscLoop *self)
{
    int i;
    MYFLT fr, feed, pos, inc;
    T_SIZE_T ipart;
    MYFLT *tablelist = TableStream_getData((TableStream *)self->table);
    T_SIZE_T size = TableStream_getSize((TableStream *)self->table);

    fr = PyFloat_AS_DOUBLE(self->freq);
    MYFLT *fd = Stream_getData((Stream *)self->feedback_stream);
    inc = fr * size / self->sr;

    for (i = 0; i < self->bufsize; i++)
    {
        feed = _clip(fd[i]) * size;
        self->pointerPos += inc;
        self->pointerPos = Osc_clip(self->pointerPos, size);
        pos = self->pointerPos + (self->lastValue * feed);

        if (pos >= size)
            pos -= size;
        else if (pos < 0)
            pos += size;

        ipart = (T_SIZE_T)pos;
        self->data[i] = self->lastValue = tablelist[ipart] + (tablelist[ipart + 1] - tablelist[ipart]) * (pos - ipart);
    }
}

static void
OscLoop_readframes_aa(OscLoop *self)
{
    int i;
    MYFLT inc, feed, pos, sizeOnSr;
    T_SIZE_T ipart;
    MYFLT *tablelist = TableStream_getData((TableStream *)self->table);
    T_SIZE_T size = TableStream_getSize((TableStream *)self->table);

    MYFLT *fr = Stream_getData((Stream *)self->freq_stream);
    MYFLT *fd = Stream_getData((Stream *)self->feedback_stream);

    sizeOnSr = size / self->sr;

    for (i = 0; i < self->bufsize; i++)
    {
        inc = fr[i] * sizeOnSr;
        feed = _clip(fd[i]) * size;
        self->pointerPos += inc;
        self->pointerPos = Osc_clip(self->pointerPos, size);
        pos = self->pointerPos + (self->lastValue * feed);

        if (pos >= size)
            pos -= size;
        else if (pos < 0)
            pos += size;

        ipart = (T_SIZE_T)pos;
        self->data[i] = self->lastValue = tablelist[ipart] + (tablelist[ipart + 1] - tablelist[ipart]) * (pos - ipart);
    }
}

static void OscLoop_postprocessing_ii(OscLoop *self) { POST_PROCESSING_II };
static void OscLoop_postprocessing_ai(OscLoop *self) { POST_PROCESSING_AI };
static void OscLoop_postprocessing_ia(OscLoop *self) { POST_PROCESSING_IA };
static void OscLoop_postprocessing_aa(OscLoop *self) { POST_PROCESSING_AA };
static void OscLoop_postprocessing_ireva(OscLoop *self) { POST_PROCESSING_IREVA };
static void OscLoop_postprocessing_areva(OscLoop *self) { POST_PROCESSING_AREVA };
static void OscLoop_postprocessing_revai(OscLoop *self) { POST_PROCESSING_REVAI };
static void OscLoop_postprocessing_revaa(OscLoop *self) { POST_PROCESSING_REVAA };
static void OscLoop_postprocessing_revareva(OscLoop *self) { POST_PROCESSING_REVAREVA };

static void
OscLoop_setProcMode(OscLoop *self)
{
    int procmode, muladdmode;
    procmode = self->modebuffer[2] + self->modebuffer[3] * 10;
    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;

    switch (procmode)
    {
        case 0:
            self->proc_func_ptr = OscLoop_readframes_ii;
            break;

        case 1:
            self->proc_func_ptr = OscLoop_readframes_ai;
            break;

        case 10:
            self->proc_func_ptr = OscLoop_readframes_ia;
            break;

        case 11:
            self->proc_func_ptr = OscLoop_readframes_aa;
            break;
    }

    switch (muladdmode)
    {
        case 0:
            self->muladd_func_ptr = OscLoop_postprocessing_ii;
            break;

        case 1:
            self->muladd_func_ptr = OscLoop_postprocessing_ai;
            break;

        case 2:
            self->muladd_func_ptr = OscLoop_postprocessing_revai;
            break;

        case 10:
            self->muladd_func_ptr = OscLoop_postprocessing_ia;
            break;

        case 11:
            self->muladd_func_ptr = OscLoop_postprocessing_aa;
            break;

        case 12:
            self->muladd_func_ptr = OscLoop_postprocessing_revaa;
            break;

        case 20:
            self->muladd_func_ptr = OscLoop_postprocessing_ireva;
            break;

        case 21:
            self->muladd_func_ptr = OscLoop_postprocessing_areva;
            break;

        case 22:
            self->muladd_func_ptr = OscLoop_postprocessing_revareva;
            break;
    }
}

static void
OscLoop_compute_next_data_frame(OscLoop *self)
{
    (*self->proc_func_ptr)(self);
    (*self->muladd_func_ptr)(self);
}

static int
OscLoop_traverse(OscLoop *self, visitproc visit, void *arg)
{
    pyo_VISIT
    Py_VISIT(self->feedback);
    Py_VISIT(self->freq);
    return 0;
}

static int
OscLoop_clear(OscLoop *self)
{
    pyo_CLEAR
    Py_CLEAR(self->feedback);
    Py_CLEAR(self->freq);
    return 0;
}

static void
OscLoop_dealloc(OscLoop* self)
{
    pyo_DEALLOC
    OscLoop_clear(self);
    Py_TYPE(self->stream)->tp_free((PyObject*)self->stream);
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject *
OscLoop_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    int i;
    PyObject *tabletmp, *freqtmp = NULL, *feedbacktmp = NULL, *multmp = NULL, *addtmp = NULL;
    OscLoop *self;
    self = (OscLoop *)type->tp_alloc(type, 0);

    self->freq = PyFloat_FromDouble(1000);
    self->feedback = PyFloat_FromDouble(0);
    self->modebuffer[0] = 0;
    self->modebuffer[1] = 0;
    self->modebuffer[2] = 0;
    self->modebuffer[3] = 0;
    self->pointerPos = self->lastValue = 0.;

    INIT_OBJECT_COMMON
    Stream_setFunctionPtr(self->stream, OscLoop_compute_next_data_frame);
    self->mode_func_ptr = OscLoop_setProcMode;

    static char *kwlist[] = {"table", "freq", "feedback", "mul", "add", NULL};

    if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|OOOO", kwlist, &tabletmp, &freqtmp, &feedbacktmp, &multmp, &addtmp))
        Py_RETURN_NONE;

    if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 )
    {
        PyErr_SetString(PyExc_TypeError, "\"table\" argument of OscLoop must be a PyoTableObject.\n");
        Py_RETURN_NONE;
    }

    self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");

    if (feedbacktmp)
    {
        PyObject_CallMethod((PyObject *)self, "setFeedback", "O", feedbacktmp);
    }

    if (freqtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setFreq", "O", freqtmp);
    }

    if (multmp)
    {
        PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
    }

    if (addtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
    }

    PyObject_CallMethod(self->server, "addStream", "O", self->stream);

    (*self->mode_func_ptr)(self);

    return (PyObject *)self;
}

static PyObject * OscLoop_getServer(OscLoop* self) { GET_SERVER };
static PyObject * OscLoop_getStream(OscLoop* self) { GET_STREAM };
static PyObject * OscLoop_setMul(OscLoop *self, PyObject *arg) { SET_MUL };
static PyObject * OscLoop_setAdd(OscLoop *self, PyObject *arg) { SET_ADD };
static PyObject * OscLoop_setSub(OscLoop *self, PyObject *arg) { SET_SUB };
static PyObject * OscLoop_setDiv(OscLoop *self, PyObject *arg) { SET_DIV };

static PyObject * OscLoop_play(OscLoop *self, PyObject *args, PyObject *kwds) { PLAY };
static PyObject * OscLoop_out(OscLoop *self, PyObject *args, PyObject *kwds) { OUT };
static PyObject * OscLoop_stop(OscLoop *self, PyObject *args, PyObject *kwds) { STOP };

static PyObject * OscLoop_multiply(OscLoop *self, PyObject *arg) { MULTIPLY };
static PyObject * OscLoop_inplace_multiply(OscLoop *self, PyObject *arg) { INPLACE_MULTIPLY };
static PyObject * OscLoop_add(OscLoop *self, PyObject *arg) { ADD };
static PyObject * OscLoop_inplace_add(OscLoop *self, PyObject *arg) { INPLACE_ADD };
static PyObject * OscLoop_sub(OscLoop *self, PyObject *arg) { SUB };
static PyObject * OscLoop_inplace_sub(OscLoop *self, PyObject *arg) { INPLACE_SUB };
static PyObject * OscLoop_div(OscLoop *self, PyObject *arg) { DIV };
static PyObject * OscLoop_inplace_div(OscLoop *self, PyObject *arg) { INPLACE_DIV };

static PyObject *
OscLoop_getTable(OscLoop* self)
{
    Py_INCREF(self->table);
    return self->table;
};

static PyObject *
OscLoop_setTable(OscLoop *self, PyObject *arg)
{
    ASSERT_ARG_NOT_NULL

    Py_DECREF(self->table);
    self->table = PyObject_CallMethod((PyObject *)arg, "getTableStream", "");

    Py_RETURN_NONE;
}

static PyObject * OscLoop_setFreq(OscLoop *self, PyObject *arg) { SET_PARAM(self->freq, self->freq_stream, 2); }
static PyObject * OscLoop_setFeedback(OscLoop *self, PyObject *arg) { SET_PARAM(self->feedback, self->feedback_stream, 3); }

static PyMemberDef OscLoop_members[] =
{
    {"server", T_OBJECT_EX, offsetof(OscLoop, server), 0, "Pyo server."},
    {"stream", T_OBJECT_EX, offsetof(OscLoop, stream), 0, "Stream object."},
    {"table", T_OBJECT_EX, offsetof(OscLoop, table), 0, "Waveform table."},
    {"freq", T_OBJECT_EX, offsetof(OscLoop, freq), 0, "Frequency in cycle per second."},
    {"feedback", T_OBJECT_EX, offsetof(OscLoop, feedback), 0, "Oscillator feedback."},
    {"mul", T_OBJECT_EX, offsetof(OscLoop, mul), 0, "Mul factor."},
    {"add", T_OBJECT_EX, offsetof(OscLoop, add), 0, "Add factor."},
    {NULL}  /* Sentinel */
};

static PyMethodDef OscLoop_methods[] =
{
    {"getTable", (PyCFunction)OscLoop_getTable, METH_NOARGS, "Returns waveform table object."},
    {"getServer", (PyCFunction)OscLoop_getServer, METH_NOARGS, "Returns server object."},
    {"_getStream", (PyCFunction)OscLoop_getStream, METH_NOARGS, "Returns stream object."},
    {"play", (PyCFunction)OscLoop_play, METH_VARARGS | METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
    {"out", (PyCFunction)OscLoop_out, METH_VARARGS | METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
    {"stop", (PyCFunction)OscLoop_stop, METH_VARARGS | METH_KEYWORDS, "Stops computing."},
    {"setTable", (PyCFunction)OscLoop_setTable, METH_O, "Sets oscillator table."},
    {"setFreq", (PyCFunction)OscLoop_setFreq, METH_O, "Sets oscillator frequency in cycle per second."},
    {"setFeedback", (PyCFunction)OscLoop_setFeedback, METH_O, "Sets oscillator feedback."},
    {"setMul", (PyCFunction)OscLoop_setMul, METH_O, "Sets oscillator mul factor."},
    {"setAdd", (PyCFunction)OscLoop_setAdd, METH_O, "Sets oscillator add factor."},
    {"setSub", (PyCFunction)OscLoop_setSub, METH_O, "Sets oscillator inverse add factor."},
    {"setDiv", (PyCFunction)OscLoop_setDiv, METH_O, "Sets inverse mul factor."},
    {NULL}  /* Sentinel */
};

static PyNumberMethods OscLoop_as_number =
{
    (binaryfunc)OscLoop_add,                      /*nb_add*/
    (binaryfunc)OscLoop_sub,                 /*nb_subtract*/
    (binaryfunc)OscLoop_multiply,                 /*nb_multiply*/
    0,                /*nb_remainder*/
    0,                   /*nb_divmod*/
    0,                   /*nb_power*/
    0,                  /*nb_neg*/
    0,                /*nb_pos*/
    0,                  /*(unaryfunc)array_abs,*/
    0,                    /*nb_nonzero*/
    0,                    /*nb_invert*/
    0,               /*nb_lshift*/
    0,              /*nb_rshift*/
    0,              /*nb_and*/
    0,              /*nb_xor*/
    0,               /*nb_or*/
    0,                       /*nb_int*/
    0,                      /*nb_long*/
    0,                     /*nb_float*/
    (binaryfunc)OscLoop_inplace_add,              /*inplace_add*/
    (binaryfunc)OscLoop_inplace_sub,         /*inplace_subtract*/
    (binaryfunc)OscLoop_inplace_multiply,         /*inplace_multiply*/
    0,        /*inplace_remainder*/
    0,           /*inplace_power*/
    0,       /*inplace_lshift*/
    0,      /*inplace_rshift*/
    0,      /*inplace_and*/
    0,      /*inplace_xor*/
    0,       /*inplace_or*/
    0,             /*nb_floor_divide*/
    (binaryfunc)OscLoop_div,                       /*nb_true_divide*/
    0,     /*nb_inplace_floor_divide*/
    (binaryfunc)OscLoop_inplace_div,                       /*nb_inplace_true_divide*/
    0,                     /* nb_index */
};

PyTypeObject OscLoopType =
{
    PyVarObject_HEAD_INIT(NULL, 0)
    "_pyo.OscLoop_base",         /*tp_name*/
    sizeof(OscLoop),         /*tp_basicsize*/
    0,                         /*tp_itemsize*/
    (destructor)OscLoop_dealloc, /*tp_dealloc*/
    0,                         /*tp_print*/
    0,                         /*tp_getattr*/
    0,                         /*tp_setattr*/
    0,                         /*tp_as_async (tp_compare in Python 2)*/
    0,                         /*tp_repr*/
    &OscLoop_as_number,             /*tp_as_number*/
    0,                         /*tp_as_sequence*/
    0,                         /*tp_as_mapping*/
    0,                         /*tp_hash */
    0,                         /*tp_call*/
    0,                         /*tp_str*/
    0,                         /*tp_getattro*/
    0,                         /*tp_setattro*/
    0,                         /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
    "OscLoop objects. Generates an oscillatory waveform.",           /* tp_doc */
    (traverseproc)OscLoop_traverse,   /* tp_traverse */
    (inquiry)OscLoop_clear,           /* tp_clear */
    0,                     /* tp_richcompare */
    0,                     /* tp_weaklistoffset */
    0,                     /* tp_iter */
    0,                     /* tp_iternext */
    OscLoop_methods,             /* tp_methods */
    OscLoop_members,             /* tp_members */
    0,                      /* tp_getset */
    0,                         /* tp_base */
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    0,                         /* tp_dictoffset */
    0,      /* tp_init */
    0,                         /* tp_alloc */
    OscLoop_new,                 /* tp_new */
};

typedef struct
{
    pyo_audio_HEAD
    PyObject *table;
    PyObject *freq;
    Stream *freq_stream;
    PyObject *phase;
    Stream *phase_stream;
    PyObject *trig;
    Stream *trig_stream;
    int modebuffer[4];
    double pointerPos;
    int interp; /* 0 = default to 2, 1 = nointerp, 2 = linear, 3 = cos, 4 = cubic */
    MYFLT (*interp_func_ptr)(MYFLT *, T_SIZE_T, MYFLT, T_SIZE_T);
} OscTrig;

static void
OscTrig_readframes_ii(OscTrig *self)
{
    int i;
    MYFLT fr, ph, fpart;
    double inc, pos;
    T_SIZE_T ipart;
    MYFLT *tablelist = TableStream_getData((TableStream *)self->table);
    T_SIZE_T size = TableStream_getSize((TableStream *)self->table);

    fr = PyFloat_AS_DOUBLE(self->freq);
    ph = PyFloat_AS_DOUBLE(self->phase);
    MYFLT *tr = Stream_getData((Stream *)self->trig_stream);
    inc = fr * size / self->sr;

    ph *= size;

    for (i = 0; i < self->bufsize; i++)
    {
        if (tr[i] == 1)
            self->pointerPos = 0.0;
        else
        {
            self->pointerPos += inc;
            self->pointerPos = Osc_clip(self->pointerPos, size);
        }

        pos = self->pointerPos + ph;

        if (pos >= size)
            pos -= size;

        ipart = (T_SIZE_T)pos;
        fpart = pos - ipart;
        self->data[i] = (*self->interp_func_ptr)(tablelist, ipart, fpart, size);
    }
}

static void
OscTrig_readframes_ai(OscTrig *self)
{
    int i;
    MYFLT ph, fpart, sizeOnSr;
    double inc, pos;
    T_SIZE_T ipart;
    MYFLT *tablelist = TableStream_getData((TableStream *)self->table);
    T_SIZE_T size = TableStream_getSize((TableStream *)self->table);

    MYFLT *fr = Stream_getData((Stream *)self->freq_stream);
    ph = PyFloat_AS_DOUBLE(self->phase);
    MYFLT *tr = Stream_getData((Stream *)self->trig_stream);
    ph *= size;

    sizeOnSr = size / self->sr;

    for (i = 0; i < self->bufsize; i++)
    {
        inc = fr[i] * sizeOnSr;

        if (tr[i] == 1)
            self->pointerPos = 0.0;
        else
        {
            self->pointerPos += inc;
            self->pointerPos = Osc_clip(self->pointerPos, size);
        }

        pos = self->pointerPos + ph;

        if (pos >= size)
            pos -= size;

        ipart = (T_SIZE_T)pos;
        fpart = pos - ipart;
        self->data[i] = (*self->interp_func_ptr)(tablelist, ipart, fpart, size);
    }
}

static void
OscTrig_readframes_ia(OscTrig *self)
{
    int i;
    MYFLT fr, pha, fpart;
    double inc, pos;
    T_SIZE_T ipart;
    MYFLT *tablelist = TableStream_getData((TableStream *)self->table);
    T_SIZE_T size = TableStream_getSize((TableStream *)self->table);

    fr = PyFloat_AS_DOUBLE(self->freq);
    MYFLT *ph = Stream_getData((Stream *)self->phase_stream);
    MYFLT *tr = Stream_getData((Stream *)self->trig_stream);
    inc = fr * size / self->sr;

    for (i = 0; i < self->bufsize; i++)
    {
        pha = ph[i] * size;

        if (tr[i] == 1)
            self->pointerPos = 0.0;
        else
        {
            self->pointerPos += inc;
            self->pointerPos = Osc_clip(self->pointerPos, size);
        }

        pos = self->pointerPos + pha;

        if (pos >= size)
            pos -= size;

        ipart = (T_SIZE_T)pos;
        fpart = pos - ipart;
        self->data[i] = (*self->interp_func_ptr)(tablelist, ipart, fpart, size);
    }
}

static void
OscTrig_readframes_aa(OscTrig *self)
{
    int i;
    MYFLT pha, fpart, sizeOnSr;
    double inc, pos;
    T_SIZE_T ipart;
    MYFLT *tablelist = TableStream_getData((TableStream *)self->table);
    T_SIZE_T size = TableStream_getSize((TableStream *)self->table);

    MYFLT *fr = Stream_getData((Stream *)self->freq_stream);
    MYFLT *ph = Stream_getData((Stream *)self->phase_stream);
    MYFLT *tr = Stream_getData((Stream *)self->trig_stream);

    sizeOnSr = size / self->sr;

    for (i = 0; i < self->bufsize; i++)
    {
        inc = fr[i] * sizeOnSr;
        pha = ph[i] * size;

        if (tr[i] == 1)
            self->pointerPos = 0.0;
        else
        {
            self->pointerPos += inc;
            self->pointerPos = Osc_clip(self->pointerPos, size);
        }

        pos = self->pointerPos + pha;

        if (pos >= size)
            pos -= size;

        ipart = (T_SIZE_T)pos;
        fpart = pos - ipart;
        self->data[i] = (*self->interp_func_ptr)(tablelist, ipart, fpart, size);
    }
}

static void OscTrig_postprocessing_ii(OscTrig *self) { POST_PROCESSING_II };
static void OscTrig_postprocessing_ai(OscTrig *self) { POST_PROCESSING_AI };
static void OscTrig_postprocessing_ia(OscTrig *self) { POST_PROCESSING_IA };
static void OscTrig_postprocessing_aa(OscTrig *self) { POST_PROCESSING_AA };
static void OscTrig_postprocessing_ireva(OscTrig *self) { POST_PROCESSING_IREVA };
static void OscTrig_postprocessing_areva(OscTrig *self) { POST_PROCESSING_AREVA };
static void OscTrig_postprocessing_revai(OscTrig *self) { POST_PROCESSING_REVAI };
static void OscTrig_postprocessing_revaa(OscTrig *self) { POST_PROCESSING_REVAA };
static void OscTrig_postprocessing_revareva(OscTrig *self) { POST_PROCESSING_REVAREVA };

static void
OscTrig_setProcMode(OscTrig *self)
{
    int procmode, muladdmode;
    procmode = self->modebuffer[2] + self->modebuffer[3] * 10;
    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;

    switch (procmode)
    {
        case 0:
            self->proc_func_ptr = OscTrig_readframes_ii;
            break;

        case 1:
            self->proc_func_ptr = OscTrig_readframes_ai;
            break;

        case 10:
            self->proc_func_ptr = OscTrig_readframes_ia;
            break;

        case 11:
            self->proc_func_ptr = OscTrig_readframes_aa;
            break;
    }

    switch (muladdmode)
    {
        case 0:
            self->muladd_func_ptr = OscTrig_postprocessing_ii;
            break;

        case 1:
            self->muladd_func_ptr = OscTrig_postprocessing_ai;
            break;

        case 2:
            self->muladd_func_ptr = OscTrig_postprocessing_revai;
            break;

        case 10:
            self->muladd_func_ptr = OscTrig_postprocessing_ia;
            break;

        case 11:
            self->muladd_func_ptr = OscTrig_postprocessing_aa;
            break;

        case 12:
            self->muladd_func_ptr = OscTrig_postprocessing_revaa;
            break;

        case 20:
            self->muladd_func_ptr = OscTrig_postprocessing_ireva;
            break;

        case 21:
            self->muladd_func_ptr = OscTrig_postprocessing_areva;
            break;

        case 22:
            self->muladd_func_ptr = OscTrig_postprocessing_revareva;
            break;
    }
}

static void
OscTrig_compute_next_data_frame(OscTrig *self)
{
    (*self->proc_func_ptr)(self);
    (*self->muladd_func_ptr)(self);
}

static int
OscTrig_traverse(OscTrig *self, visitproc visit, void *arg)
{
    pyo_VISIT
    Py_VISIT(self->phase);
    Py_VISIT(self->freq);
    Py_VISIT(self->trig);
    return 0;
}

static int
OscTrig_clear(OscTrig *self)
{
    pyo_CLEAR
    Py_CLEAR(self->phase);
    Py_CLEAR(self->freq);
    Py_CLEAR(self->trig);
    return 0;
}

static void
OscTrig_dealloc(OscTrig* self)
{
    pyo_DEALLOC
    OscTrig_clear(self);
    Py_TYPE(self->stream)->tp_free((PyObject*)self->stream);
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject *
OscTrig_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    int i;
    PyObject *tabletmp, *trigtmp, *freqtmp = NULL, *phasetmp = NULL, *multmp = NULL, *addtmp = NULL;
    OscTrig *self;
    self = (OscTrig *)type->tp_alloc(type, 0);

    self->trig = PyFloat_FromDouble(0.0);
    self->freq = PyFloat_FromDouble(1000);
    self->phase = PyFloat_FromDouble(0);
    self->modebuffer[0] = 0;
    self->modebuffer[1] = 0;
    self->modebuffer[2] = 0;
    self->modebuffer[3] = 0;
    self->pointerPos = 0.;
    self->interp = 2;

    INIT_OBJECT_COMMON
    Stream_setFunctionPtr(self->stream, OscTrig_compute_next_data_frame);
    self->mode_func_ptr = OscTrig_setProcMode;

    static char *kwlist[] = {"table", "trig", "freq", "phase", "interp", "mul", "add", NULL};

    if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OOiOO", kwlist, &tabletmp, &trigtmp, &freqtmp, &phasetmp, &self->interp, &multmp, &addtmp))
        Py_RETURN_NONE;

    if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 )
    {
        PyErr_SetString(PyExc_TypeError, "\"table\" argument of OscTrig must be a PyoTableObject.\n");
        Py_RETURN_NONE;
    }

    self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");

    if (trigtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setTrig", "O", trigtmp);
    }

    if (phasetmp)
    {
        PyObject_CallMethod((PyObject *)self, "setPhase", "O", phasetmp);
    }

    if (freqtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setFreq", "O", freqtmp);
    }

    if (multmp)
    {
        PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
    }

    if (addtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
    }

    PyObject_CallMethod(self->server, "addStream", "O", self->stream);

    (*self->mode_func_ptr)(self);

    SET_INTERP_POINTER

    return (PyObject *)self;
}

static PyObject * OscTrig_getServer(OscTrig* self) { GET_SERVER };
static PyObject * OscTrig_getStream(OscTrig* self) { GET_STREAM };
static PyObject * OscTrig_setMul(OscTrig *self, PyObject *arg) { SET_MUL };
static PyObject * OscTrig_setAdd(OscTrig *self, PyObject *arg) { SET_ADD };
static PyObject * OscTrig_setSub(OscTrig *self, PyObject *arg) { SET_SUB };
static PyObject * OscTrig_setDiv(OscTrig *self, PyObject *arg) { SET_DIV };

static PyObject * OscTrig_play(OscTrig *self, PyObject *args, PyObject *kwds) { PLAY };
static PyObject * OscTrig_out(OscTrig *self, PyObject *args, PyObject *kwds) { OUT };
static PyObject * OscTrig_stop(OscTrig *self, PyObject *args, PyObject *kwds) { STOP };

static PyObject * OscTrig_multiply(OscTrig *self, PyObject *arg) { MULTIPLY };
static PyObject * OscTrig_inplace_multiply(OscTrig *self, PyObject *arg) { INPLACE_MULTIPLY };
static PyObject * OscTrig_add(OscTrig *self, PyObject *arg) { ADD };
static PyObject * OscTrig_inplace_add(OscTrig *self, PyObject *arg) { INPLACE_ADD };
static PyObject * OscTrig_sub(OscTrig *self, PyObject *arg) { SUB };
static PyObject * OscTrig_inplace_sub(OscTrig *self, PyObject *arg) { INPLACE_SUB };
static PyObject * OscTrig_div(OscTrig *self, PyObject *arg) { DIV };
static PyObject * OscTrig_inplace_div(OscTrig *self, PyObject *arg) { INPLACE_DIV };

static PyObject *
OscTrig_getTable(OscTrig* self)
{
    Py_INCREF(self->table);
    return self->table;
};

static PyObject *
OscTrig_setTable(OscTrig *self, PyObject *arg)
{
    ASSERT_ARG_NOT_NULL

    Py_DECREF(self->table);
    self->table = PyObject_CallMethod((PyObject *)arg, "getTableStream", "");

    Py_RETURN_NONE;
}

static PyObject *
OscTrig_setTrig(OscTrig *self, PyObject *arg)
{
    ASSERT_ARG_NOT_NULL

    if (PyObject_HasAttrString((PyObject *)arg, "server") == 0)
    {
        PyErr_SetString(PyExc_TypeError, "\"trig\" attribute of OscTrig must be a PyoObject.\n");
        Py_RETURN_NONE;
    }

    Py_DECREF(self->trig);

    self->trig = arg;
    Py_INCREF(self->trig);
    PyObject *streamtmp = PyObject_CallMethod((PyObject *)self->trig, "_getStream", NULL);
    self->trig_stream = (Stream *)streamtmp;
    Py_INCREF(self->trig_stream);

    Py_RETURN_NONE;
}

static PyObject * OscTrig_setFreq(OscTrig *self, PyObject *arg) { SET_PARAM(self->freq, self->freq_stream, 2); }
static PyObject * OscTrig_setPhase(OscTrig *self, PyObject *arg) { SET_PARAM(self->phase, self->phase_stream, 3); }

static PyObject *
OscTrig_setInterp(OscTrig *self, PyObject *arg)
{
    ASSERT_ARG_NOT_NULL

    if (PyNumber_Check(arg))
    {
        self->interp = PyLong_AsLong(PyNumber_Long(arg));
    }

    SET_INTERP_POINTER

    Py_RETURN_NONE;
}

static PyObject *
OscTrig_reset(OscTrig *self)
{
    self->pointerPos = 0.0;
    Py_RETURN_NONE;
}

static PyMemberDef OscTrig_members[] =
{
    {"server", T_OBJECT_EX, offsetof(OscTrig, server), 0, "Pyo server."},
    {"stream", T_OBJECT_EX, offsetof(OscTrig, stream), 0, "Stream object."},
    {"table", T_OBJECT_EX, offsetof(OscTrig, table), 0, "Waveform table."},
    {"trig", T_OBJECT_EX, offsetof(OscTrig, trig), 0, "Trigger signal."},
    {"freq", T_OBJECT_EX, offsetof(OscTrig, freq), 0, "Frequency in cycle per second."},
    {"phase", T_OBJECT_EX, offsetof(OscTrig, phase), 0, "OscTrigillator phase."},
    {"mul", T_OBJECT_EX, offsetof(OscTrig, mul), 0, "Mul factor."},
    {"add", T_OBJECT_EX, offsetof(OscTrig, add), 0, "Add factor."},
    {NULL}  /* Sentinel */
};

static PyMethodDef OscTrig_methods[] =
{
    {"getTable", (PyCFunction)OscTrig_getTable, METH_NOARGS, "Returns waveform table object."},
    {"getServer", (PyCFunction)OscTrig_getServer, METH_NOARGS, "Returns server object."},
    {"_getStream", (PyCFunction)OscTrig_getStream, METH_NOARGS, "Returns stream object."},
    {"play", (PyCFunction)OscTrig_play, METH_VARARGS | METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
    {"out", (PyCFunction)OscTrig_out, METH_VARARGS | METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
    {"stop", (PyCFunction)OscTrig_stop, METH_VARARGS | METH_KEYWORDS, "Stops computing."},
    {"setTable", (PyCFunction)OscTrig_setTable, METH_O, "Sets oscillator table."},
    {"setTrig", (PyCFunction)OscTrig_setTrig, METH_O, "Sets the reset trigger signal."},
    {"setFreq", (PyCFunction)OscTrig_setFreq, METH_O, "Sets oscillator frequency in cycle per second."},
    {"setPhase", (PyCFunction)OscTrig_setPhase, METH_O, "Sets oscillator phase."},
    {"setInterp", (PyCFunction)OscTrig_setInterp, METH_O, "Sets oscillator interpolation mode."},
    {"reset", (PyCFunction)OscTrig_reset, METH_NOARGS, "Resets pointer position to 0."},
    {"setMul", (PyCFunction)OscTrig_setMul, METH_O, "Sets oscillator mul factor."},
    {"setAdd", (PyCFunction)OscTrig_setAdd, METH_O, "Sets oscillator add factor."},
    {"setSub", (PyCFunction)OscTrig_setSub, METH_O, "Sets oscillator inverse add factor."},
    {"setDiv", (PyCFunction)OscTrig_setDiv, METH_O, "Sets inverse mul factor."},
    {NULL}  /* Sentinel */
};

static PyNumberMethods OscTrig_as_number =
{
    (binaryfunc)OscTrig_add,                      /*nb_add*/
    (binaryfunc)OscTrig_sub,                 /*nb_subtract*/
    (binaryfunc)OscTrig_multiply,                 /*nb_multiply*/
    0,                /*nb_remainder*/
    0,                   /*nb_divmod*/
    0,                   /*nb_power*/
    0,                  /*nb_neg*/
    0,                /*nb_pos*/
    0,                  /*(unaryfunc)array_abs,*/
    0,                    /*nb_nonzero*/
    0,                    /*nb_invert*/
    0,               /*nb_lshift*/
    0,              /*nb_rshift*/
    0,              /*nb_and*/
    0,              /*nb_xor*/
    0,               /*nb_or*/
    0,                       /*nb_int*/
    0,                      /*nb_long*/
    0,                     /*nb_float*/
    (binaryfunc)OscTrig_inplace_add,              /*inplace_add*/
    (binaryfunc)OscTrig_inplace_sub,         /*inplace_subtract*/
    (binaryfunc)OscTrig_inplace_multiply,         /*inplace_multiply*/
    0,        /*inplace_remainder*/
    0,           /*inplace_power*/
    0,       /*inplace_lshift*/
    0,      /*inplace_rshift*/
    0,      /*inplace_and*/
    0,      /*inplace_xor*/
    0,       /*inplace_or*/
    0,             /*nb_floor_divide*/
    (binaryfunc)OscTrig_div,                       /*nb_true_divide*/
    0,     /*nb_inplace_floor_divide*/
    (binaryfunc)OscTrig_inplace_div,                       /*nb_inplace_true_divide*/
    0,                     /* nb_index */
};

PyTypeObject OscTrigType =
{
    PyVarObject_HEAD_INIT(NULL, 0)
    "_pyo.OscTrig_base",         /*tp_name*/
    sizeof(OscTrig),         /*tp_basicsize*/
    0,                         /*tp_itemsize*/
    (destructor)OscTrig_dealloc, /*tp_dealloc*/
    0,                         /*tp_print*/
    0,                         /*tp_getattr*/
    0,                         /*tp_setattr*/
    0,                         /*tp_as_async (tp_compare in Python 2)*/
    0,                         /*tp_repr*/
    &OscTrig_as_number,             /*tp_as_number*/
    0,                         /*tp_as_sequence*/
    0,                         /*tp_as_mapping*/
    0,                         /*tp_hash */
    0,                         /*tp_call*/
    0,                         /*tp_str*/
    0,                         /*tp_getattro*/
    0,                         /*tp_setattro*/
    0,                         /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
    "OscTrig objects. Generates an oscillatory waveform with sample accurate reset signal.",           /* tp_doc */
    (traverseproc)OscTrig_traverse,   /* tp_traverse */
    (inquiry)OscTrig_clear,           /* tp_clear */
    0,                     /* tp_richcompare */
    0,                     /* tp_weaklistoffset */
    0,                     /* tp_iter */
    0,                     /* tp_iternext */
    OscTrig_methods,             /* tp_methods */
    OscTrig_members,             /* tp_members */
    0,                      /* tp_getset */
    0,                         /* tp_base */
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    0,                         /* tp_dictoffset */
    0,      /* tp_init */
    0,                         /* tp_alloc */
    OscTrig_new,                 /* tp_new */
};

/**************/
/* Phasor object */
/**************/
typedef struct
{
    pyo_audio_HEAD
    PyObject *freq;
    Stream *freq_stream;
    PyObject *phase;
    Stream *phase_stream;
    int modebuffer[4];
    double pointerPos;
} Phasor;

static void
Phasor_readframes_ii(Phasor *self)
{
    MYFLT fr, ph;
    double inc, pos;
    int i;

    fr = PyFloat_AS_DOUBLE(self->freq);
    ph = _clip(PyFloat_AS_DOUBLE(self->phase));
    inc = fr / self->sr;

    for (i = 0; i < self->bufsize; i++)
    {
        pos = self->pointerPos + ph;

        if (pos > 1)
            pos -= 1.0;

        self->data[i] = pos;

        self->pointerPos += inc;

        if (self->pointerPos < 0)
            self->pointerPos += 1.0;
        else if (self->pointerPos >= 1)
            self->pointerPos -= 1.0;
    }
}

static void
Phasor_readframes_ai(Phasor *self)
{
    MYFLT ph, oneOnSr;
    double inc, pos;
    int i;

    MYFLT *fr = Stream_getData((Stream *)self->freq_stream);
    ph = _clip(PyFloat_AS_DOUBLE(self->phase));

    oneOnSr = 1.0 / self->sr;

    for (i = 0; i < self->bufsize; i++)
    {
        pos = self->pointerPos + ph;

        if (pos > 1)
            pos -= 1.0;

        self->data[i] = pos;

        inc = fr[i] * oneOnSr;
        self->pointerPos += inc;

        if (self->pointerPos < 0)
            self->pointerPos += 1.0;
        else if (self->pointerPos >= 1)
            self->pointerPos -= 1.0;
    }
}

static void
Phasor_readframes_ia(Phasor *self)
{
    MYFLT fr, pha;
    double inc, pos;
    int i;

    fr = PyFloat_AS_DOUBLE(self->freq);
    MYFLT *ph = Stream_getData((Stream *)self->phase_stream);

    inc = fr / self->sr;

    for (i = 0; i < self->bufsize; i++)
    {
        pha = _clip(ph[i]);

        pos = self->pointerPos + pha;

        if (pos > 1)
            pos -= 1.0;

        self->data[i] = pos;

        self->pointerPos += inc;

        if (self->pointerPos < 0)
            self->pointerPos += 1.0;
        else if (self->pointerPos >= 1)
            self->pointerPos -= 1.0;
    }
}

static void
Phasor_readframes_aa(Phasor *self)
{
    MYFLT pha, oneOnSr;
    double inc, pos;
    int i;

    MYFLT *fr = Stream_getData((Stream *)self->freq_stream);
    MYFLT *ph = Stream_getData((Stream *)self->phase_stream);

    oneOnSr = 1.0 / self->sr;

    for (i = 0; i < self->bufsize; i++)
    {
        pha = _clip(ph[i]);

        pos = self->pointerPos + pha;

        if (pos > 1)
            pos -= 1.0;

        self->data[i] = pos;

        inc = fr[i] * oneOnSr;
        self->pointerPos += inc;

        if (self->pointerPos < 0)
            self->pointerPos += 1.0;
        else if (self->pointerPos >= 1)
            self->pointerPos -= 1.0;
    }
}

static void Phasor_postprocessing_ii(Phasor *self) { POST_PROCESSING_II };
static void Phasor_postprocessing_ai(Phasor *self) { POST_PROCESSING_AI };
static void Phasor_postprocessing_ia(Phasor *self) { POST_PROCESSING_IA };
static void Phasor_postprocessing_aa(Phasor *self) { POST_PROCESSING_AA };
static void Phasor_postprocessing_ireva(Phasor *self) { POST_PROCESSING_IREVA };
static void Phasor_postprocessing_areva(Phasor *self) { POST_PROCESSING_AREVA };
static void Phasor_postprocessing_revai(Phasor *self) { POST_PROCESSING_REVAI };
static void Phasor_postprocessing_revaa(Phasor *self) { POST_PROCESSING_REVAA };
static void Phasor_postprocessing_revareva(Phasor *self) { POST_PROCESSING_REVAREVA };

static void
Phasor_setProcMode(Phasor *self)
{
    int procmode, muladdmode;
    procmode = self->modebuffer[2] + self->modebuffer[3] * 10;
    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;

    switch (procmode)
    {
        case 0:
            self->proc_func_ptr = Phasor_readframes_ii;
            break;

        case 1:
            self->proc_func_ptr = Phasor_readframes_ai;
            break;

        case 10:
            self->proc_func_ptr = Phasor_readframes_ia;
            break;

        case 11:
            self->proc_func_ptr = Phasor_readframes_aa;
            break;
    }

    switch (muladdmode)
    {
        case 0:
            self->muladd_func_ptr = Phasor_postprocessing_ii;
            break;

        case 1:
            self->muladd_func_ptr = Phasor_postprocessing_ai;
            break;

        case 2:
            self->muladd_func_ptr = Phasor_postprocessing_revai;
            break;

        case 10:
            self->muladd_func_ptr = Phasor_postprocessing_ia;
            break;

        case 11:
            self->muladd_func_ptr = Phasor_postprocessing_aa;
            break;

        case 12:
            self->muladd_func_ptr = Phasor_postprocessing_revaa;
            break;

        case 20:
            self->muladd_func_ptr = Phasor_postprocessing_ireva;
            break;

        case 21:
            self->muladd_func_ptr = Phasor_postprocessing_areva;
            break;

        case 22:
            self->muladd_func_ptr = Phasor_postprocessing_revareva;
            break;
    }
}

static void
Phasor_compute_next_data_frame(Phasor *self)
{
    (*self->proc_func_ptr)(self);
    (*self->muladd_func_ptr)(self);
}

static int
Phasor_traverse(Phasor *self, visitproc visit, void *arg)
{
    pyo_VISIT
    Py_VISIT(self->phase);
    Py_VISIT(self->freq);
    return 0;
}

static int
Phasor_clear(Phasor *self)
{
    pyo_CLEAR
    Py_CLEAR(self->phase);
    Py_CLEAR(self->freq);
    return 0;
}

static void
Phasor_dealloc(Phasor* self)
{
    pyo_DEALLOC
    Phasor_clear(self);
    Py_TYPE(self->stream)->tp_free((PyObject*)self->stream);
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject *
Phasor_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    int i;
    PyObject *freqtmp = NULL, *phasetmp = NULL, *multmp = NULL, *addtmp = NULL;
    Phasor *self;
    self = (Phasor *)type->tp_alloc(type, 0);

    self->freq = PyFloat_FromDouble(100);
    self->phase = PyFloat_FromDouble(0);
    self->modebuffer[0] = 0;
    self->modebuffer[1] = 0;
    self->modebuffer[2] = 0;
    self->modebuffer[3] = 0;
    self->pointerPos = 0.;

    INIT_OBJECT_COMMON
    Stream_setFunctionPtr(self->stream, Phasor_compute_next_data_frame);
    self->mode_func_ptr = Phasor_setProcMode;

    static char *kwlist[] = {"freq", "phase", "mul", "add", NULL};

    if (! PyArg_ParseTupleAndKeywords(args, kwds, "|OOOO", kwlist, &freqtmp, &phasetmp, &multmp, &addtmp))
        Py_RETURN_NONE;

    if (freqtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setFreq", "O", freqtmp);
    }

    if (phasetmp)
    {
        PyObject_CallMethod((PyObject *)self, "setPhase", "O", phasetmp);
    }

    if (multmp)
    {
        PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
    }

    if (addtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
    }

    PyObject_CallMethod(self->server, "addStream", "O", self->stream);

    (*self->mode_func_ptr)(self);

    return (PyObject *)self;
}

static PyObject * Phasor_getServer(Phasor* self) { GET_SERVER };
static PyObject * Phasor_getStream(Phasor* self) { GET_STREAM };
static PyObject * Phasor_setMul(Phasor *self, PyObject *arg) { SET_MUL };
static PyObject * Phasor_setAdd(Phasor *self, PyObject *arg) { SET_ADD };
static PyObject * Phasor_setSub(Phasor *self, PyObject *arg) { SET_SUB };
static PyObject * Phasor_setDiv(Phasor *self, PyObject *arg) { SET_DIV };

static PyObject * Phasor_play(Phasor *self, PyObject *args, PyObject *kwds) { PLAY };
static PyObject * Phasor_out(Phasor *self, PyObject *args, PyObject *kwds) { OUT };
static PyObject * Phasor_stop(Phasor *self, PyObject *args, PyObject *kwds) { STOP };

static PyObject * Phasor_multiply(Phasor *self, PyObject *arg) { MULTIPLY };
static PyObject * Phasor_inplace_multiply(Phasor *self, PyObject *arg) { INPLACE_MULTIPLY };
static PyObject * Phasor_add(Phasor *self, PyObject *arg) { ADD };
static PyObject * Phasor_inplace_add(Phasor *self, PyObject *arg) { INPLACE_ADD };
static PyObject * Phasor_sub(Phasor *self, PyObject *arg) { SUB };
static PyObject * Phasor_inplace_sub(Phasor *self, PyObject *arg) { INPLACE_SUB };
static PyObject * Phasor_div(Phasor *self, PyObject *arg) { DIV };
static PyObject * Phasor_inplace_div(Phasor *self, PyObject *arg) { INPLACE_DIV };

static PyObject * Phasor_setFreq(Phasor *self, PyObject *arg) { SET_PARAM(self->freq, self->freq_stream, 2); }
static PyObject * Phasor_setPhase(Phasor *self, PyObject *arg) { SET_PARAM(self->phase, self->phase_stream, 3); }

static PyObject *
Phasor_reset(Phasor *self)
{
    self->pointerPos = 0.0;
    Py_RETURN_NONE;
}

static PyMemberDef Phasor_members[] =
{
    {"server", T_OBJECT_EX, offsetof(Phasor, server), 0, "Pyo server."},
    {"stream", T_OBJECT_EX, offsetof(Phasor, stream), 0, "Stream object."},
    {"freq", T_OBJECT_EX, offsetof(Phasor, freq), 0, "Frequency in cycle per second."},
    {"phase", T_OBJECT_EX, offsetof(Phasor, phase), 0, "Phasorillator phase."},
    {"mul", T_OBJECT_EX, offsetof(Phasor, mul), 0, "Mul factor."},
    {"add", T_OBJECT_EX, offsetof(Phasor, add), 0, "Add factor."},
    {NULL}  /* Sentinel */
};

static PyMethodDef Phasor_methods[] =
{
    {"getServer", (PyCFunction)Phasor_getServer, METH_NOARGS, "Returns server object."},
    {"_getStream", (PyCFunction)Phasor_getStream, METH_NOARGS, "Returns stream object."},
    {"play", (PyCFunction)Phasor_play, METH_VARARGS | METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
    {"out", (PyCFunction)Phasor_out, METH_VARARGS | METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
    {"stop", (PyCFunction)Phasor_stop, METH_VARARGS | METH_KEYWORDS, "Stops computing."},
    {"setFreq", (PyCFunction)Phasor_setFreq, METH_O, "Sets oscillator frequency in cycle per second."},
    {"setPhase", (PyCFunction)Phasor_setPhase, METH_O, "Sets oscillator phase."},
    {"reset", (PyCFunction)Phasor_reset, METH_NOARGS, "Resets pointer position to 0."},
    {"setMul", (PyCFunction)Phasor_setMul, METH_O, "Sets oscillator mul factor."},
    {"setAdd", (PyCFunction)Phasor_setAdd, METH_O, "Sets oscillator add factor."},
    {"setSub", (PyCFunction)Phasor_setSub, METH_O, "Sets oscillator inverse add factor."},
    {"setDiv", (PyCFunction)Phasor_setDiv, METH_O, "Sets inverse mul factor."},
    {NULL}  /* Sentinel */
};

static PyNumberMethods Phasor_as_number =
{
    (binaryfunc)Phasor_add,                      /*nb_add*/
    (binaryfunc)Phasor_sub,                 /*nb_subtract*/
    (binaryfunc)Phasor_multiply,                 /*nb_multiply*/
    0,                /*nb_remainder*/
    0,                   /*nb_divmod*/
    0,                   /*nb_power*/
    0,                  /*nb_neg*/
    0,                /*nb_pos*/
    0,                  /*(unaryfunc)array_abs,*/
    0,                    /*nb_nonzero*/
    0,                    /*nb_invert*/
    0,               /*nb_lshift*/
    0,              /*nb_rshift*/
    0,              /*nb_and*/
    0,              /*nb_xor*/
    0,               /*nb_or*/
    0,                       /*nb_int*/
    0,                      /*nb_long*/
    0,                     /*nb_float*/
    (binaryfunc)Phasor_inplace_add,              /*inplace_add*/
    (binaryfunc)Phasor_inplace_sub,         /*inplace_subtract*/
    (binaryfunc)Phasor_inplace_multiply,         /*inplace_multiply*/
    0,        /*inplace_remainder*/
    0,           /*inplace_power*/
    0,       /*inplace_lshift*/
    0,      /*inplace_rshift*/
    0,      /*inplace_and*/
    0,      /*inplace_xor*/
    0,       /*inplace_or*/
    0,             /*nb_floor_divide*/
    (binaryfunc)Phasor_div,                       /*nb_true_divide*/
    0,     /*nb_inplace_floor_divide*/
    (binaryfunc)Phasor_inplace_div,                       /*nb_inplace_true_divide*/
    0,                     /* nb_index */
};

PyTypeObject PhasorType =
{
    PyVarObject_HEAD_INIT(NULL, 0)
    "_pyo.Phasor_base",         /*tp_name*/
    sizeof(Phasor),         /*tp_basicsize*/
    0,                         /*tp_itemsize*/
    (destructor)Phasor_dealloc, /*tp_dealloc*/
    0,                         /*tp_print*/
    0,                         /*tp_getattr*/
    0,                         /*tp_setattr*/
    0,                         /*tp_as_async (tp_compare in Python 2)*/
    0,                         /*tp_repr*/
    &Phasor_as_number,             /*tp_as_number*/
    0,                         /*tp_as_sequence*/
    0,                         /*tp_as_mapping*/
    0,                         /*tp_hash */
    0,                         /*tp_call*/
    0,                         /*tp_str*/
    0,                         /*tp_getattro*/
    0,                         /*tp_setattro*/
    0,                         /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
    "Phasor objects. Phase incrementor from 0 to 1.",           /* tp_doc */
    (traverseproc)Phasor_traverse,   /* tp_traverse */
    (inquiry)Phasor_clear,           /* tp_clear */
    0,                     /* tp_richcompare */
    0,                     /* tp_weaklistoffset */
    0,                     /* tp_iter */
    0,                     /* tp_iternext */
    Phasor_methods,             /* tp_methods */
    Phasor_members,             /* tp_members */
    0,                      /* tp_getset */
    0,                         /* tp_base */
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    0,                         /* tp_dictoffset */
    0,      /* tp_init */
    0,                         /* tp_alloc */
    Phasor_new,                 /* tp_new */
};

/**************/
/* Pointer object */
/**************/
typedef struct
{
    pyo_audio_HEAD
    PyObject *table;
    PyObject *index;
    Stream *index_stream;
    int modebuffer[2];
} Pointer;

static void
Pointer_readframes_a(Pointer *self)
{
    int i;
    MYFLT fpart;
    double ph;
    T_SIZE_T ipart;
    MYFLT *tablelist = TableStream_getData((TableStream *)self->table);
    T_SIZE_T size = TableStream_getSize((TableStream *)self->table);

    MYFLT *pha = Stream_getData((Stream *)self->index_stream);

    for (i = 0; i < self->bufsize; i++)
    {
        ph = Osc_clip(pha[i] * size, size);
        ipart = (T_SIZE_T)ph;
        fpart = ph - ipart;
        self->data[i] = tablelist[ipart] + (tablelist[ipart + 1] - tablelist[ipart]) * fpart;
    }
}

static void Pointer_postprocessing_ii(Pointer *self) { POST_PROCESSING_II };
static void Pointer_postprocessing_ai(Pointer *self) { POST_PROCESSING_AI };
static void Pointer_postprocessing_ia(Pointer *self) { POST_PROCESSING_IA };
static void Pointer_postprocessing_aa(Pointer *self) { POST_PROCESSING_AA };
static void Pointer_postprocessing_ireva(Pointer *self) { POST_PROCESSING_IREVA };
static void Pointer_postprocessing_areva(Pointer *self) { POST_PROCESSING_AREVA };
static void Pointer_postprocessing_revai(Pointer *self) { POST_PROCESSING_REVAI };
static void Pointer_postprocessing_revaa(Pointer *self) { POST_PROCESSING_REVAA };
static void Pointer_postprocessing_revareva(Pointer *self) { POST_PROCESSING_REVAREVA };

static void
Pointer_setProcMode(Pointer *self)
{
    int muladdmode;
    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;

    self->proc_func_ptr = Pointer_readframes_a;

    switch (muladdmode)
    {
        case 0:
            self->muladd_func_ptr = Pointer_postprocessing_ii;
            break;

        case 1:
            self->muladd_func_ptr = Pointer_postprocessing_ai;
            break;

        case 2:
            self->muladd_func_ptr = Pointer_postprocessing_revai;
            break;

        case 10:
            self->muladd_func_ptr = Pointer_postprocessing_ia;
            break;

        case 11:
            self->muladd_func_ptr = Pointer_postprocessing_aa;
            break;

        case 12:
            self->muladd_func_ptr = Pointer_postprocessing_revaa;
            break;

        case 20:
            self->muladd_func_ptr = Pointer_postprocessing_ireva;
            break;

        case 21:
            self->muladd_func_ptr = Pointer_postprocessing_areva;
            break;

        case 22:
            self->muladd_func_ptr = Pointer_postprocessing_revareva;
            break;
    }
}

static void
Pointer_compute_next_data_frame(Pointer *self)
{
    (*self->proc_func_ptr)(self);
    (*self->muladd_func_ptr)(self);
}

static int
Pointer_traverse(Pointer *self, visitproc visit, void *arg)
{
    pyo_VISIT
    Py_VISIT(self->index);
    return 0;
}

static int
Pointer_clear(Pointer *self)
{
    pyo_CLEAR
    Py_CLEAR(self->index);
    return 0;
}

static void
Pointer_dealloc(Pointer* self)
{
    pyo_DEALLOC
    Pointer_clear(self);
    Py_TYPE(self->stream)->tp_free((PyObject*)self->stream);
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject *
Pointer_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    int i;
    PyObject *tabletmp, *indextmp, *multmp = NULL, *addtmp = NULL;
    Pointer *self;
    self = (Pointer *)type->tp_alloc(type, 0);

    self->index = PyFloat_FromDouble(0.0);

    self->modebuffer[0] = 0;
    self->modebuffer[1] = 0;

    INIT_OBJECT_COMMON
    Stream_setFunctionPtr(self->stream, Pointer_compute_next_data_frame);
    self->mode_func_ptr = Pointer_setProcMode;

    static char *kwlist[] = {"table", "index", "mul", "add", NULL};

    if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO", kwlist, &tabletmp, &indextmp, &multmp, &addtmp))
        Py_RETURN_NONE;

    if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 )
    {
        PyErr_SetString(PyExc_TypeError, "\"table\" argument of Pointer must be a PyoTableObject.\n");
        Py_RETURN_NONE;
    }

    self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");

    if (indextmp)
    {
        PyObject_CallMethod((PyObject *)self, "setIndex", "O", indextmp);
    }

    if (multmp)
    {
        PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
    }

    if (addtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
    }

    PyObject_CallMethod(self->server, "addStream", "O", self->stream);

    (*self->mode_func_ptr)(self);

    return (PyObject *)self;
}

static PyObject * Pointer_getServer(Pointer* self) { GET_SERVER };
static PyObject * Pointer_getStream(Pointer* self) { GET_STREAM };
static PyObject * Pointer_setMul(Pointer *self, PyObject *arg) { SET_MUL };
static PyObject * Pointer_setAdd(Pointer *self, PyObject *arg) { SET_ADD };
static PyObject * Pointer_setSub(Pointer *self, PyObject *arg) { SET_SUB };
static PyObject * Pointer_setDiv(Pointer *self, PyObject *arg) { SET_DIV };

static PyObject * Pointer_play(Pointer *self, PyObject *args, PyObject *kwds) { PLAY };
static PyObject * Pointer_out(Pointer *self, PyObject *args, PyObject *kwds) { OUT };
static PyObject * Pointer_stop(Pointer *self, PyObject *args, PyObject *kwds) { STOP };

static PyObject * Pointer_multiply(Pointer *self, PyObject *arg) { MULTIPLY };
static PyObject * Pointer_inplace_multiply(Pointer *self, PyObject *arg) { INPLACE_MULTIPLY };
static PyObject * Pointer_add(Pointer *self, PyObject *arg) { ADD };
static PyObject * Pointer_inplace_add(Pointer *self, PyObject *arg) { INPLACE_ADD };
static PyObject * Pointer_sub(Pointer *self, PyObject *arg) { SUB };
static PyObject * Pointer_inplace_sub(Pointer *self, PyObject *arg) { INPLACE_SUB };
static PyObject * Pointer_div(Pointer *self, PyObject *arg) { DIV };
static PyObject * Pointer_inplace_div(Pointer *self, PyObject *arg) { INPLACE_DIV };

static PyObject *
Pointer_getTable(Pointer* self)
{
    Py_INCREF(self->table);
    return self->table;
};

static PyObject *
Pointer_setTable(Pointer *self, PyObject *arg)
{
    ASSERT_ARG_NOT_NULL

    Py_DECREF(self->table);
    self->table = PyObject_CallMethod((PyObject *)arg, "getTableStream", "");

    Py_RETURN_NONE;
}

static PyObject *
Pointer_setIndex(Pointer *self, PyObject *arg)
{
    ASSERT_ARG_NOT_NULL

    if (PyObject_HasAttrString((PyObject *)arg, "server") == 0)
    {
        PyErr_SetString(PyExc_TypeError, "\"index\" argument of Pointer must be a PyoObject.\n");
        Py_RETURN_NONE;
    }

    Py_DECREF(self->index);

    self->index = arg;
    Py_INCREF(self->index);
    PyObject *streamtmp = PyObject_CallMethod((PyObject *)self->index, "_getStream", NULL);
    self->index_stream = (Stream *)streamtmp;
    Py_INCREF(self->index_stream);

    Py_RETURN_NONE;
}

static PyMemberDef Pointer_members[] =
{
    {"server", T_OBJECT_EX, offsetof(Pointer, server), 0, "Pyo server."},
    {"stream", T_OBJECT_EX, offsetof(Pointer, stream), 0, "Stream object."},
    {"table", T_OBJECT_EX, offsetof(Pointer, table), 0, "Waveform table."},
    {"index", T_OBJECT_EX, offsetof(Pointer, index), 0, "Reader index."},
    {"mul", T_OBJECT_EX, offsetof(Pointer, mul), 0, "Mul factor."},
    {"add", T_OBJECT_EX, offsetof(Pointer, add), 0, "Add factor."},
    {NULL}  /* Sentinel */
};

static PyMethodDef Pointer_methods[] =
{
    {"getTable", (PyCFunction)Pointer_getTable, METH_NOARGS, "Returns waveform table object."},
    {"getServer", (PyCFunction)Pointer_getServer, METH_NOARGS, "Returns server object."},
    {"_getStream", (PyCFunction)Pointer_getStream, METH_NOARGS, "Returns stream object."},
    {"play", (PyCFunction)Pointer_play, METH_VARARGS | METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
    {"out", (PyCFunction)Pointer_out, METH_VARARGS | METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
    {"stop", (PyCFunction)Pointer_stop, METH_VARARGS | METH_KEYWORDS, "Stops computing."},
    {"setTable", (PyCFunction)Pointer_setTable, METH_O, "Sets oscillator table."},
    {"setIndex", (PyCFunction)Pointer_setIndex, METH_O, "Sets reader index."},
    {"setMul", (PyCFunction)Pointer_setMul, METH_O, "Sets oscillator mul factor."},
    {"setAdd", (PyCFunction)Pointer_setAdd, METH_O, "Sets oscillator add factor."},
    {"setSub", (PyCFunction)Pointer_setSub, METH_O, "Sets oscillator inverse add factor."},
    {"setDiv", (PyCFunction)Pointer_setDiv, METH_O, "Sets inverse mul factor."},
    {NULL}  /* Sentinel */
};

static PyNumberMethods Pointer_as_number =
{
    (binaryfunc)Pointer_add,                      /*nb_add*/
    (binaryfunc)Pointer_sub,                 /*nb_subtract*/
    (binaryfunc)Pointer_multiply,                 /*nb_multiply*/
    0,                /*nb_remainder*/
    0,                   /*nb_divmod*/
    0,                   /*nb_power*/
    0,                  /*nb_neg*/
    0,                /*nb_pos*/
    0,                  /*(unaryfunc)array_abs,*/
    0,                    /*nb_nonzero*/
    0,                    /*nb_invert*/
    0,               /*nb_lshift*/
    0,              /*nb_rshift*/
    0,              /*nb_and*/
    0,              /*nb_xor*/
    0,               /*nb_or*/
    0,                       /*nb_int*/
    0,                      /*nb_long*/
    0,                     /*nb_float*/
    (binaryfunc)Pointer_inplace_add,              /*inplace_add*/
    (binaryfunc)Pointer_inplace_sub,         /*inplace_subtract*/
    (binaryfunc)Pointer_inplace_multiply,         /*inplace_multiply*/
    0,        /*inplace_remainder*/
    0,           /*inplace_power*/
    0,       /*inplace_lshift*/
    0,      /*inplace_rshift*/
    0,      /*inplace_and*/
    0,      /*inplace_xor*/
    0,       /*inplace_or*/
    0,             /*nb_floor_divide*/
    (binaryfunc)Pointer_div,                       /*nb_true_divide*/
    0,     /*nb_inplace_floor_divide*/
    (binaryfunc)Pointer_inplace_div,                       /*nb_inplace_true_divide*/
    0,                     /* nb_index */
};

PyTypeObject PointerType =
{
    PyVarObject_HEAD_INIT(NULL, 0)
    "_pyo.Pointer_base",         /*tp_name*/
    sizeof(Pointer),         /*tp_basicsize*/
    0,                         /*tp_itemsize*/
    (destructor)Pointer_dealloc, /*tp_dealloc*/
    0,                         /*tp_print*/
    0,                         /*tp_getattr*/
    0,                         /*tp_setattr*/
    0,                         /*tp_as_async (tp_compare in Python 2)*/
    0,                         /*tp_repr*/
    &Pointer_as_number,             /*tp_as_number*/
    0,                         /*tp_as_sequence*/
    0,                         /*tp_as_mapping*/
    0,                         /*tp_hash */
    0,                         /*tp_call*/
    0,                         /*tp_str*/
    0,                         /*tp_getattro*/
    0,                         /*tp_setattro*/
    0,                         /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
    "Pointer objects. Read a waveform table with a pointer index.",           /* tp_doc */
    (traverseproc)Pointer_traverse,   /* tp_traverse */
    (inquiry)Pointer_clear,           /* tp_clear */
    0,                     /* tp_richcompare */
    0,                     /* tp_weaklistoffset */
    0,                     /* tp_iter */
    0,                     /* tp_iternext */
    Pointer_methods,             /* tp_methods */
    Pointer_members,             /* tp_members */
    0,                      /* tp_getset */
    0,                         /* tp_base */
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    0,                         /* tp_dictoffset */
    0,      /* tp_init */
    0,                         /* tp_alloc */
    Pointer_new,                 /* tp_new */
};

/**************/
/* Pointer2 object */
/**************/
typedef struct
{
    pyo_audio_HEAD
    PyObject *table;
    PyObject *index;
    Stream *index_stream;
    int modebuffer[2];
    int interp; /* 0 = default to 2, 1 = nointerp, 2 = linear, 3 = cos, 4 = cubic */
    int autosmooth; /* 0 = off, > 0 = on */
    MYFLT y1;
    MYFLT y2;
    MYFLT lastPh;
    MYFLT mTwoPiOverSr;
    MYFLT (*interp_func_ptr)(MYFLT *, T_SIZE_T, MYFLT, T_SIZE_T);
} Pointer2;

static void
Pointer2_readframes_a(Pointer2 *self)
{
    int i;
    MYFLT fpart, phdiff, c, fr;
    double ph;
    T_SIZE_T ipart;
    MYFLT *tablelist = TableStream_getData((TableStream *)self->table);
    T_SIZE_T size = TableStream_getSize((TableStream *)self->table);
    double tableSr = TableStream_getSamplingRate((TableStream *)self->table);

    MYFLT *pha = Stream_getData((Stream *)self->index_stream);

    if (!self->autosmooth)
    {
        for (i = 0; i < self->bufsize; i++)
        {
            ph = Osc_clip(pha[i] * size, size);
            ipart = (T_SIZE_T)ph;
            fpart = ph - ipart;
            self->y1 = self->y2 = self->data[i] = (*self->interp_func_ptr)(tablelist, ipart, fpart, size);
        }
    }
    else
    {
        for (i = 0; i < self->bufsize; i++)
        {
            ph = Osc_clip(pha[i] * size, size);
            ipart = (T_SIZE_T)ph;
            fpart = ph - ipart;
            self->data[i] = (*self->interp_func_ptr)(tablelist, ipart, fpart, size);
            phdiff = fabs(ph - self->lastPh);
            self->lastPh = ph;

            if (phdiff < 1)
            {
                fr = phdiff * tableSr * 0.45;
                c = MYEXP(self->mTwoPiOverSr * fr);
                self->y1 = self->data[i] + (self->y1 - self->data[i]) * c;
                self->data[i] = self->y2 = self->y1 + (self->y2 - self->y1) * c;
            }
            else
                self->y1 = self->y2 = self->data[i];
        }
    }
}

static void Pointer2_postprocessing_ii(Pointer2 *self) { POST_PROCESSING_II };
static void Pointer2_postprocessing_ai(Pointer2 *self) { POST_PROCESSING_AI };
static void Pointer2_postprocessing_ia(Pointer2 *self) { POST_PROCESSING_IA };
static void Pointer2_postprocessing_aa(Pointer2 *self) { POST_PROCESSING_AA };
static void Pointer2_postprocessing_ireva(Pointer2 *self) { POST_PROCESSING_IREVA };
static void Pointer2_postprocessing_areva(Pointer2 *self) { POST_PROCESSING_AREVA };
static void Pointer2_postprocessing_revai(Pointer2 *self) { POST_PROCESSING_REVAI };
static void Pointer2_postprocessing_revaa(Pointer2 *self) { POST_PROCESSING_REVAA };
static void Pointer2_postprocessing_revareva(Pointer2 *self) { POST_PROCESSING_REVAREVA };

static void
Pointer2_setProcMode(Pointer2 *self)
{
    int muladdmode;
    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;

    self->proc_func_ptr = Pointer2_readframes_a;

    switch (muladdmode)
    {
        case 0:
            self->muladd_func_ptr = Pointer2_postprocessing_ii;
            break;

        case 1:
            self->muladd_func_ptr = Pointer2_postprocessing_ai;
            break;

        case 2:
            self->muladd_func_ptr = Pointer2_postprocessing_revai;
            break;

        case 10:
            self->muladd_func_ptr = Pointer2_postprocessing_ia;
            break;

        case 11:
            self->muladd_func_ptr = Pointer2_postprocessing_aa;
            break;

        case 12:
            self->muladd_func_ptr = Pointer2_postprocessing_revaa;
            break;

        case 20:
            self->muladd_func_ptr = Pointer2_postprocessing_ireva;
            break;

        case 21:
            self->muladd_func_ptr = Pointer2_postprocessing_areva;
            break;

        case 22:
            self->muladd_func_ptr = Pointer2_postprocessing_revareva;
            break;
    }
}

static void
Pointer2_compute_next_data_frame(Pointer2 *self)
{
    (*self->proc_func_ptr)(self);
    (*self->muladd_func_ptr)(self);
}

static int
Pointer2_traverse(Pointer2 *self, visitproc visit, void *arg)
{
    pyo_VISIT
    Py_VISIT(self->index);
    return 0;
}

static int
Pointer2_clear(Pointer2 *self)
{
    pyo_CLEAR
    Py_CLEAR(self->index);
    return 0;
}

static void
Pointer2_dealloc(Pointer2* self)
{
    pyo_DEALLOC
    Pointer2_clear(self);
    Py_TYPE(self->stream)->tp_free((PyObject*)self->stream);
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject *
Pointer2_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    int i;
    PyObject *tabletmp, *indextmp, *multmp = NULL, *addtmp = NULL;
    Pointer2 *self;
    self = (Pointer2 *)type->tp_alloc(type, 0);

    self->index = PyFloat_FromDouble(0.0);

    self->modebuffer[0] = 0;
    self->modebuffer[1] = 0;
    self->interp = 4;
    self->autosmooth = 1;
    self->y1 = self->y2 = self->lastPh = 0.0;

    INIT_OBJECT_COMMON
    Stream_setFunctionPtr(self->stream, Pointer2_compute_next_data_frame);
    self->mode_func_ptr = Pointer2_setProcMode;

    self->mTwoPiOverSr = -TWOPI / self->sr;

    static char *kwlist[] = {"table", "index", "interp", "autosmooth", "mul", "add", NULL};

    if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|iiOO", kwlist, &tabletmp, &indextmp, &self->interp, &self->autosmooth, &multmp, &addtmp))
        Py_RETURN_NONE;

    if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 )
    {
        PyErr_SetString(PyExc_TypeError, "\"table\" argument of Pointer2 must be a PyoTableObject.\n");
        Py_RETURN_NONE;
    }

    self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");

    if (indextmp)
    {
        PyObject_CallMethod((PyObject *)self, "setIndex", "O", indextmp);
    }

    if (multmp)
    {
        PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
    }

    if (addtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
    }

    PyObject_CallMethod(self->server, "addStream", "O", self->stream);

    (*self->mode_func_ptr)(self);

    SET_INTERP_POINTER

    return (PyObject *)self;
}

static PyObject * Pointer2_getServer(Pointer2* self) { GET_SERVER };
static PyObject * Pointer2_getStream(Pointer2* self) { GET_STREAM };
static PyObject * Pointer2_setMul(Pointer2 *self, PyObject *arg) { SET_MUL };
static PyObject * Pointer2_setAdd(Pointer2 *self, PyObject *arg) { SET_ADD };
static PyObject * Pointer2_setSub(Pointer2 *self, PyObject *arg) { SET_SUB };
static PyObject * Pointer2_setDiv(Pointer2 *self, PyObject *arg) { SET_DIV };

static PyObject * Pointer2_play(Pointer2 *self, PyObject *args, PyObject *kwds) { PLAY };
static PyObject * Pointer2_out(Pointer2 *self, PyObject *args, PyObject *kwds) { OUT };
static PyObject * Pointer2_stop(Pointer2 *self, PyObject *args, PyObject *kwds) { STOP };

static PyObject * Pointer2_multiply(Pointer2 *self, PyObject *arg) { MULTIPLY };
static PyObject * Pointer2_inplace_multiply(Pointer2 *self, PyObject *arg) { INPLACE_MULTIPLY };
static PyObject * Pointer2_add(Pointer2 *self, PyObject *arg) { ADD };
static PyObject * Pointer2_inplace_add(Pointer2 *self, PyObject *arg) { INPLACE_ADD };
static PyObject * Pointer2_sub(Pointer2 *self, PyObject *arg) { SUB };
static PyObject * Pointer2_inplace_sub(Pointer2 *self, PyObject *arg) { INPLACE_SUB };
static PyObject * Pointer2_div(Pointer2 *self, PyObject *arg) { DIV };
static PyObject * Pointer2_inplace_div(Pointer2 *self, PyObject *arg) { INPLACE_DIV };

static PyObject *
Pointer2_getTable(Pointer2* self)
{
    Py_INCREF(self->table);
    return self->table;
};

static PyObject *
Pointer2_setTable(Pointer2 *self, PyObject *arg)
{
    ASSERT_ARG_NOT_NULL

    Py_DECREF(self->table);
    self->table = PyObject_CallMethod((PyObject *)arg, "getTableStream", "");

    Py_RETURN_NONE;
}

static PyObject *
Pointer2_setIndex(Pointer2 *self, PyObject *arg)
{
    ASSERT_ARG_NOT_NULL

    if (PyObject_HasAttrString((PyObject *)arg, "server") == 0)
    {
        PyErr_SetString(PyExc_TypeError, "\"index\" argument of Pointer2 must be a PyoObject.\n");
        Py_RETURN_NONE;
    }

    Py_DECREF(self->index);

    self->index = arg;
    Py_INCREF(self->index);
    PyObject *streamtmp = PyObject_CallMethod((PyObject *)self->index, "_getStream", NULL);
    self->index_stream = (Stream *)streamtmp;
    Py_INCREF(self->index_stream);

    Py_RETURN_NONE;
}

static PyObject *
Pointer2_setInterp(Pointer2 *self, PyObject *arg)
{
    ASSERT_ARG_NOT_NULL

    if (PyNumber_Check(arg))
    {
        self->interp = PyLong_AsLong(PyNumber_Long(arg));
    }

    SET_INTERP_POINTER

    Py_RETURN_NONE;
}

static PyObject *
Pointer2_setAutoSmooth(Pointer2 *self, PyObject *arg)
{
    ASSERT_ARG_NOT_NULL

    if (PyNumber_Check(arg))
    {
        self->autosmooth = PyLong_AsLong(PyNumber_Long(arg));
    }

    Py_RETURN_NONE;
}

static PyMemberDef Pointer2_members[] =
{
    {"server", T_OBJECT_EX, offsetof(Pointer2, server), 0, "Pyo server."},
    {"stream", T_OBJECT_EX, offsetof(Pointer2, stream), 0, "Stream object."},
    {"table", T_OBJECT_EX, offsetof(Pointer2, table), 0, "Waveform table."},
    {"index", T_OBJECT_EX, offsetof(Pointer2, index), 0, "Reader index."},
    {"mul", T_OBJECT_EX, offsetof(Pointer2, mul), 0, "Mul factor."},
    {"add", T_OBJECT_EX, offsetof(Pointer2, add), 0, "Add factor."},
    {NULL}  /* Sentinel */
};

static PyMethodDef Pointer2_methods[] =
{
    {"getTable", (PyCFunction)Pointer2_getTable, METH_NOARGS, "Returns waveform table object."},
    {"getServer", (PyCFunction)Pointer2_getServer, METH_NOARGS, "Returns server object."},
    {"_getStream", (PyCFunction)Pointer2_getStream, METH_NOARGS, "Returns stream object."},
    {"play", (PyCFunction)Pointer2_play, METH_VARARGS | METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
    {"out", (PyCFunction)Pointer2_out, METH_VARARGS | METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
    {"stop", (PyCFunction)Pointer2_stop, METH_VARARGS | METH_KEYWORDS, "Stops computing."},
    {"setTable", (PyCFunction)Pointer2_setTable, METH_O, "Sets oscillator table."},
    {"setIndex", (PyCFunction)Pointer2_setIndex, METH_O, "Sets reader index."},
    {"setInterp", (PyCFunction)Pointer2_setInterp, METH_O, "Sets oscillator interpolation mode."},
    {"setAutoSmooth", (PyCFunction)Pointer2_setAutoSmooth, METH_O, "Activates auto smoother filter."},
    {"setMul", (PyCFunction)Pointer2_setMul, METH_O, "Sets oscillator mul factor."},
    {"setAdd", (PyCFunction)Pointer2_setAdd, METH_O, "Sets oscillator add factor."},
    {"setSub", (PyCFunction)Pointer2_setSub, METH_O, "Sets oscillator inverse add factor."},
    {"setDiv", (PyCFunction)Pointer2_setDiv, METH_O, "Sets inverse mul factor."},
    {NULL}  /* Sentinel */
};

static PyNumberMethods Pointer2_as_number =
{
    (binaryfunc)Pointer2_add,                      /*nb_add*/
    (binaryfunc)Pointer2_sub,                 /*nb_subtract*/
    (binaryfunc)Pointer2_multiply,                 /*nb_multiply*/
    0,                /*nb_remainder*/
    0,                   /*nb_divmod*/
    0,                   /*nb_power*/
    0,                  /*nb_neg*/
    0,                /*nb_pos*/
    0,                  /*(unaryfunc)array_abs,*/
    0,                    /*nb_nonzero*/
    0,                    /*nb_invert*/
    0,               /*nb_lshift*/
    0,              /*nb_rshift*/
    0,              /*nb_and*/
    0,              /*nb_xor*/
    0,               /*nb_or*/
    0,                       /*nb_int*/
    0,                      /*nb_long*/
    0,                     /*nb_float*/
    (binaryfunc)Pointer2_inplace_add,              /*inplace_add*/
    (binaryfunc)Pointer2_inplace_sub,         /*inplace_subtract*/
    (binaryfunc)Pointer2_inplace_multiply,         /*inplace_multiply*/
    0,        /*inplace_remainder*/
    0,           /*inplace_power*/
    0,       /*inplace_lshift*/
    0,      /*inplace_rshift*/
    0,      /*inplace_and*/
    0,      /*inplace_xor*/
    0,       /*inplace_or*/
    0,             /*nb_floor_divide*/
    (binaryfunc)Pointer2_div,                       /*nb_true_divide*/
    0,     /*nb_inplace_floor_divide*/
    (binaryfunc)Pointer2_inplace_div,                       /*nb_inplace_true_divide*/
    0,                     /* nb_index */
};

PyTypeObject Pointer2Type =
{
    PyVarObject_HEAD_INIT(NULL, 0)
    "_pyo.Pointer2_base",         /*tp_name*/
    sizeof(Pointer2),         /*tp_basicsize*/
    0,                         /*tp_itemsize*/
    (destructor)Pointer2_dealloc, /*tp_dealloc*/
    0,                         /*tp_print*/
    0,                         /*tp_getattr*/
    0,                         /*tp_setattr*/
    0,                         /*tp_as_async (tp_compare in Python 2)*/
    0,                         /*tp_repr*/
    &Pointer2_as_number,             /*tp_as_number*/
    0,                         /*tp_as_sequence*/
    0,                         /*tp_as_mapping*/
    0,                         /*tp_hash */
    0,                         /*tp_call*/
    0,                         /*tp_str*/
    0,                         /*tp_getattro*/
    0,                         /*tp_setattro*/
    0,                         /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
    "Pointer2 objects. High quality table reader with a pointer index.",           /* tp_doc */
    (traverseproc)Pointer2_traverse,   /* tp_traverse */
    (inquiry)Pointer2_clear,           /* tp_clear */
    0,                     /* tp_richcompare */
    0,                     /* tp_weaklistoffset */
    0,                     /* tp_iter */
    0,                     /* tp_iternext */
    Pointer2_methods,             /* tp_methods */
    Pointer2_members,             /* tp_members */
    0,                      /* tp_getset */
    0,                         /* tp_base */
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    0,                         /* tp_dictoffset */
    0,      /* tp_init */
    0,                         /* tp_alloc */
    Pointer2_new,                 /* tp_new */
};

/**************/
/* TableIndex object */
/**************/
typedef struct
{
    pyo_audio_HEAD
    PyObject *table;
    PyObject *index;
    Stream *index_stream;
    int modebuffer[2];
} TableIndex;

static void
TableIndex_readframes_a(TableIndex *self)
{
    int i;
    T_SIZE_T ind;
    MYFLT *tablelist = TableStream_getData((TableStream *)self->table);
    T_SIZE_T size = TableStream_getSize((TableStream *)self->table);

    MYFLT *phase = Stream_getData((Stream *)self->index_stream);

    for (i = 0; i < self->bufsize; i++)
    {
        ind = (T_SIZE_T)phase[i];

        if (ind < 0)
            ind = 0;
        else if (ind >= size)
            ind = size - 1;

        self->data[i] = tablelist[ind];
    }
}

static void TableIndex_postprocessing_ii(TableIndex *self) { POST_PROCESSING_II };
static void TableIndex_postprocessing_ai(TableIndex *self) { POST_PROCESSING_AI };
static void TableIndex_postprocessing_ia(TableIndex *self) { POST_PROCESSING_IA };
static void TableIndex_postprocessing_aa(TableIndex *self) { POST_PROCESSING_AA };
static void TableIndex_postprocessing_ireva(TableIndex *self) { POST_PROCESSING_IREVA };
static void TableIndex_postprocessing_areva(TableIndex *self) { POST_PROCESSING_AREVA };
static void TableIndex_postprocessing_revai(TableIndex *self) { POST_PROCESSING_REVAI };
static void TableIndex_postprocessing_revaa(TableIndex *self) { POST_PROCESSING_REVAA };
static void TableIndex_postprocessing_revareva(TableIndex *self) { POST_PROCESSING_REVAREVA };

static void
TableIndex_setProcMode(TableIndex *self)
{
    int muladdmode;
    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;

    self->proc_func_ptr = TableIndex_readframes_a;

    switch (muladdmode)
    {
        case 0:
            self->muladd_func_ptr = TableIndex_postprocessing_ii;
            break;

        case 1:
            self->muladd_func_ptr = TableIndex_postprocessing_ai;
            break;

        case 2:
            self->muladd_func_ptr = TableIndex_postprocessing_revai;
            break;

        case 10:
            self->muladd_func_ptr = TableIndex_postprocessing_ia;
            break;

        case 11:
            self->muladd_func_ptr = TableIndex_postprocessing_aa;
            break;

        case 12:
            self->muladd_func_ptr = TableIndex_postprocessing_revaa;
            break;

        case 20:
            self->muladd_func_ptr = TableIndex_postprocessing_ireva;
            break;

        case 21:
            self->muladd_func_ptr = TableIndex_postprocessing_areva;
            break;

        case 22:
            self->muladd_func_ptr = TableIndex_postprocessing_revareva;
            break;
    }
}

static void
TableIndex_compute_next_data_frame(TableIndex *self)
{
    (*self->proc_func_ptr)(self);
    (*self->muladd_func_ptr)(self);
}

static int
TableIndex_traverse(TableIndex *self, visitproc visit, void *arg)
{
    pyo_VISIT
    Py_VISIT(self->index);
    return 0;
}

static int
TableIndex_clear(TableIndex *self)
{
    pyo_CLEAR
    Py_CLEAR(self->index);
    return 0;
}

static void
TableIndex_dealloc(TableIndex* self)
{
    pyo_DEALLOC
    TableIndex_clear(self);
    Py_TYPE(self->stream)->tp_free((PyObject*)self->stream);
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject *
TableIndex_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    int i;
    PyObject *tabletmp, *indextmp, *multmp = NULL, *addtmp = NULL;
    TableIndex *self;
    self = (TableIndex *)type->tp_alloc(type, 0);

    self->index = PyFloat_FromDouble(0.0);

    self->modebuffer[0] = 0;
    self->modebuffer[1] = 0;

    INIT_OBJECT_COMMON
    Stream_setFunctionPtr(self->stream, TableIndex_compute_next_data_frame);
    self->mode_func_ptr = TableIndex_setProcMode;

    static char *kwlist[] = {"table", "index", "mul", "add", NULL};

    if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO", kwlist, &tabletmp, &indextmp, &multmp, &addtmp))
        Py_RETURN_NONE;

    if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 )
    {
        PyErr_SetString(PyExc_TypeError, "\"table\" argument of TableIndex must be a PyoTableObject.\n");
        Py_RETURN_NONE;
    }

    self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");

    if (indextmp)
    {
        PyObject_CallMethod((PyObject *)self, "setIndex", "O", indextmp);
    }

    if (multmp)
    {
        PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
    }

    if (addtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
    }

    PyObject_CallMethod(self->server, "addStream", "O", self->stream);

    (*self->mode_func_ptr)(self);

    return (PyObject *)self;
}

static PyObject * TableIndex_getServer(TableIndex* self) { GET_SERVER };
static PyObject * TableIndex_getStream(TableIndex* self) { GET_STREAM };
static PyObject * TableIndex_setMul(TableIndex *self, PyObject *arg) { SET_MUL };
static PyObject * TableIndex_setAdd(TableIndex *self, PyObject *arg) { SET_ADD };
static PyObject * TableIndex_setSub(TableIndex *self, PyObject *arg) { SET_SUB };
static PyObject * TableIndex_setDiv(TableIndex *self, PyObject *arg) { SET_DIV };

static PyObject * TableIndex_play(TableIndex *self, PyObject *args, PyObject *kwds) { PLAY };
static PyObject * TableIndex_out(TableIndex *self, PyObject *args, PyObject *kwds) { OUT };
static PyObject * TableIndex_stop(TableIndex *self, PyObject *args, PyObject *kwds) { STOP };

static PyObject * TableIndex_multiply(TableIndex *self, PyObject *arg) { MULTIPLY };
static PyObject * TableIndex_inplace_multiply(TableIndex *self, PyObject *arg) { INPLACE_MULTIPLY };
static PyObject * TableIndex_add(TableIndex *self, PyObject *arg) { ADD };
static PyObject * TableIndex_inplace_add(TableIndex *self, PyObject *arg) { INPLACE_ADD };
static PyObject * TableIndex_sub(TableIndex *self, PyObject *arg) { SUB };
static PyObject * TableIndex_inplace_sub(TableIndex *self, PyObject *arg) { INPLACE_SUB };
static PyObject * TableIndex_div(TableIndex *self, PyObject *arg) { DIV };
static PyObject * TableIndex_inplace_div(TableIndex *self, PyObject *arg) { INPLACE_DIV };

static PyObject *
TableIndex_getTable(TableIndex* self)
{
    Py_INCREF(self->table);
    return self->table;
};

static PyObject *
TableIndex_setTable(TableIndex *self, PyObject *arg)
{
    ASSERT_ARG_NOT_NULL

    Py_DECREF(self->table);
    self->table = PyObject_CallMethod((PyObject *)arg, "getTableStream", "");

    Py_RETURN_NONE;
}

static PyObject *
TableIndex_setIndex(TableIndex *self, PyObject *arg)
{
    ASSERT_ARG_NOT_NULL

    if (PyObject_HasAttrString((PyObject *)arg, "server") == 0)
    {
        PyErr_SetString(PyExc_TypeError, "\"index\" argument of TableIndex must be a PyoObject.\n");
        Py_RETURN_NONE;
    }

    Py_DECREF(self->index);

    self->index = arg;
    Py_INCREF(self->index);
    PyObject *streamtmp = PyObject_CallMethod((PyObject *)self->index, "_getStream", NULL);
    self->index_stream = (Stream *)streamtmp;
    Py_INCREF(self->index_stream);

    Py_RETURN_NONE;
}

static PyMemberDef TableIndex_members[] =
{
    {"server", T_OBJECT_EX, offsetof(TableIndex, server), 0, "Pyo server."},
    {"stream", T_OBJECT_EX, offsetof(TableIndex, stream), 0, "Stream object."},
    {"table", T_OBJECT_EX, offsetof(TableIndex, table), 0, "Waveform table."},
    {"index", T_OBJECT_EX, offsetof(TableIndex, index), 0, "Reader index."},
    {"mul", T_OBJECT_EX, offsetof(TableIndex, mul), 0, "Mul factor."},
    {"add", T_OBJECT_EX, offsetof(TableIndex, add), 0, "Add factor."},
    {NULL}  /* Sentinel */
};

static PyMethodDef TableIndex_methods[] =
{
    {"getTable", (PyCFunction)TableIndex_getTable, METH_NOARGS, "Returns waveform table object."},
    {"getServer", (PyCFunction)TableIndex_getServer, METH_NOARGS, "Returns server object."},
    {"_getStream", (PyCFunction)TableIndex_getStream, METH_NOARGS, "Returns stream object."},
    {"play", (PyCFunction)TableIndex_play, METH_VARARGS | METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
    {"out", (PyCFunction)TableIndex_out, METH_VARARGS | METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
    {"stop", (PyCFunction)TableIndex_stop, METH_VARARGS | METH_KEYWORDS, "Stops computing."},
    {"setTable", (PyCFunction)TableIndex_setTable, METH_O, "Sets oscillator table."},
    {"setIndex", (PyCFunction)TableIndex_setIndex, METH_O, "Sets reader index."},
    {"setMul", (PyCFunction)TableIndex_setMul, METH_O, "Sets oscillator mul factor."},
    {"setAdd", (PyCFunction)TableIndex_setAdd, METH_O, "Sets oscillator add factor."},
    {"setSub", (PyCFunction)TableIndex_setSub, METH_O, "Sets oscillator inverse add factor."},
    {"setDiv", (PyCFunction)TableIndex_setDiv, METH_O, "Sets inverse mul factor."},
    {NULL}  /* Sentinel */
};

static PyNumberMethods TableIndex_as_number =
{
    (binaryfunc)TableIndex_add,                      /*nb_add*/
    (binaryfunc)TableIndex_sub,                 /*nb_subtract*/
    (binaryfunc)TableIndex_multiply,                 /*nb_multiply*/
    0,                /*nb_remainder*/
    0,                   /*nb_divmod*/
    0,                   /*nb_power*/
    0,                  /*nb_neg*/
    0,                /*nb_pos*/
    0,                  /*(unaryfunc)array_abs,*/
    0,                    /*nb_nonzero*/
    0,                    /*nb_invert*/
    0,               /*nb_lshift*/
    0,              /*nb_rshift*/
    0,              /*nb_and*/
    0,              /*nb_xor*/
    0,               /*nb_or*/
    0,                       /*nb_int*/
    0,                      /*nb_long*/
    0,                     /*nb_float*/
    (binaryfunc)TableIndex_inplace_add,              /*inplace_add*/
    (binaryfunc)TableIndex_inplace_sub,         /*inplace_subtract*/
    (binaryfunc)TableIndex_inplace_multiply,         /*inplace_multiply*/
    0,        /*inplace_remainder*/
    0,           /*inplace_power*/
    0,       /*inplace_lshift*/
    0,      /*inplace_rshift*/
    0,      /*inplace_and*/
    0,      /*inplace_xor*/
    0,       /*inplace_or*/
    0,             /*nb_floor_divide*/
    (binaryfunc)TableIndex_div,                       /*nb_true_divide*/
    0,     /*nb_inplace_floor_divide*/
    (binaryfunc)TableIndex_inplace_div,                       /*nb_inplace_true_divide*/
    0,                     /* nb_index */
};

PyTypeObject TableIndexType =
{
    PyVarObject_HEAD_INIT(NULL, 0)
    "_pyo.TableIndex_base",         /*tp_name*/
    sizeof(TableIndex),         /*tp_basicsize*/
    0,                         /*tp_itemsize*/
    (destructor)TableIndex_dealloc, /*tp_dealloc*/
    0,                         /*tp_print*/
    0,                         /*tp_getattr*/
    0,                         /*tp_setattr*/
    0,                         /*tp_as_async (tp_compare in Python 2)*/
    0,                         /*tp_repr*/
    &TableIndex_as_number,             /*tp_as_number*/
    0,                         /*tp_as_sequence*/
    0,                         /*tp_as_mapping*/
    0,                         /*tp_hash */
    0,                         /*tp_call*/
    0,                         /*tp_str*/
    0,                         /*tp_getattro*/
    0,                         /*tp_setattro*/
    0,                         /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
    "TableIndex objects. Read a table by indexing without interpolation.",           /* tp_doc */
    (traverseproc)TableIndex_traverse,   /* tp_traverse */
    (inquiry)TableIndex_clear,           /* tp_clear */
    0,                     /* tp_richcompare */
    0,                     /* tp_weaklistoffset */
    0,                     /* tp_iter */
    0,                     /* tp_iternext */
    TableIndex_methods,             /* tp_methods */
    TableIndex_members,             /* tp_members */
    0,                      /* tp_getset */
    0,                         /* tp_base */
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    0,                         /* tp_dictoffset */
    0,      /* tp_init */
    0,                         /* tp_alloc */
    TableIndex_new,                 /* tp_new */
};

/**************/
/* Lookup object */
/**************/
typedef struct
{
    pyo_audio_HEAD
    PyObject *table;
    PyObject *index;
    Stream *index_stream;
    int modebuffer[2];
} Lookup;

static MYFLT
Lookup_clip(MYFLT x)
{
    if (x < -1.0)
        return -1.0;
    else if (x > 1.0)
        return 1.0;
    else
        return x;
}

static void
Lookup_readframes_a(Lookup *self)
{
    int i;
    MYFLT ph, fpart;
    T_SIZE_T ipart;
    MYFLT *tablelist = TableStream_getData((TableStream *)self->table);
    T_SIZE_T size = TableStream_getSize((TableStream *)self->table);

    MYFLT *pha = Stream_getData((Stream *)self->index_stream);

    for (i = 0; i < self->bufsize; i++)
    {
        ph = (Lookup_clip(pha[i]) * 0.495 + 0.5) * size;
        ipart = (T_SIZE_T)ph;
        fpart = ph - ipart;
        self->data[i] = tablelist[ipart] + (tablelist[ipart + 1] - tablelist[ipart]) * fpart;
    }
}

static void Lookup_postprocessing_ii(Lookup *self) { POST_PROCESSING_II };
static void Lookup_postprocessing_ai(Lookup *self) { POST_PROCESSING_AI };
static void Lookup_postprocessing_ia(Lookup *self) { POST_PROCESSING_IA };
static void Lookup_postprocessing_aa(Lookup *self) { POST_PROCESSING_AA };
static void Lookup_postprocessing_ireva(Lookup *self) { POST_PROCESSING_IREVA };
static void Lookup_postprocessing_areva(Lookup *self) { POST_PROCESSING_AREVA };
static void Lookup_postprocessing_revai(Lookup *self) { POST_PROCESSING_REVAI };
static void Lookup_postprocessing_revaa(Lookup *self) { POST_PROCESSING_REVAA };
static void Lookup_postprocessing_revareva(Lookup *self) { POST_PROCESSING_REVAREVA };

static void
Lookup_setProcMode(Lookup *self)
{
    int muladdmode;
    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;

    self->proc_func_ptr = Lookup_readframes_a;

    switch (muladdmode)
    {
        case 0:
            self->muladd_func_ptr = Lookup_postprocessing_ii;
            break;

        case 1:
            self->muladd_func_ptr = Lookup_postprocessing_ai;
            break;

        case 2:
            self->muladd_func_ptr = Lookup_postprocessing_revai;
            break;

        case 10:
            self->muladd_func_ptr = Lookup_postprocessing_ia;
            break;

        case 11:
            self->muladd_func_ptr = Lookup_postprocessing_aa;
            break;

        case 12:
            self->muladd_func_ptr = Lookup_postprocessing_revaa;
            break;

        case 20:
            self->muladd_func_ptr = Lookup_postprocessing_ireva;
            break;

        case 21:
            self->muladd_func_ptr = Lookup_postprocessing_areva;
            break;

        case 22:
            self->muladd_func_ptr = Lookup_postprocessing_revareva;
            break;
    }
}

static void
Lookup_compute_next_data_frame(Lookup *self)
{
    (*self->proc_func_ptr)(self);
    (*self->muladd_func_ptr)(self);
}

static int
Lookup_traverse(Lookup *self, visitproc visit, void *arg)
{
    pyo_VISIT
    Py_VISIT(self->index);
    return 0;
}

static int
Lookup_clear(Lookup *self)
{
    pyo_CLEAR
    Py_CLEAR(self->index);
    return 0;
}

static void
Lookup_dealloc(Lookup* self)
{
    pyo_DEALLOC
    Lookup_clear(self);
    Py_TYPE(self->stream)->tp_free((PyObject*)self->stream);
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject *
Lookup_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    int i;
    PyObject *tabletmp, *indextmp, *multmp = NULL, *addtmp = NULL;
    Lookup *self;
    self = (Lookup *)type->tp_alloc(type, 0);

    self->index = PyFloat_FromDouble(0.0);

    self->modebuffer[0] = 0;
    self->modebuffer[1] = 0;

    INIT_OBJECT_COMMON
    Stream_setFunctionPtr(self->stream, Lookup_compute_next_data_frame);
    self->mode_func_ptr = Lookup_setProcMode;

    static char *kwlist[] = {"table", "index", "mul", "add", NULL};

    if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO", kwlist, &tabletmp, &indextmp, &multmp, &addtmp))
        Py_RETURN_NONE;

    if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 )
    {
        PyErr_SetString(PyExc_TypeError, "\"table\" argument of Lookup must be a PyoTableObject.\n");
        Py_RETURN_NONE;
    }

    self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");

    if (indextmp)
    {
        PyObject_CallMethod((PyObject *)self, "setIndex", "O", indextmp);
    }

    if (multmp)
    {
        PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
    }

    if (addtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
    }

    PyObject_CallMethod(self->server, "addStream", "O", self->stream);

    (*self->mode_func_ptr)(self);

    return (PyObject *)self;
}

static PyObject * Lookup_getServer(Lookup* self) { GET_SERVER };
static PyObject * Lookup_getStream(Lookup* self) { GET_STREAM };
static PyObject * Lookup_setMul(Lookup *self, PyObject *arg) { SET_MUL };
static PyObject * Lookup_setAdd(Lookup *self, PyObject *arg) { SET_ADD };
static PyObject * Lookup_setSub(Lookup *self, PyObject *arg) { SET_SUB };
static PyObject * Lookup_setDiv(Lookup *self, PyObject *arg) { SET_DIV };

static PyObject * Lookup_play(Lookup *self, PyObject *args, PyObject *kwds) { PLAY };
static PyObject * Lookup_out(Lookup *self, PyObject *args, PyObject *kwds) { OUT };
static PyObject * Lookup_stop(Lookup *self, PyObject *args, PyObject *kwds) { STOP };

static PyObject * Lookup_multiply(Lookup *self, PyObject *arg) { MULTIPLY };
static PyObject * Lookup_inplace_multiply(Lookup *self, PyObject *arg) { INPLACE_MULTIPLY };
static PyObject * Lookup_add(Lookup *self, PyObject *arg) { ADD };
static PyObject * Lookup_inplace_add(Lookup *self, PyObject *arg) { INPLACE_ADD };
static PyObject * Lookup_sub(Lookup *self, PyObject *arg) { SUB };
static PyObject * Lookup_inplace_sub(Lookup *self, PyObject *arg) { INPLACE_SUB };
static PyObject * Lookup_div(Lookup *self, PyObject *arg) { DIV };
static PyObject * Lookup_inplace_div(Lookup *self, PyObject *arg) { INPLACE_DIV };

static PyObject *
Lookup_getTable(Lookup* self)
{
    Py_INCREF(self->table);
    return self->table;
};

static PyObject *
Lookup_setTable(Lookup *self, PyObject *arg)
{
    ASSERT_ARG_NOT_NULL

    Py_DECREF(self->table);
    self->table = PyObject_CallMethod((PyObject *)arg, "getTableStream", "");

    Py_RETURN_NONE;
}

static PyObject *
Lookup_setIndex(Lookup *self, PyObject *arg)
{
    ASSERT_ARG_NOT_NULL

    if (PyObject_HasAttrString((PyObject *)arg, "server") == 0)
    {
        PyErr_SetString(PyExc_TypeError, "\"index\" argument of Lookup must be a PyoObject.\n");
        Py_RETURN_NONE;
    }

    Py_DECREF(self->index);

    self->index = arg;
    Py_INCREF(self->index);
    PyObject *streamtmp = PyObject_CallMethod((PyObject *)self->index, "_getStream", NULL);
    self->index_stream = (Stream *)streamtmp;
    Py_INCREF(self->index_stream);

    Py_RETURN_NONE;
}

static PyMemberDef Lookup_members[] =
{
    {"server", T_OBJECT_EX, offsetof(Lookup, server), 0, "Pyo server."},
    {"stream", T_OBJECT_EX, offsetof(Lookup, stream), 0, "Stream object."},
    {"table", T_OBJECT_EX, offsetof(Lookup, table), 0, "Waveform table."},
    {"index", T_OBJECT_EX, offsetof(Lookup, index), 0, "Reader index."},
    {"mul", T_OBJECT_EX, offsetof(Lookup, mul), 0, "Mul factor."},
    {"add", T_OBJECT_EX, offsetof(Lookup, add), 0, "Add factor."},
    {NULL}  /* Sentinel */
};

static PyMethodDef Lookup_methods[] =
{
    {"getTable", (PyCFunction)Lookup_getTable, METH_NOARGS, "Returns waveform table object."},
    {"getServer", (PyCFunction)Lookup_getServer, METH_NOARGS, "Returns server object."},
    {"_getStream", (PyCFunction)Lookup_getStream, METH_NOARGS, "Returns stream object."},
    {"play", (PyCFunction)Lookup_play, METH_VARARGS | METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
    {"out", (PyCFunction)Lookup_out, METH_VARARGS | METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
    {"stop", (PyCFunction)Lookup_stop, METH_VARARGS | METH_KEYWORDS, "Stops computing."},
    {"setTable", (PyCFunction)Lookup_setTable, METH_O, "Sets oscillator table."},
    {"setIndex", (PyCFunction)Lookup_setIndex, METH_O, "Sets reader index."},
    {"setMul", (PyCFunction)Lookup_setMul, METH_O, "Sets oscillator mul factor."},
    {"setAdd", (PyCFunction)Lookup_setAdd, METH_O, "Sets oscillator add factor."},
    {"setSub", (PyCFunction)Lookup_setSub, METH_O, "Sets oscillator inverse add factor."},
    {"setDiv", (PyCFunction)Lookup_setDiv, METH_O, "Sets inverse mul factor."},
    {NULL}  /* Sentinel */
};

static PyNumberMethods Lookup_as_number =
{
    (binaryfunc)Lookup_add,                      /*nb_add*/
    (binaryfunc)Lookup_sub,                 /*nb_subtract*/
    (binaryfunc)Lookup_multiply,                 /*nb_multiply*/
    0,                /*nb_remainder*/
    0,                   /*nb_divmod*/
    0,                   /*nb_power*/
    0,                  /*nb_neg*/
    0,                /*nb_pos*/
    0,                  /*(unaryfunc)array_abs,*/
    0,                    /*nb_nonzero*/
    0,                    /*nb_invert*/
    0,               /*nb_lshift*/
    0,              /*nb_rshift*/
    0,              /*nb_and*/
    0,              /*nb_xor*/
    0,               /*nb_or*/
    0,                       /*nb_int*/
    0,                      /*nb_long*/
    0,                     /*nb_float*/
    (binaryfunc)Lookup_inplace_add,              /*inplace_add*/
    (binaryfunc)Lookup_inplace_sub,         /*inplace_subtract*/
    (binaryfunc)Lookup_inplace_multiply,         /*inplace_multiply*/
    0,        /*inplace_remainder*/
    0,           /*inplace_power*/
    0,       /*inplace_lshift*/
    0,      /*inplace_rshift*/
    0,      /*inplace_and*/
    0,      /*inplace_xor*/
    0,       /*inplace_or*/
    0,             /*nb_floor_divide*/
    (binaryfunc)Lookup_div,                       /*nb_true_divide*/
    0,     /*nb_inplace_floor_divide*/
    (binaryfunc)Lookup_inplace_div,                       /*nb_inplace_true_divide*/
    0,                     /* nb_index */
};

PyTypeObject LookupType =
{
    PyVarObject_HEAD_INIT(NULL, 0)
    "_pyo.Lookup_base",         /*tp_name*/
    sizeof(Lookup),         /*tp_basicsize*/
    0,                         /*tp_itemsize*/
    (destructor)Lookup_dealloc, /*tp_dealloc*/
    0,                         /*tp_print*/
    0,                         /*tp_getattr*/
    0,                         /*tp_setattr*/
    0,                         /*tp_as_async (tp_compare in Python 2)*/
    0,                         /*tp_repr*/
    &Lookup_as_number,             /*tp_as_number*/
    0,                         /*tp_as_sequence*/
    0,                         /*tp_as_mapping*/
    0,                         /*tp_hash */
    0,                         /*tp_call*/
    0,                         /*tp_str*/
    0,                         /*tp_getattro*/
    0,                         /*tp_setattro*/
    0,                         /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
    "Lookup objects. Modify a signal by reading a table with the signal as the index.",           /* tp_doc */
    (traverseproc)Lookup_traverse,   /* tp_traverse */
    (inquiry)Lookup_clear,           /* tp_clear */
    0,                     /* tp_richcompare */
    0,                     /* tp_weaklistoffset */
    0,                     /* tp_iter */
    0,                     /* tp_iternext */
    Lookup_methods,             /* tp_methods */
    Lookup_members,             /* tp_members */
    0,                      /* tp_getset */
    0,                         /* tp_base */
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    0,                         /* tp_dictoffset */
    0,      /* tp_init */
    0,                         /* tp_alloc */
    Lookup_new,                 /* tp_new */
};

/**************/
/* Pulsar object */
/**************/
typedef struct
{
    pyo_audio_HEAD
    PyObject *table;
    PyObject *env;
    PyObject *freq;
    Stream *freq_stream;
    PyObject *phase;
    Stream *phase_stream;
    PyObject *frac;
    Stream *frac_stream;
    int modebuffer[5];
    MYFLT pointerPos;
    int interp; /* 0 = default to 2, 1 = nointerp, 2 = linear, 3 = cos, 4 = cubic */
    MYFLT (*interp_func_ptr)(MYFLT *, T_SIZE_T, MYFLT, T_SIZE_T);
} Pulsar;

static void
Pulsar_readframes_iii(Pulsar *self)
{
    int i;
    MYFLT fr, ph, frac, invfrac, pos, scl_pos, t_pos, e_pos, fpart, tmp;
    double inc;
    T_SIZE_T ipart;
    MYFLT *tablelist = TableStream_getData((TableStream *)self->table);
    MYFLT *envlist = TableStream_getData((TableStream *)self->env);
    T_SIZE_T size = TableStream_getSize((TableStream *)self->table);
    T_SIZE_T envsize = TableStream_getSize((TableStream *)self->env);

    fr = PyFloat_AS_DOUBLE(self->freq);
    ph = PyFloat_AS_DOUBLE(self->phase);
    frac = _clip(PyFloat_AS_DOUBLE(self->frac));
    invfrac = 1.0 / frac;
    inc = fr / self->sr;

    for (i = 0; i < self->bufsize; i++)
    {
        self->pointerPos += inc;

        if (self->pointerPos < 0)
            self->pointerPos = 1.0 + self->pointerPos;
        else if (self->pointerPos >= 1.0)
            self->pointerPos -= 1.0;

        pos = self->pointerPos + ph;

        if (pos >= 1.0)
            pos -= 1.0;

        if (pos < frac)
        {
            scl_pos = pos * invfrac;
            t_pos = scl_pos * size;
            ipart = (T_SIZE_T)t_pos;
            fpart = t_pos - ipart;
            tmp = (*self->interp_func_ptr)(tablelist, ipart, fpart, size);

            e_pos = scl_pos * envsize;
            ipart = (T_SIZE_T)e_pos;
            fpart = e_pos - ipart;
            self->data[i] = tmp * (envlist[ipart] + (envlist[ipart + 1] - envlist[ipart]) * fpart);
        }
        else
        {
            self->data[i] = 0.0;
        }
    }
}

static void
Pulsar_readframes_aii(Pulsar *self)
{
    int i;
    MYFLT ph, frac, invfrac, pos, scl_pos, t_pos, e_pos, fpart, tmp, oneOnSr;
    double inc;
    T_SIZE_T ipart;
    MYFLT *tablelist = TableStream_getData((TableStream *)self->table);
    MYFLT *envlist = TableStream_getData((TableStream *)self->env);
    T_SIZE_T size = TableStream_getSize((TableStream *)self->table);
    T_SIZE_T envsize = TableStream_getSize((TableStream *)self->env);

    MYFLT *fr = Stream_getData((Stream *)self->freq_stream);
    ph = PyFloat_AS_DOUBLE(self->phase);
    frac = _clip(PyFloat_AS_DOUBLE(self->frac));
    invfrac = 1.0 / frac;

    oneOnSr = 1.0 / self->sr;

    for (i = 0; i < self->bufsize; i++)
    {
        inc = fr[i] * oneOnSr;
        self->pointerPos += inc;

        if (self->pointerPos < 0)
            self->pointerPos = 1.0 + self->pointerPos;
        else if (self->pointerPos >= 1.0)
            self->pointerPos -= 1.0;

        pos = self->pointerPos + ph;

        if (pos >= 1.0)
            pos -= 1.0;

        if (pos < frac)
        {
            scl_pos = pos * invfrac;
            t_pos = scl_pos * size;
            ipart = (T_SIZE_T)t_pos;
            fpart = t_pos - ipart;
            tmp = (*self->interp_func_ptr)(tablelist, ipart, fpart, size);

            e_pos = scl_pos * envsize;
            ipart = (T_SIZE_T)e_pos;
            fpart = e_pos - ipart;
            self->data[i] = tmp * (envlist[ipart] + (envlist[ipart + 1] - envlist[ipart]) * fpart);
        }
        else
        {
            self->data[i] = 0.0;
        }
    }
}

static void
Pulsar_readframes_iai(Pulsar *self)
{
    int i;
    MYFLT fr, frac, invfrac, pos, scl_pos, t_pos, e_pos, fpart, tmp;
    double inc;
    T_SIZE_T ipart;
    MYFLT *tablelist = TableStream_getData((TableStream *)self->table);
    MYFLT *envlist = TableStream_getData((TableStream *)self->env);
    T_SIZE_T size = TableStream_getSize((TableStream *)self->table);
    T_SIZE_T envsize = TableStream_getSize((TableStream *)self->env);

    fr = PyFloat_AS_DOUBLE(self->freq);
    MYFLT *ph = Stream_getData((Stream *)self->phase_stream);
    frac = _clip(PyFloat_AS_DOUBLE(self->frac));
    invfrac = 1.0 / frac;
    inc = fr / self->sr;

    for (i = 0; i < self->bufsize; i++)
    {
        self->pointerPos += inc;

        if (self->pointerPos < 0)
            self->pointerPos = 1.0 + self->pointerPos;
        else if (self->pointerPos >= 1.0)
            self->pointerPos -= 1.0;

        pos = self->pointerPos + ph[i];

        if (pos >= 1.0)
            pos -= 1.0;

        if (pos < frac)
        {
            scl_pos = pos * invfrac;
            t_pos = scl_pos * size;
            ipart = (T_SIZE_T)t_pos;
            fpart = t_pos - ipart;
            tmp = (*self->interp_func_ptr)(tablelist, ipart, fpart, size);

            e_pos = scl_pos * envsize;
            ipart = (T_SIZE_T)e_pos;
            fpart = e_pos - ipart;
            self->data[i] = tmp * (envlist[ipart] + (envlist[ipart + 1] - envlist[ipart]) * fpart);
        }
        else
        {
            self->data[i] = 0.0;
        }
    }
}

static void
Pulsar_readframes_aai(Pulsar *self)
{
    int i;
    MYFLT frac, invfrac, pos, scl_pos, t_pos, e_pos, fpart, tmp, oneOnSr;
    double inc;
    T_SIZE_T ipart;
    MYFLT *tablelist = TableStream_getData((TableStream *)self->table);
    MYFLT *envlist = TableStream_getData((TableStream *)self->env);
    T_SIZE_T size = TableStream_getSize((TableStream *)self->table);
    T_SIZE_T envsize = TableStream_getSize((TableStream *)self->env);

    MYFLT *fr = Stream_getData((Stream *)self->freq_stream);
    MYFLT *ph = Stream_getData((Stream *)self->phase_stream);
    frac = _clip(PyFloat_AS_DOUBLE(self->frac));
    invfrac = 1.0 / frac;

    oneOnSr = 1.0 / self->sr;

    for (i = 0; i < self->bufsize; i++)
    {
        inc = fr[i] * oneOnSr;
        self->pointerPos += inc;

        if (self->pointerPos < 0)
            self->pointerPos = 1.0 + self->pointerPos;
        else if (self->pointerPos >= 1.0)
            self->pointerPos -= 1.0;

        pos = self->pointerPos + ph[i];

        if (pos >= 1.0)
            pos -= 1.0;

        if (pos < frac)
        {
            scl_pos = pos * invfrac;
            t_pos = scl_pos * size;
            ipart = (T_SIZE_T)t_pos;
            fpart = t_pos - ipart;
            tmp = (*self->interp_func_ptr)(tablelist, ipart, fpart, size);

            e_pos = scl_pos * envsize;
            ipart = (T_SIZE_T)e_pos;
            fpart = e_pos - ipart;
            self->data[i] = tmp * (envlist[ipart] + (envlist[ipart + 1] - envlist[ipart]) * fpart);
        }
        else
        {
            self->data[i] = 0.0;
        }
    }
}

static void
Pulsar_readframes_iia(Pulsar *self)
{
    int i;
    MYFLT fr, ph, pos, curfrac, scl_pos, t_pos, e_pos, fpart, tmp;
    double inc;
    T_SIZE_T ipart;
    MYFLT *tablelist = TableStream_getData((TableStream *)self->table);
    MYFLT *envlist = TableStream_getData((TableStream *)self->env);
    T_SIZE_T size = TableStream_getSize((TableStream *)self->table);
    T_SIZE_T envsize = TableStream_getSize((TableStream *)self->env);

    fr = PyFloat_AS_DOUBLE(self->freq);
    ph = PyFloat_AS_DOUBLE(self->phase);
    MYFLT *frac = Stream_getData((Stream *)self->frac_stream);
    inc = fr / self->sr;

    for (i = 0; i < self->bufsize; i++)
    {
        curfrac = frac[i];
        self->pointerPos += inc;

        if (self->pointerPos < 0)
            self->pointerPos = 1.0 + self->pointerPos;
        else if (self->pointerPos >= 1.0)
            self->pointerPos -= 1.0;

        pos = self->pointerPos + ph;

        if (pos >= 1.0)
            pos -= 1.0;

        if (pos < curfrac)
        {
            scl_pos = pos / curfrac;
            t_pos = scl_pos * size;
            ipart = (T_SIZE_T)t_pos;
            fpart = t_pos - ipart;
            tmp = (*self->interp_func_ptr)(tablelist, ipart, fpart, size);

            e_pos = scl_pos * envsize;
            ipart = (T_SIZE_T)e_pos;
            fpart = e_pos - ipart;
            self->data[i] = tmp * (envlist[ipart] + (envlist[ipart + 1] - envlist[ipart]) * fpart);
        }
        else
        {
            self->data[i] = 0.0;
        }
    }
}

static void
Pulsar_readframes_aia(Pulsar *self)
{
    int i;
    MYFLT ph, pos, curfrac, scl_pos, t_pos, e_pos, fpart, tmp, oneOnSr;
    double inc;
    T_SIZE_T ipart;
    MYFLT *tablelist = TableStream_getData((TableStream *)self->table);
    MYFLT *envlist = TableStream_getData((TableStream *)self->env);
    T_SIZE_T size = TableStream_getSize((TableStream *)self->table);
    T_SIZE_T envsize = TableStream_getSize((TableStream *)self->env);

    MYFLT *fr = Stream_getData((Stream *)self->freq_stream);
    ph = PyFloat_AS_DOUBLE(self->phase);
    MYFLT *frac = Stream_getData((Stream *)self->frac_stream);

    oneOnSr = 1.0 / self->sr;

    for (i = 0; i < self->bufsize; i++)
    {
        curfrac = frac[i];
        inc = fr[i] * oneOnSr;
        self->pointerPos += inc;

        if (self->pointerPos < 0)
            self->pointerPos = 1.0 + self->pointerPos;
        else if (self->pointerPos >= 1.0)
            self->pointerPos -= 1.0;

        pos = self->pointerPos + ph;

        if (pos >= 1.0)
            pos -= 1.0;

        if (pos < curfrac)
        {
            scl_pos = pos / curfrac;
            t_pos = scl_pos * size;
            ipart = (T_SIZE_T)t_pos;
            fpart = t_pos - ipart;
            tmp = (*self->interp_func_ptr)(tablelist, ipart, fpart, size);

            e_pos = scl_pos * envsize;
            ipart = (T_SIZE_T)e_pos;
            fpart = e_pos - ipart;
            self->data[i] = tmp * (envlist[ipart] + (envlist[ipart + 1] - envlist[ipart]) * fpart);
        }
        else
        {
            self->data[i] = 0.0;
        }
    }
}

static void
Pulsar_readframes_iaa(Pulsar *self)
{
    int i;
    MYFLT fr, pos, curfrac, scl_pos, t_pos, e_pos, fpart, tmp;
    double inc;
    T_SIZE_T ipart;
    MYFLT *tablelist = TableStream_getData((TableStream *)self->table);
    MYFLT *envlist = TableStream_getData((TableStream *)self->env);
    T_SIZE_T size = TableStream_getSize((TableStream *)self->table);
    T_SIZE_T envsize = TableStream_getSize((TableStream *)self->env);

    fr = PyFloat_AS_DOUBLE(self->freq);
    MYFLT *ph = Stream_getData((Stream *)self->phase_stream);
    MYFLT *frac = Stream_getData((Stream *)self->frac_stream);
    inc = fr / self->sr;

    for (i = 0; i < self->bufsize; i++)
    {
        curfrac = frac[i];
        self->pointerPos += inc;

        if (self->pointerPos < 0)
            self->pointerPos = 1.0 + self->pointerPos;
        else if (self->pointerPos >= 1.0)
            self->pointerPos -= 1.0;

        pos = self->pointerPos + ph[i];

        if (pos >= 1.0)
            pos -= 1.0;

        if (pos < curfrac)
        {
            scl_pos = pos / curfrac;
            t_pos = scl_pos * size;
            ipart = (T_SIZE_T)t_pos;
            fpart = t_pos - ipart;
            tmp = (*self->interp_func_ptr)(tablelist, ipart, fpart, size);

            e_pos = scl_pos * envsize;
            ipart = (T_SIZE_T)e_pos;
            fpart = e_pos - ipart;
            self->data[i] = tmp * (envlist[ipart] + (envlist[ipart + 1] - envlist[ipart]) * fpart);
        }
        else
        {
            self->data[i] = 0.0;
        }
    }
}

static void
Pulsar_readframes_aaa(Pulsar *self)
{
    int i;
    MYFLT pos, curfrac, scl_pos, t_pos, e_pos, fpart, tmp, oneOnSr;
    double inc;
    T_SIZE_T ipart;
    MYFLT *tablelist = TableStream_getData((TableStream *)self->table);
    MYFLT *envlist = TableStream_getData((TableStream *)self->env);
    T_SIZE_T size = TableStream_getSize((TableStream *)self->table);
    T_SIZE_T envsize = TableStream_getSize((TableStream *)self->env);

    MYFLT *fr = Stream_getData((Stream *)self->freq_stream);
    MYFLT *ph = Stream_getData((Stream *)self->phase_stream);
    MYFLT *frac = Stream_getData((Stream *)self->frac_stream);

    oneOnSr = 1.0 / self->sr;

    for (i = 0; i < self->bufsize; i++)
    {
        curfrac = frac[i];
        inc = fr[i] * oneOnSr;
        self->pointerPos += inc;

        if (self->pointerPos < 0)
            self->pointerPos = 1.0 + self->pointerPos;
        else if (self->pointerPos >= 1.0)
            self->pointerPos -= 1.0;

        pos = self->pointerPos + ph[i];

        if (pos >= 1.0)
            pos -= 1.0;

        if (pos < curfrac)
        {
            scl_pos = pos / curfrac;
            t_pos = scl_pos * size;
            ipart = (T_SIZE_T)t_pos;
            fpart = t_pos - ipart;
            tmp = (*self->interp_func_ptr)(tablelist, ipart, fpart, size);

            e_pos = scl_pos * envsize;
            ipart = (T_SIZE_T)e_pos;
            fpart = e_pos - ipart;
            self->data[i] = tmp * (envlist[ipart] + (envlist[ipart + 1] - envlist[ipart]) * fpart);
        }
        else
        {
            self->data[i] = 0.0;
        }
    }
}

static void Pulsar_postprocessing_ii(Pulsar *self) { POST_PROCESSING_II };
static void Pulsar_postprocessing_ai(Pulsar *self) { POST_PROCESSING_AI };
static void Pulsar_postprocessing_ia(Pulsar *self) { POST_PROCESSING_IA };
static void Pulsar_postprocessing_aa(Pulsar *self) { POST_PROCESSING_AA };
static void Pulsar_postprocessing_ireva(Pulsar *self) { POST_PROCESSING_IREVA };
static void Pulsar_postprocessing_areva(Pulsar *self) { POST_PROCESSING_AREVA };
static void Pulsar_postprocessing_revai(Pulsar *self) { POST_PROCESSING_REVAI };
static void Pulsar_postprocessing_revaa(Pulsar *self) { POST_PROCESSING_REVAA };
static void Pulsar_postprocessing_revareva(Pulsar *self) { POST_PROCESSING_REVAREVA };

static void
Pulsar_setProcMode(Pulsar *self)
{
    int procmode, muladdmode;
    procmode = self->modebuffer[2] + self->modebuffer[3] * 10 + self->modebuffer[4] * 100;
    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;

    switch (procmode)
    {
        case 0:
            self->proc_func_ptr = Pulsar_readframes_iii;
            break;

        case 1:
            self->proc_func_ptr = Pulsar_readframes_aii;
            break;

        case 10:
            self->proc_func_ptr = Pulsar_readframes_iai;
            break;

        case 11:
            self->proc_func_ptr = Pulsar_readframes_aai;
            break;

        case 100:
            self->proc_func_ptr = Pulsar_readframes_iia;
            break;

        case 101:
            self->proc_func_ptr = Pulsar_readframes_aia;
            break;

        case 110:
            self->proc_func_ptr = Pulsar_readframes_iaa;
            break;

        case 111:
            self->proc_func_ptr = Pulsar_readframes_aaa;
            break;
    }

    switch (muladdmode)
    {
        case 0:
            self->muladd_func_ptr = Pulsar_postprocessing_ii;
            break;

        case 1:
            self->muladd_func_ptr = Pulsar_postprocessing_ai;
            break;

        case 2:
            self->muladd_func_ptr = Pulsar_postprocessing_revai;
            break;

        case 10:
            self->muladd_func_ptr = Pulsar_postprocessing_ia;
            break;

        case 11:
            self->muladd_func_ptr = Pulsar_postprocessing_aa;
            break;

        case 12:
            self->muladd_func_ptr = Pulsar_postprocessing_revaa;
            break;

        case 20:
            self->muladd_func_ptr = Pulsar_postprocessing_ireva;
            break;

        case 21:
            self->muladd_func_ptr = Pulsar_postprocessing_areva;
            break;

        case 22:
            self->muladd_func_ptr = Pulsar_postprocessing_revareva;
            break;
    }
}

static void
Pulsar_compute_next_data_frame(Pulsar *self)
{
    (*self->proc_func_ptr)(self);
    (*self->muladd_func_ptr)(self);
}

static int
Pulsar_traverse(Pulsar *self, visitproc visit, void *arg)
{
    pyo_VISIT
    Py_VISIT(self->phase);
    Py_VISIT(self->freq);
    Py_VISIT(self->frac);
    return 0;
}

static int
Pulsar_clear(Pulsar *self)
{
    pyo_CLEAR
    Py_CLEAR(self->phase);
    Py_CLEAR(self->freq);
    Py_CLEAR(self->frac);
    return 0;
}

static void
Pulsar_dealloc(Pulsar* self)
{
    pyo_DEALLOC
    Pulsar_clear(self);
    Py_TYPE(self->stream)->tp_free((PyObject*)self->stream);
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject *
Pulsar_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    int i;
    PyObject *tabletmp, *envtmp, *freqtmp = NULL, *phasetmp = NULL, *fractmp = NULL, *multmp = NULL, *addtmp = NULL;
    Pulsar *self;
    self = (Pulsar *)type->tp_alloc(type, 0);

    self->freq = PyFloat_FromDouble(100);
    self->phase = PyFloat_FromDouble(0);
    self->frac = PyFloat_FromDouble(0.5);
    self->interp = 2;
    self->modebuffer[0] = 0;
    self->modebuffer[1] = 0;
    self->modebuffer[2] = 0;
    self->modebuffer[3] = 0;
    self->modebuffer[4] = 0;
    self->pointerPos = 0.;

    INIT_OBJECT_COMMON
    Stream_setFunctionPtr(self->stream, Pulsar_compute_next_data_frame);
    self->mode_func_ptr = Pulsar_setProcMode;

    static char *kwlist[] = {"table", "env", "freq", "frac", "phase", "interp", "mul", "add", NULL};

    if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OOOiOO", kwlist, &tabletmp, &envtmp, &freqtmp, &fractmp, &phasetmp, &self->interp, &multmp, &addtmp))
        Py_RETURN_NONE;

    if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 )
    {
        PyErr_SetString(PyExc_TypeError, "\"table\" argument of Pulsar must be a PyoTableObject.\n");
        Py_RETURN_NONE;
    }

    self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");

    if ( PyObject_HasAttrString((PyObject *)envtmp, "getTableStream") == 0 )
    {
        PyErr_SetString(PyExc_TypeError, "\"env\" argument of Pulsar must be a PyoTableObject.\n");
        Py_RETURN_NONE;
    }

    self->env = PyObject_CallMethod((PyObject *)envtmp, "getTableStream", "");

    if (phasetmp)
    {
        PyObject_CallMethod((PyObject *)self, "setPhase", "O", phasetmp);
    }

    if (freqtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setFreq", "O", freqtmp);
    }

    if (fractmp)
    {
        PyObject_CallMethod((PyObject *)self, "setFrac", "O", fractmp);
    }

    if (multmp)
    {
        PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
    }

    if (addtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
    }

    PyObject_CallMethod(self->server, "addStream", "O", self->stream);

    (*self->mode_func_ptr)(self);

    SET_INTERP_POINTER

    return (PyObject *)self;
}

static PyObject * Pulsar_getServer(Pulsar* self) { GET_SERVER };
static PyObject * Pulsar_getStream(Pulsar* self) { GET_STREAM };
static PyObject * Pulsar_setMul(Pulsar *self, PyObject *arg) { SET_MUL };
static PyObject * Pulsar_setAdd(Pulsar *self, PyObject *arg) { SET_ADD };
static PyObject * Pulsar_setSub(Pulsar *self, PyObject *arg) { SET_SUB };
static PyObject * Pulsar_setDiv(Pulsar *self, PyObject *arg) { SET_DIV };

static PyObject * Pulsar_play(Pulsar *self, PyObject *args, PyObject *kwds) { PLAY };
static PyObject * Pulsar_out(Pulsar *self, PyObject *args, PyObject *kwds) { OUT };
static PyObject * Pulsar_stop(Pulsar *self, PyObject *args, PyObject *kwds) { STOP };

static PyObject * Pulsar_multiply(Pulsar *self, PyObject *arg) { MULTIPLY };
static PyObject * Pulsar_inplace_multiply(Pulsar *self, PyObject *arg) { INPLACE_MULTIPLY };
static PyObject * Pulsar_add(Pulsar *self, PyObject *arg) { ADD };
static PyObject * Pulsar_inplace_add(Pulsar *self, PyObject *arg) { INPLACE_ADD };
static PyObject * Pulsar_sub(Pulsar *self, PyObject *arg) { SUB };
static PyObject * Pulsar_inplace_sub(Pulsar *self, PyObject *arg) { INPLACE_SUB };
static PyObject * Pulsar_div(Pulsar *self, PyObject *arg) { DIV };
static PyObject * Pulsar_inplace_div(Pulsar *self, PyObject *arg) { INPLACE_DIV };

static PyObject *
Pulsar_getTable(Pulsar* self)
{
    Py_INCREF(self->table);
    return self->table;
};

static PyObject *
Pulsar_getEnv(Pulsar* self)
{
    Py_INCREF(self->env);
    return self->env;
};

static PyObject *
Pulsar_setTable(Pulsar *self, PyObject *arg)
{
    ASSERT_ARG_NOT_NULL

    Py_DECREF(self->table);
    self->table = PyObject_CallMethod((PyObject *)arg, "getTableStream", "");

    Py_RETURN_NONE;
}

static PyObject *
Pulsar_setEnv(Pulsar *self, PyObject *arg)
{
    ASSERT_ARG_NOT_NULL

    Py_DECREF(self->env);
    self->env = PyObject_CallMethod((PyObject *)arg, "getTableStream", "");

    Py_RETURN_NONE;
}

static PyObject * Pulsar_setFreq(Pulsar *self, PyObject *arg) { SET_PARAM(self->freq, self->freq_stream, 2); }
static PyObject * Pulsar_setPhase(Pulsar *self, PyObject *arg) { SET_PARAM(self->phase, self->phase_stream, 3); }
static PyObject * Pulsar_setFrac(Pulsar *self, PyObject *arg) { SET_PARAM(self->frac, self->frac_stream, 4); }

static PyObject *
Pulsar_setInterp(Pulsar *self, PyObject *arg)
{
    ASSERT_ARG_NOT_NULL

    if (PyNumber_Check(arg))
    {
        self->interp = PyLong_AsLong(PyNumber_Long(arg));
    }

    SET_INTERP_POINTER

    Py_RETURN_NONE;
}

static PyMemberDef Pulsar_members[] =
{
    {"server", T_OBJECT_EX, offsetof(Pulsar, server), 0, "Pyo server."},
    {"stream", T_OBJECT_EX, offsetof(Pulsar, stream), 0, "Stream object."},
    {"table", T_OBJECT_EX, offsetof(Pulsar, table), 0, "Waveform table."},
    {"freq", T_OBJECT_EX, offsetof(Pulsar, freq), 0, "Frequency in cycle per second."},
    {"phase", T_OBJECT_EX, offsetof(Pulsar, phase), 0, "Oscillator phase."},
    {"frac", T_OBJECT_EX, offsetof(Pulsar, frac), 0, "Table width inside whole length."},
    {"mul", T_OBJECT_EX, offsetof(Pulsar, mul), 0, "Mul factor."},
    {"add", T_OBJECT_EX, offsetof(Pulsar, add), 0, "Add factor."},
    {NULL}  /* Sentinel */
};

static PyMethodDef Pulsar_methods[] =
{
    {"getTable", (PyCFunction)Pulsar_getTable, METH_NOARGS, "Returns waveform table object."},
    {"getEnv", (PyCFunction)Pulsar_getEnv, METH_NOARGS, "Returns object envelope."},
    {"getServer", (PyCFunction)Pulsar_getServer, METH_NOARGS, "Returns server object."},
    {"_getStream", (PyCFunction)Pulsar_getStream, METH_NOARGS, "Returns stream object."},
    {"play", (PyCFunction)Pulsar_play, METH_VARARGS | METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
    {"out", (PyCFunction)Pulsar_out, METH_VARARGS | METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
    {"stop", (PyCFunction)Pulsar_stop, METH_VARARGS | METH_KEYWORDS, "Stops computing."},
    {"setTable", (PyCFunction)Pulsar_setTable, METH_O, "Sets oscillator table."},
    {"setEnv", (PyCFunction)Pulsar_setEnv, METH_O, "Sets envelope table."},
    {"setFreq", (PyCFunction)Pulsar_setFreq, METH_O, "Sets oscillator frequency in cycle per second."},
    {"setPhase", (PyCFunction)Pulsar_setPhase, METH_O, "Sets oscillator phase."},
    {"setFrac", (PyCFunction)Pulsar_setFrac, METH_O, "Sets waveform width inside whole period length."},
    {"setInterp", (PyCFunction)Pulsar_setInterp, METH_O, "Sets Pulsar interpolation mode."},
    {"setMul", (PyCFunction)Pulsar_setMul, METH_O, "Sets oscillator mul factor."},
    {"setAdd", (PyCFunction)Pulsar_setAdd, METH_O, "Sets oscillator add factor."},
    {"setSub", (PyCFunction)Pulsar_setSub, METH_O, "Sets oscillator inverse add factor."},
    {"setDiv", (PyCFunction)Pulsar_setDiv, METH_O, "Sets inverse mul factor."},
    {NULL}  /* Sentinel */
};

static PyNumberMethods Pulsar_as_number =
{
    (binaryfunc)Pulsar_add,                      /*nb_add*/
    (binaryfunc)Pulsar_sub,                 /*nb_subtract*/
    (binaryfunc)Pulsar_multiply,                 /*nb_multiply*/
    0,                /*nb_remainder*/
    0,                   /*nb_divmod*/
    0,                   /*nb_power*/
    0,                  /*nb_neg*/
    0,                /*nb_pos*/
    0,                  /*(unaryfunc)array_abs,*/
    0,                    /*nb_nonzero*/
    0,                    /*nb_invert*/
    0,               /*nb_lshift*/
    0,              /*nb_rshift*/
    0,              /*nb_and*/
    0,              /*nb_xor*/
    0,               /*nb_or*/
    0,                       /*nb_int*/
    0,                      /*nb_long*/
    0,                     /*nb_float*/
    (binaryfunc)Pulsar_inplace_add,              /*inplace_add*/
    (binaryfunc)Pulsar_inplace_sub,         /*inplace_subtract*/
    (binaryfunc)Pulsar_inplace_multiply,         /*inplace_multiply*/
    0,        /*inplace_remainder*/
    0,           /*inplace_power*/
    0,       /*inplace_lshift*/
    0,      /*inplace_rshift*/
    0,      /*inplace_and*/
    0,      /*inplace_xor*/
    0,       /*inplace_or*/
    0,             /*nb_floor_divide*/
    (binaryfunc)Pulsar_div,                       /*nb_true_divide*/
    0,     /*nb_inplace_floor_divide*/
    (binaryfunc)Pulsar_inplace_div,                       /*nb_inplace_true_divide*/
    0,                     /* nb_index */
};

PyTypeObject PulsarType =
{
    PyVarObject_HEAD_INIT(NULL, 0)
    "_pyo.Pulsar_base",         /*tp_name*/
    sizeof(Pulsar),         /*tp_basicsize*/
    0,                         /*tp_itemsize*/
    (destructor)Pulsar_dealloc, /*tp_dealloc*/
    0,                         /*tp_print*/
    0,                         /*tp_getattr*/
    0,                         /*tp_setattr*/
    0,                         /*tp_as_async (tp_compare in Python 2)*/
    0,                         /*tp_repr*/
    &Pulsar_as_number,             /*tp_as_number*/
    0,                         /*tp_as_sequence*/
    0,                         /*tp_as_mapping*/
    0,                         /*tp_hash */
    0,                         /*tp_call*/
    0,                         /*tp_str*/
    0,                         /*tp_getattro*/
    0,                         /*tp_setattro*/
    0,                         /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
    "Pulsar objects. Generates pulsar synthesis oscillator.",           /* tp_doc */
    (traverseproc)Pulsar_traverse,   /* tp_traverse */
    (inquiry)Pulsar_clear,           /* tp_clear */
    0,                     /* tp_richcompare */
    0,                     /* tp_weaklistoffset */
    0,                     /* tp_iter */
    0,                     /* tp_iternext */
    Pulsar_methods,             /* tp_methods */
    Pulsar_members,             /* tp_members */
    0,                      /* tp_getset */
    0,                         /* tp_base */
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    0,                         /* tp_dictoffset */
    0,      /* tp_init */
    0,                         /* tp_alloc */
    Pulsar_new,                 /* tp_new */
};

/**************/
/* TableRead object */
/**************/
typedef struct
{
    pyo_audio_HEAD
    PyObject *table;
    PyObject *freq;
    Stream *freq_stream;
    int loop;
    int go;
    int modebuffer[3];
    double pointerPos;
    MYFLT lastValue;
    int keepLast;
    MYFLT *trigsBuffer;
    TriggerStream *trig_stream;
    int init;
    int interp; /* 0 = default to 2, 1 = nointerp, 2 = linear, 3 = cos, 4 = cubic */
    MYFLT (*interp_func_ptr)(MYFLT *, T_SIZE_T, MYFLT, T_SIZE_T);
} TableRead;

static void
TableRead_readframes_i(TableRead *self)
{
    int i;
    MYFLT fr, inc, fpart;
    T_SIZE_T ipart;
    MYFLT *tablelist = TableStream_getData((TableStream *)self->table);
    T_SIZE_T size = TableStream_getSize((TableStream *)self->table);

    fr = PyFloat_AS_DOUBLE(self->freq);
    inc = fr * size / self->sr;

    if (self->go == 0)
        PyObject_CallMethod((PyObject *)self, "stop", NULL);

    for (i = 0; i < self->bufsize; i++)
    {
        self->trigsBuffer[i] = 0.0;

        if (self->pointerPos < 0)
        {
            if (self->init == 0)
            {
                self->trigsBuffer[i] = 1.0;

                if (self->loop == 0)
                    self->go = 0;
            }
            else
                self->init = 0;

            self->pointerPos = size + self->pointerPos;
        }
        else if (self->pointerPos >= size && self->go)
        {
            self->trigsBuffer[i] = 1.0;

            if (self->loop == 1)
                self->pointerPos -= size;
            else
                self->go = 0;
        }

        if (self->go == 1)
        {
            ipart = (T_SIZE_T)self->pointerPos;
            fpart = self->pointerPos - ipart;
            self->lastValue = self->data[i] = (*self->interp_func_ptr)(tablelist, ipart, fpart, size);
        }
        else
        {
            if (self->keepLast == 0)
                self->data[i] = 0.0;
            else
                self->data[i] = self->lastValue;
        }

        self->pointerPos += inc;
    }
}

static void
TableRead_readframes_a(TableRead *self)
{
    int i;
    MYFLT inc, fpart, sizeOnSr;
    T_SIZE_T ipart;
    MYFLT *tablelist = TableStream_getData((TableStream *)self->table);
    T_SIZE_T size = TableStream_getSize((TableStream *)self->table);

    MYFLT *fr = Stream_getData((Stream *)self->freq_stream);

    sizeOnSr = size / self->sr;

    if (self->go == 0)
        PyObject_CallMethod((PyObject *)self, "stop", NULL);

    for (i = 0; i < self->bufsize; i++)
    {
        self->trigsBuffer[i] = 0.0;

        if (self->pointerPos < 0)
        {
            if (self->init == 0)
            {
                self->trigsBuffer[i] = 1.0;

                if (self->loop == 0)
                    self->go = 0;
            }
            else
                self->init = 0;

            self->pointerPos = size + self->pointerPos;
        }
        else if (self->pointerPos >= size && self->go)
        {
            self->trigsBuffer[i] = 1.0;

            if (self->loop == 1)
                self->pointerPos -= size;
            else
                self->go = 0;
        }

        if (self->go == 1)
        {
            ipart = (T_SIZE_T)self->pointerPos;
            fpart = self->pointerPos - ipart;
            self->lastValue = self->data[i] = (*self->interp_func_ptr)(tablelist, ipart, fpart, size);
        }
        else
        {
            if (self->keepLast == 0)
                self->data[i] = 0.0;
            else
                self->data[i] = self->lastValue;
        }

        inc = fr[i] * sizeOnSr;
        self->pointerPos += inc;
    }
}

static void TableRead_postprocessing_ii(TableRead *self) { POST_PROCESSING_II };
static void TableRead_postprocessing_ai(TableRead *self) { POST_PROCESSING_AI };
static void TableRead_postprocessing_ia(TableRead *self) { POST_PROCESSING_IA };
static void TableRead_postprocessing_aa(TableRead *self) { POST_PROCESSING_AA };
static void TableRead_postprocessing_ireva(TableRead *self) { POST_PROCESSING_IREVA };
static void TableRead_postprocessing_areva(TableRead *self) { POST_PROCESSING_AREVA };
static void TableRead_postprocessing_revai(TableRead *self) { POST_PROCESSING_REVAI };
static void TableRead_postprocessing_revaa(TableRead *self) { POST_PROCESSING_REVAA };
static void TableRead_postprocessing_revareva(TableRead *self) { POST_PROCESSING_REVAREVA };

static void
TableRead_setProcMode(TableRead *self)
{
    int procmode, muladdmode;
    procmode = self->modebuffer[2];
    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;

    switch (procmode)
    {
        case 0:
            self->proc_func_ptr = TableRead_readframes_i;
            break;

        case 1:
            self->proc_func_ptr = TableRead_readframes_a;
            break;
    }

    switch (muladdmode)
    {
        case 0:
            self->muladd_func_ptr = TableRead_postprocessing_ii;
            break;

        case 1:
            self->muladd_func_ptr = TableRead_postprocessing_ai;
            break;

        case 2:
            self->muladd_func_ptr = TableRead_postprocessing_revai;
            break;

        case 10:
            self->muladd_func_ptr = TableRead_postprocessing_ia;
            break;

        case 11:
            self->muladd_func_ptr = TableRead_postprocessing_aa;
            break;

        case 12:
            self->muladd_func_ptr = TableRead_postprocessing_revaa;
            break;

        case 20:
            self->muladd_func_ptr = TableRead_postprocessing_ireva;
            break;

        case 21:
            self->muladd_func_ptr = TableRead_postprocessing_areva;
            break;

        case 22:
            self->muladd_func_ptr = TableRead_postprocessing_revareva;
            break;
    }
}

static void
TableRead_compute_next_data_frame(TableRead *self)
{
    (*self->proc_func_ptr)(self);
    (*self->muladd_func_ptr)(self);
}

static int
TableRead_traverse(TableRead *self, visitproc visit, void *arg)
{
    pyo_VISIT
    Py_VISIT(self->freq);
    return 0;
}

static int
TableRead_clear(TableRead *self)
{
    pyo_CLEAR
    Py_CLEAR(self->freq);
    return 0;
}

static void
TableRead_dealloc(TableRead* self)
{
    pyo_DEALLOC
    PyMem_RawFree(self->trigsBuffer);
    TableRead_clear(self);
    Py_TYPE(self->trig_stream)->tp_free((PyObject*)self->trig_stream);
    Py_TYPE(self->stream)->tp_free((PyObject*)self->stream);
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject *
TableRead_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    int i;
    MYFLT *tablelist;
    PyObject *tabletmp, *freqtmp = NULL, *multmp = NULL, *addtmp = NULL;
    TableRead *self;
    self = (TableRead *)type->tp_alloc(type, 0);

    self->freq = PyFloat_FromDouble(1);
    self->loop = 0;
    self->init = 1;
    self->keepLast = 0;
    self->lastValue = 0.0;
    self->modebuffer[0] = 0;
    self->modebuffer[1] = 0;
    self->modebuffer[2] = 0;
    self->pointerPos = 0.;
    self->interp = 2;

    INIT_OBJECT_COMMON
    Stream_setFunctionPtr(self->stream, TableRead_compute_next_data_frame);
    self->mode_func_ptr = TableRead_setProcMode;

    static char *kwlist[] = {"table", "freq", "loop", "interp", "mul", "add", NULL};

    if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|OiiOO", kwlist, &tabletmp, &freqtmp, &self->loop, &self->interp, &multmp, &addtmp))
        Py_RETURN_NONE;

    if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 )
    {
        PyErr_SetString(PyExc_TypeError, "\"table\" argument of TableRead must be a PyoTableObject.\n");
        Py_RETURN_NONE;
    }

    self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");

    if (freqtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setFreq", "O", freqtmp);
    }

    if (multmp)
    {
        PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
    }

    if (addtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
    }

    PyObject_CallMethod(self->server, "addStream", "O", self->stream);

    self->trigsBuffer = (MYFLT *)PyMem_RawRealloc(self->trigsBuffer, self->bufsize * sizeof(MYFLT));

    tablelist = TableStream_getData((TableStream *)self->table);

    for (i = 0; i < self->bufsize; i++)
    {
        self->trigsBuffer[i] = 0.0;
        self->data[i] = tablelist[0];
    }

    MAKE_NEW_TRIGGER_STREAM(self->trig_stream, &TriggerStreamType, NULL);
    TriggerStream_setData(self->trig_stream, self->trigsBuffer);

    (*self->mode_func_ptr)(self);

    SET_INTERP_POINTER

    self->init = 1;

    return (PyObject *)self;
}

static PyObject * TableRead_getServer(TableRead* self) { GET_SERVER };
static PyObject * TableRead_getStream(TableRead* self) { GET_STREAM };
static PyObject * TableRead_getTriggerStream(TableRead* self) { GET_TRIGGER_STREAM };
static PyObject * TableRead_setMul(TableRead *self, PyObject *arg) { SET_MUL };
static PyObject * TableRead_setAdd(TableRead *self, PyObject *arg) { SET_ADD };
static PyObject * TableRead_setSub(TableRead *self, PyObject *arg) { SET_SUB };
static PyObject * TableRead_setDiv(TableRead *self, PyObject *arg) { SET_DIV };

static PyObject * TableRead_play(TableRead *self, PyObject *args, PyObject *kwds)
{
    self->pointerPos = 0.0;
    self->init = 1;
    self->go = 1;
    PLAY
};

static PyObject * TableRead_out(TableRead *self, PyObject *args, PyObject *kwds)
{
    self->pointerPos = 0.0;
    self->init = 1;
    self->go = 1;
    OUT
};
static PyObject * TableRead_stop(TableRead *self, PyObject *args, PyObject *kwds)
{
    int i, nearestBuf = 0;
    float wait = 0.0;

    static char *kwlist[] = {"wait", NULL};

    if (! PyArg_ParseTupleAndKeywords(args, kwds, "|f", kwlist, &wait))
        return PyLong_FromLong(-1);

    if (wait == 0)
    {
        self->go = 0;
        Stream_setStreamActive(self->stream, 0);
        Stream_setStreamChnl(self->stream, 0);
        Stream_setStreamToDac(self->stream, 0);

        if (self->keepLast == 0)
        {
            for (i = 0; i < self->bufsize; i++)
            {
                self->data[i] = 0;
            }
        }
        else
        {
            for (i = 0; i < self->bufsize; i++)
            {
                self->data[i] = self->lastValue;
            }
        }
    }
    else
    {
        Stream_resetBufferCount(self->stream);
        nearestBuf = (int)roundf((wait * self->sr) / self->bufsize + 0.5);
        Stream_setDuration(self->stream, nearestBuf);
    }

    Py_RETURN_NONE;
};

static PyObject * TableRead_multiply(TableRead *self, PyObject *arg) { MULTIPLY };
static PyObject * TableRead_inplace_multiply(TableRead *self, PyObject *arg) { INPLACE_MULTIPLY };
static PyObject * TableRead_add(TableRead *self, PyObject *arg) { ADD };
static PyObject * TableRead_inplace_add(TableRead *self, PyObject *arg) { INPLACE_ADD };
static PyObject * TableRead_sub(TableRead *self, PyObject *arg) { SUB };
static PyObject * TableRead_inplace_sub(TableRead *self, PyObject *arg) { INPLACE_SUB };
static PyObject * TableRead_div(TableRead *self, PyObject *arg) { DIV };
static PyObject * TableRead_inplace_div(TableRead *self, PyObject *arg) { INPLACE_DIV };

static PyObject *
TableRead_getTable(TableRead* self)
{
    Py_INCREF(self->table);
    return self->table;
};

static PyObject *
TableRead_setTable(TableRead *self, PyObject *arg)
{
    ASSERT_ARG_NOT_NULL

    Py_DECREF(self->table);
    self->table = PyObject_CallMethod((PyObject *)arg, "getTableStream", "");

    Py_RETURN_NONE;
}

static PyObject * TableRead_setFreq(TableRead *self, PyObject *arg) { SET_PARAM(self->freq, self->freq_stream, 2); }

static PyObject *
TableRead_setLoop(TableRead *self, PyObject *arg)
{
    ASSERT_ARG_NOT_NULL

    self->loop = PyLong_AsLong(arg);

    Py_RETURN_NONE;
}

static PyObject *
TableRead_setInterp(TableRead *self, PyObject *arg)
{
    ASSERT_ARG_NOT_NULL

    if (PyNumber_Check(arg))
    {
        self->interp = PyLong_AsLong(PyNumber_Long(arg));
    }

    SET_INTERP_POINTER

    Py_RETURN_NONE;
}

static PyObject *
TableRead_setKeepLast(TableRead *self, PyObject *arg)
{
    ASSERT_ARG_NOT_NULL

    self->keepLast = PyLong_AsLong(arg);

    Py_RETURN_NONE;
}

static PyObject *
TableRead_reset(TableRead *self)
{
    self->pointerPos = 0.0;
    Py_RETURN_NONE;
}

static PyMemberDef TableRead_members[] =
{
    {"server", T_OBJECT_EX, offsetof(TableRead, server), 0, "Pyo server."},
    {"stream", T_OBJECT_EX, offsetof(TableRead, stream), 0, "Stream object."},
    {"trig_stream", T_OBJECT_EX, offsetof(TableRead, trig_stream), 0, "Trigger Stream object."},
    {"table", T_OBJECT_EX, offsetof(TableRead, table), 0, "Waveform table."},
    {"freq", T_OBJECT_EX, offsetof(TableRead, freq), 0, "Frequency in cycle per second."},
    {"mul", T_OBJECT_EX, offsetof(TableRead, mul), 0, "Mul factor."},
    {"add", T_OBJECT_EX, offsetof(TableRead, add), 0, "Add factor."},
    {NULL}  /* Sentinel */
};

static PyMethodDef TableRead_methods[] =
{
    {"getTable", (PyCFunction)TableRead_getTable, METH_NOARGS, "Returns waveform table object."},
    {"getServer", (PyCFunction)TableRead_getServer, METH_NOARGS, "Returns server object."},
    {"_getStream", (PyCFunction)TableRead_getStream, METH_NOARGS, "Returns stream object."},
    {"_getTriggerStream", (PyCFunction)TableRead_getTriggerStream, METH_NOARGS, "Returns trigger stream object."},
    {"play", (PyCFunction)TableRead_play, METH_VARARGS | METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
    {"out", (PyCFunction)TableRead_out, METH_VARARGS | METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
    {"stop", (PyCFunction)TableRead_stop, METH_VARARGS | METH_KEYWORDS, "Stops computing."},
    {"setTable", (PyCFunction)TableRead_setTable, METH_O, "Sets oscillator table."},
    {"setFreq", (PyCFunction)TableRead_setFreq, METH_O, "Sets oscillator frequency in cycle per second."},
    {"setLoop", (PyCFunction)TableRead_setLoop, METH_O, "Sets the looping mode."},
    {"setInterp", (PyCFunction)TableRead_setInterp, METH_O, "Sets reader interpolation mode."},
    {"setKeepLast", (PyCFunction)TableRead_setKeepLast, METH_O, "Sets keepLast mode."},
    {"reset", (PyCFunction)TableRead_reset, METH_NOARGS, "Resets pointer position to 0."},
    {"setMul", (PyCFunction)TableRead_setMul, METH_O, "Sets oscillator mul factor."},
    {"setAdd", (PyCFunction)TableRead_setAdd, METH_O, "Sets oscillator add factor."},
    {"setSub", (PyCFunction)TableRead_setSub, METH_O, "Sets oscillator inverse add factor."},
    {"setDiv", (PyCFunction)TableRead_setDiv, METH_O, "Sets inverse mul factor."},
    {NULL}  /* Sentinel */
};

static PyNumberMethods TableRead_as_number =
{
    (binaryfunc)TableRead_add,                      /*nb_add*/
    (binaryfunc)TableRead_sub,                 /*nb_subtract*/
    (binaryfunc)TableRead_multiply,                 /*nb_multiply*/
    0,                /*nb_remainder*/
    0,                   /*nb_divmod*/
    0,                   /*nb_power*/
    0,                  /*nb_neg*/
    0,                /*nb_pos*/
    0,                  /*(unaryfunc)array_abs,*/
    0,                    /*nb_nonzero*/
    0,                    /*nb_invert*/
    0,               /*nb_lshift*/
    0,              /*nb_rshift*/
    0,              /*nb_and*/
    0,              /*nb_xor*/
    0,               /*nb_or*/
    0,                       /*nb_int*/
    0,                      /*nb_long*/
    0,                     /*nb_float*/
    (binaryfunc)TableRead_inplace_add,              /*inplace_add*/
    (binaryfunc)TableRead_inplace_sub,         /*inplace_subtract*/
    (binaryfunc)TableRead_inplace_multiply,         /*inplace_multiply*/
    0,        /*inplace_remainder*/
    0,           /*inplace_power*/
    0,       /*inplace_lshift*/
    0,      /*inplace_rshift*/
    0,      /*inplace_and*/
    0,      /*inplace_xor*/
    0,       /*inplace_or*/
    0,             /*nb_floor_divide*/
    (binaryfunc)TableRead_div,                       /*nb_true_divide*/
    0,     /*nb_inplace_floor_divide*/
    (binaryfunc)TableRead_inplace_div,                       /*nb_inplace_true_divide*/
    0,                     /* nb_index */
};

PyTypeObject TableReadType =
{
    PyVarObject_HEAD_INIT(NULL, 0)
    "_pyo.TableRead_base",         /*tp_name*/
    sizeof(TableRead),         /*tp_basicsize*/
    0,                         /*tp_itemsize*/
    (destructor)TableRead_dealloc, /*tp_dealloc*/
    0,                         /*tp_print*/
    0,                         /*tp_getattr*/
    0,                         /*tp_setattr*/
    0,                         /*tp_as_async (tp_compare in Python 2)*/
    0,                         /*tp_repr*/
    &TableRead_as_number,             /*tp_as_number*/
    0,                         /*tp_as_sequence*/
    0,                         /*tp_as_mapping*/
    0,                         /*tp_hash */
    0,                         /*tp_call*/
    0,                         /*tp_str*/
    0,                         /*tp_getattro*/
    0,                         /*tp_setattro*/
    0,                         /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
    "TableRead objects. Generates an oscillatory waveform.",           /* tp_doc */
    (traverseproc)TableRead_traverse,   /* tp_traverse */
    (inquiry)TableRead_clear,           /* tp_clear */
    0,                     /* tp_richcompare */
    0,                     /* tp_weaklistoffset */
    0,                     /* tp_iter */
    0,                     /* tp_iternext */
    TableRead_methods,             /* tp_methods */
    TableRead_members,             /* tp_members */
    0,                      /* tp_getset */
    0,                         /* tp_base */
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    0,                         /* tp_dictoffset */
    0,      /* tp_init */
    0,                         /* tp_alloc */
    TableRead_new,                 /* tp_new */
};

/*************/
/* Fm object */
/*************/
typedef struct
{
    pyo_audio_HEAD
    PyObject *car;
    Stream *car_stream;
    PyObject *ratio;
    Stream *ratio_stream;
    PyObject *index;
    Stream *index_stream;
    int modebuffer[5];
    MYFLT pointerPos_car;
    MYFLT pointerPos_mod;
    MYFLT scaleFactor;
} Fm;

static void
Fm_readframes_iii(Fm *self)
{
    MYFLT mod_freq, mod_amp, mod_delta, mod_val, car_freq, car_delta, fpart;
    int i, ipart;

    MYFLT car = PyFloat_AS_DOUBLE(self->car);
    MYFLT rat = PyFloat_AS_DOUBLE(self->ratio);
    MYFLT ind = PyFloat_AS_DOUBLE(self->index);

    mod_freq = car * rat;
    mod_amp = mod_freq * ind;
    mod_delta = mod_freq * self->scaleFactor;

    for (i = 0; i < self->bufsize; i++)
    {
        self->pointerPos_mod = Sine_clip(self->pointerPos_mod);
        ipart = (int)self->pointerPos_mod;
        fpart = self->pointerPos_mod - ipart;
        mod_val = mod_amp * (SINE_ARRAY[ipart] + (SINE_ARRAY[ipart + 1] - SINE_ARRAY[ipart]) * fpart);
        self->pointerPos_mod += mod_delta;

        car_freq = car + mod_val;
        car_delta = car_freq * self->scaleFactor;
        self->pointerPos_car = Sine_clip(self->pointerPos_car);
        ipart = (int)self->pointerPos_car;
        fpart = self->pointerPos_car - ipart;
        self->data[i] = SINE_ARRAY[ipart] + (SINE_ARRAY[ipart + 1] - SINE_ARRAY[ipart]) * fpart;
        self->pointerPos_car += car_delta;
    }
}

static void
Fm_readframes_aii(Fm *self)
{
    MYFLT mod_freq, mod_amp, mod_delta, mod_val, car_freq, car_delta, fpart;
    int i, ipart;

    MYFLT *car = Stream_getData((Stream *)self->car_stream);
    MYFLT rat = PyFloat_AS_DOUBLE(self->ratio);
    MYFLT ind = PyFloat_AS_DOUBLE(self->index);

    for (i = 0; i < self->bufsize; i++)
    {
        mod_freq = car[i] * rat;
        mod_amp = mod_freq * ind;
        mod_delta = mod_freq * self->scaleFactor;
        self->pointerPos_mod = Sine_clip(self->pointerPos_mod);
        ipart = (int)self->pointerPos_mod;
        fpart = self->pointerPos_mod - ipart;
        mod_val = mod_amp * (SINE_ARRAY[ipart] + (SINE_ARRAY[ipart + 1] - SINE_ARRAY[ipart]) * fpart);
        self->pointerPos_mod += mod_delta;

        car_freq = car[i] + mod_val;
        car_delta = car_freq * self->scaleFactor;
        self->pointerPos_car = Sine_clip(self->pointerPos_car);
        ipart = (int)self->pointerPos_car;
        fpart = self->pointerPos_car - ipart;
        self->data[i] = SINE_ARRAY[ipart] + (SINE_ARRAY[ipart + 1] - SINE_ARRAY[ipart]) * fpart;
        self->pointerPos_car += car_delta;
    }
}

static void
Fm_readframes_iai(Fm *self)
{
    MYFLT mod_freq, mod_amp, mod_delta, mod_val, car_freq, car_delta, fpart;
    int i, ipart;

    MYFLT car = PyFloat_AS_DOUBLE(self->car);
    MYFLT *rat = Stream_getData((Stream *)self->ratio_stream);
    MYFLT ind = PyFloat_AS_DOUBLE(self->index);

    for (i = 0; i < self->bufsize; i++)
    {
        mod_freq = car * rat[i];
        mod_amp = mod_freq * ind;
        mod_delta = mod_freq * self->scaleFactor;
        self->pointerPos_mod = Sine_clip(self->pointerPos_mod);
        ipart = (int)self->pointerPos_mod;
        fpart = self->pointerPos_mod - ipart;
        mod_val = mod_amp * (SINE_ARRAY[ipart] + (SINE_ARRAY[ipart + 1] - SINE_ARRAY[ipart]) * fpart);
        self->pointerPos_mod += mod_delta;

        car_freq = car + mod_val;
        car_delta = car_freq * self->scaleFactor;
        self->pointerPos_car = Sine_clip(self->pointerPos_car);
        ipart = (int)self->pointerPos_car;
        fpart = self->pointerPos_car - ipart;
        self->data[i] = SINE_ARRAY[ipart] + (SINE_ARRAY[ipart + 1] - SINE_ARRAY[ipart]) * fpart;
        self->pointerPos_car += car_delta;
    }
}

static void
Fm_readframes_aai(Fm *self)
{
    MYFLT mod_freq, mod_amp, mod_delta, mod_val, car_freq, car_delta, fpart;
    int i, ipart;

    MYFLT *car = Stream_getData((Stream *)self->car_stream);
    MYFLT *rat = Stream_getData((Stream *)self->ratio_stream);
    MYFLT ind = PyFloat_AS_DOUBLE(self->index);

    for (i = 0; i < self->bufsize; i++)
    {
        mod_freq = car[i] * rat[i];
        mod_amp = mod_freq * ind;
        mod_delta = mod_freq * self->scaleFactor;
        self->pointerPos_mod = Sine_clip(self->pointerPos_mod);
        ipart = (int)self->pointerPos_mod;
        fpart = self->pointerPos_mod - ipart;
        mod_val = mod_amp * (SINE_ARRAY[ipart] + (SINE_ARRAY[ipart + 1] - SINE_ARRAY[ipart]) * fpart);
        self->pointerPos_mod += mod_delta;

        car_freq = car[i] + mod_val;
        car_delta = car_freq * self->scaleFactor;
        self->pointerPos_car = Sine_clip(self->pointerPos_car);
        ipart = (int)self->pointerPos_car;
        fpart = self->pointerPos_car - ipart;
        self->data[i] = SINE_ARRAY[ipart] + (SINE_ARRAY[ipart + 1] - SINE_ARRAY[ipart]) * fpart;
        self->pointerPos_car += car_delta;
    }
}

static void
Fm_readframes_iia(Fm *self)
{
    MYFLT mod_freq, mod_amp, mod_delta, mod_val, car_freq, car_delta, fpart;
    int i, ipart;

    MYFLT car = PyFloat_AS_DOUBLE(self->car);
    MYFLT rat = PyFloat_AS_DOUBLE(self->ratio);
    MYFLT *ind = Stream_getData((Stream *)self->index_stream);

    mod_freq = car * rat;
    mod_delta = mod_freq * self->scaleFactor;

    for (i = 0; i < self->bufsize; i++)
    {
        mod_amp = mod_freq * ind[i];
        self->pointerPos_mod = Sine_clip(self->pointerPos_mod);
        ipart = (int)self->pointerPos_mod;
        fpart = self->pointerPos_mod - ipart;
        mod_val = mod_amp * (SINE_ARRAY[ipart] + (SINE_ARRAY[ipart + 1] - SINE_ARRAY[ipart]) * fpart);
        self->pointerPos_mod += mod_delta;

        car_freq = car + mod_val;
        car_delta = car_freq * self->scaleFactor;
        self->pointerPos_car = Sine_clip(self->pointerPos_car);
        ipart = (int)self->pointerPos_car;
        fpart = self->pointerPos_car - ipart;
        self->data[i] = SINE_ARRAY[ipart] + (SINE_ARRAY[ipart + 1] - SINE_ARRAY[ipart]) * fpart;
        self->pointerPos_car += car_delta;
    }
}

static void
Fm_readframes_aia(Fm *self)
{
    MYFLT mod_freq, mod_amp, mod_delta, mod_val, car_freq, car_delta, fpart;
    int i, ipart;

    MYFLT *car = Stream_getData((Stream *)self->car_stream);
    MYFLT rat = PyFloat_AS_DOUBLE(self->ratio);
    MYFLT *ind = Stream_getData((Stream *)self->index_stream);

    for (i = 0; i < self->bufsize; i++)
    {
        mod_freq = car[i] * rat;
        mod_amp = mod_freq * ind[i];
        mod_delta = mod_freq * self->scaleFactor;
        self->pointerPos_mod = Sine_clip(self->pointerPos_mod);
        ipart = (int)self->pointerPos_mod;
        fpart = self->pointerPos_mod - ipart;
        mod_val = mod_amp * (SINE_ARRAY[ipart] + (SINE_ARRAY[ipart + 1] - SINE_ARRAY[ipart]) * fpart);
        self->pointerPos_mod += mod_delta;

        car_freq = car[i] + mod_val;
        car_delta = car_freq * self->scaleFactor;
        self->pointerPos_car = Sine_clip(self->pointerPos_car);
        ipart = (int)self->pointerPos_car;
        fpart = self->pointerPos_car - ipart;
        self->data[i] = SINE_ARRAY[ipart] + (SINE_ARRAY[ipart + 1] - SINE_ARRAY[ipart]) * fpart;
        self->pointerPos_car += car_delta;
    }
}

static void
Fm_readframes_iaa(Fm *self)
{
    MYFLT mod_freq, mod_amp, mod_delta, mod_val, car_freq, car_delta, fpart;
    int i, ipart;

    MYFLT car = PyFloat_AS_DOUBLE(self->car);
    MYFLT *rat = Stream_getData((Stream *)self->ratio_stream);
    MYFLT *ind = Stream_getData((Stream *)self->index_stream);

    for (i = 0; i < self->bufsize; i++)
    {
        mod_freq = car * rat[i];
        mod_amp = mod_freq * ind[i];
        mod_delta = mod_freq * self->scaleFactor;
        self->pointerPos_mod = Sine_clip(self->pointerPos_mod);
        ipart = (int)self->pointerPos_mod;
        fpart = self->pointerPos_mod - ipart;
        mod_val = mod_amp * (SINE_ARRAY[ipart] + (SINE_ARRAY[ipart + 1] - SINE_ARRAY[ipart]) * fpart);
        self->pointerPos_mod += mod_delta;

        car_freq = car + mod_val;
        car_delta = car_freq * self->scaleFactor;
        self->pointerPos_car = Sine_clip(self->pointerPos_car);
        ipart = (int)self->pointerPos_car;
        fpart = self->pointerPos_car - ipart;
        self->data[i] = SINE_ARRAY[ipart] + (SINE_ARRAY[ipart + 1] - SINE_ARRAY[ipart]) * fpart;
        self->pointerPos_car += car_delta;
    }
}

static void
Fm_readframes_aaa(Fm *self)
{
    MYFLT mod_freq, mod_amp, mod_delta, mod_val, car_freq, car_delta, fpart;
    int i, ipart;

    MYFLT *car = Stream_getData((Stream *)self->car_stream);
    MYFLT *rat = Stream_getData((Stream *)self->ratio_stream);
    MYFLT *ind = Stream_getData((Stream *)self->index_stream);

    for (i = 0; i < self->bufsize; i++)
    {
        mod_freq = car[i] * rat[i];
        mod_amp = mod_freq * ind[i];
        mod_delta = mod_freq * self->scaleFactor;
        self->pointerPos_mod = Sine_clip(self->pointerPos_mod);
        ipart = (int)self->pointerPos_mod;
        fpart = self->pointerPos_mod - ipart;
        mod_val = mod_amp * (SINE_ARRAY[ipart] + (SINE_ARRAY[ipart + 1] - SINE_ARRAY[ipart]) * fpart);
        self->pointerPos_mod += mod_delta;

        car_freq = car[i] + mod_val;
        car_delta = car_freq * self->scaleFactor;
        self->pointerPos_car = Sine_clip(self->pointerPos_car);
        ipart = (int)self->pointerPos_car;
        fpart = self->pointerPos_car - ipart;
        self->data[i] = SINE_ARRAY[ipart] + (SINE_ARRAY[ipart + 1] - SINE_ARRAY[ipart]) * fpart;
        self->pointerPos_car += car_delta;
    }
}

static void Fm_postprocessing_ii(Fm *self) { POST_PROCESSING_II };
static void Fm_postprocessing_ai(Fm *self) { POST_PROCESSING_AI };
static void Fm_postprocessing_ia(Fm *self) { POST_PROCESSING_IA };
static void Fm_postprocessing_aa(Fm *self) { POST_PROCESSING_AA };
static void Fm_postprocessing_ireva(Fm *self) { POST_PROCESSING_IREVA };
static void Fm_postprocessing_areva(Fm *self) { POST_PROCESSING_AREVA };
static void Fm_postprocessing_revai(Fm *self) { POST_PROCESSING_REVAI };
static void Fm_postprocessing_revaa(Fm *self) { POST_PROCESSING_REVAA };
static void Fm_postprocessing_revareva(Fm *self) { POST_PROCESSING_REVAREVA };

static void
Fm_setProcMode(Fm *self)
{
    int procmode, muladdmode;
    procmode = self->modebuffer[2] + self->modebuffer[3] * 10 + self->modebuffer[4] * 100;
    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;

    switch (procmode)
    {
        case 0:
            self->proc_func_ptr = Fm_readframes_iii;
            break;

        case 1:
            self->proc_func_ptr = Fm_readframes_aii;
            break;

        case 10:
            self->proc_func_ptr = Fm_readframes_iai;
            break;

        case 11:
            self->proc_func_ptr = Fm_readframes_aai;
            break;

        case 100:
            self->proc_func_ptr = Fm_readframes_iia;
            break;

        case 101:
            self->proc_func_ptr = Fm_readframes_aia;
            break;

        case 110:
            self->proc_func_ptr = Fm_readframes_iaa;
            break;

        case 111:
            self->proc_func_ptr = Fm_readframes_aaa;
            break;
    }

    switch (muladdmode)
    {
        case 0:
            self->muladd_func_ptr = Fm_postprocessing_ii;
            break;

        case 1:
            self->muladd_func_ptr = Fm_postprocessing_ai;
            break;

        case 2:
            self->muladd_func_ptr = Fm_postprocessing_revai;
            break;

        case 10:
            self->muladd_func_ptr = Fm_postprocessing_ia;
            break;

        case 11:
            self->muladd_func_ptr = Fm_postprocessing_aa;
            break;

        case 12:
            self->muladd_func_ptr = Fm_postprocessing_revaa;
            break;

        case 20:
            self->muladd_func_ptr = Fm_postprocessing_ireva;
            break;

        case 21:
            self->muladd_func_ptr = Fm_postprocessing_areva;
            break;

        case 22:
            self->muladd_func_ptr = Fm_postprocessing_revareva;
            break;
    }
}

static void
Fm_compute_next_data_frame(Fm *self)
{
    (*self->proc_func_ptr)(self);
    (*self->muladd_func_ptr)(self);
}

static int
Fm_traverse(Fm *self, visitproc visit, void *arg)
{
    pyo_VISIT
    Py_VISIT(self->car);
    Py_VISIT(self->ratio);
    Py_VISIT(self->index);
    return 0;
}

static int
Fm_clear(Fm *self)
{
    pyo_CLEAR
    Py_CLEAR(self->car);
    Py_CLEAR(self->ratio);
    Py_CLEAR(self->index);
    return 0;
}

static void
Fm_dealloc(Fm* self)
{
    pyo_DEALLOC
    Fm_clear(self);
    Py_TYPE(self->stream)->tp_free((PyObject*)self->stream);
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject *
Fm_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    int i;
    PyObject *cartmp = NULL, *ratiotmp = NULL, *indextmp = NULL, *multmp = NULL, *addtmp = NULL;
    Fm *self;
    self = (Fm *)type->tp_alloc(type, 0);

    self->car = PyFloat_FromDouble(100);
    self->ratio = PyFloat_FromDouble(0.5);
    self->index = PyFloat_FromDouble(5);
    self->modebuffer[0] = 0;
    self->modebuffer[1] = 0;
    self->modebuffer[2] = 0;
    self->modebuffer[3] = 0;
    self->modebuffer[4] = 0;
    self->pointerPos_car = self->pointerPos_mod = 0.;

    INIT_OBJECT_COMMON
    Stream_setFunctionPtr(self->stream, Fm_compute_next_data_frame);
    self->mode_func_ptr = Fm_setProcMode;

    self->scaleFactor = 512.0 / self->sr;

    static char *kwlist[] = {"carrier", "ratio", "index", "mul", "add", NULL};

    if (! PyArg_ParseTupleAndKeywords(args, kwds, "|OOOOO", kwlist, &cartmp, &ratiotmp, &indextmp, &multmp, &addtmp))
        Py_RETURN_NONE;

    if (cartmp)
    {
        PyObject_CallMethod((PyObject *)self, "setCarrier", "O", cartmp);
    }

    if (ratiotmp)
    {
        PyObject_CallMethod((PyObject *)self, "setRatio", "O", ratiotmp);
    }

    if (indextmp)
    {
        PyObject_CallMethod((PyObject *)self, "setIndex", "O", indextmp);
    }

    if (multmp)
    {
        PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
    }

    if (addtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
    }

    PyObject_CallMethod(self->server, "addStream", "O", self->stream);

    (*self->mode_func_ptr)(self);

    return (PyObject *)self;
}

static PyObject * Fm_getServer(Fm* self) { GET_SERVER };
static PyObject * Fm_getStream(Fm* self) { GET_STREAM };
static PyObject * Fm_setMul(Fm *self, PyObject *arg) { SET_MUL };
static PyObject * Fm_setAdd(Fm *self, PyObject *arg) { SET_ADD };
static PyObject * Fm_setSub(Fm *self, PyObject *arg) { SET_SUB };
static PyObject * Fm_setDiv(Fm *self, PyObject *arg) { SET_DIV };

static PyObject * Fm_play(Fm *self, PyObject *args, PyObject *kwds) { PLAY };
static PyObject * Fm_out(Fm *self, PyObject *args, PyObject *kwds) { OUT };
static PyObject * Fm_stop(Fm *self, PyObject *args, PyObject *kwds) { STOP };

static PyObject * Fm_multiply(Fm *self, PyObject *arg) { MULTIPLY };
static PyObject * Fm_inplace_multiply(Fm *self, PyObject *arg) { INPLACE_MULTIPLY };
static PyObject * Fm_add(Fm *self, PyObject *arg) { ADD };
static PyObject * Fm_inplace_add(Fm *self, PyObject *arg) { INPLACE_ADD };
static PyObject * Fm_sub(Fm *self, PyObject *arg) { SUB };
static PyObject * Fm_inplace_sub(Fm *self, PyObject *arg) { INPLACE_SUB };
static PyObject * Fm_div(Fm *self, PyObject *arg) { DIV };
static PyObject * Fm_inplace_div(Fm *self, PyObject *arg) { INPLACE_DIV };

static PyObject * Fm_setCarrier(Fm *self, PyObject *arg) { SET_PARAM(self->car, self->car_stream, 2); }
static PyObject * Fm_setRatio(Fm *self, PyObject *arg) { SET_PARAM(self->ratio, self->ratio_stream, 3); }
static PyObject * Fm_setIndex(Fm *self, PyObject *arg) { SET_PARAM(self->index, self->index_stream, 4); }

static PyMemberDef Fm_members[] =
{
    {"server", T_OBJECT_EX, offsetof(Fm, server), 0, "Pyo server."},
    {"stream", T_OBJECT_EX, offsetof(Fm, stream), 0, "Stream object."},
    {"carrier", T_OBJECT_EX, offsetof(Fm, car), 0, "Frequency in cycle per second."},
    {"ratio", T_OBJECT_EX, offsetof(Fm, ratio), 0, "Ratio carrier:modulator (mod freq = car*mod)."},
    {"index", T_OBJECT_EX, offsetof(Fm, index), 0, "Modulation index (mod amp = mod freq*index)."},
    {"mul", T_OBJECT_EX, offsetof(Fm, mul), 0, "Mul factor."},
    {"add", T_OBJECT_EX, offsetof(Fm, add), 0, "Add factor."},
    {NULL}  /* Sentinel */
};

static PyMethodDef Fm_methods[] =
{
    {"getServer", (PyCFunction)Fm_getServer, METH_NOARGS, "Returns server object."},
    {"_getStream", (PyCFunction)Fm_getStream, METH_NOARGS, "Returns stream object."},
    {"play", (PyCFunction)Fm_play, METH_VARARGS | METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
    {"out", (PyCFunction)Fm_out, METH_VARARGS | METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
    {"stop", (PyCFunction)Fm_stop, METH_VARARGS | METH_KEYWORDS, "Stops computing."},
    {"setCarrier", (PyCFunction)Fm_setCarrier, METH_O, "Sets carrier frequency in cycle per second."},
    {"setRatio", (PyCFunction)Fm_setRatio, METH_O, "Sets car:mod ratio."},
    {"setIndex", (PyCFunction)Fm_setIndex, METH_O, "Sets modulation index."},
    {"setMul", (PyCFunction)Fm_setMul, METH_O, "Sets Fm mul factor."},
    {"setAdd", (PyCFunction)Fm_setAdd, METH_O, "Sets Fm add factor."},
    {"setSub", (PyCFunction)Fm_setSub, METH_O, "Sets inverse add factor."},
    {"setDiv", (PyCFunction)Fm_setDiv, METH_O, "Sets inverse mul factor."},
    {NULL}  /* Sentinel */
};

static PyNumberMethods Fm_as_number =
{
    (binaryfunc)Fm_add,                      /*nb_add*/
    (binaryfunc)Fm_sub,                 /*nb_subtract*/
    (binaryfunc)Fm_multiply,                 /*nb_multiply*/
    0,                /*nb_remainder*/
    0,                   /*nb_divmod*/
    0,                   /*nb_power*/
    0,                  /*nb_neg*/
    0,                /*nb_pos*/
    0,                  /*(unaryfunc)array_abs*/
    0,                    /*nb_nonzero*/
    0,                    /*nb_invert*/
    0,               /*nb_lshift*/
    0,              /*nb_rshift*/
    0,              /*nb_and*/
    0,              /*nb_xor*/
    0,               /*nb_or*/
    0,                       /*nb_int*/
    0,                      /*nb_long*/
    0,                     /*nb_float*/
    (binaryfunc)Fm_inplace_add,              /*inplace_add*/
    (binaryfunc)Fm_inplace_sub,         /*inplace_subtract*/
    (binaryfunc)Fm_inplace_multiply,         /*inplace_multiply*/
    0,        /*inplace_remainder*/
    0,           /*inplace_power*/
    0,       /*inplace_lshift*/
    0,      /*inplace_rshift*/
    0,      /*inplace_and*/
    0,      /*inplace_xor*/
    0,       /*inplace_or*/
    0,             /*nb_floor_divide*/
    (binaryfunc)Fm_div,                       /*nb_true_divide*/
    0,     /*nb_inplace_floor_divide*/
    (binaryfunc)Fm_inplace_div,                       /*nb_inplace_true_divide*/
    0,                     /* nb_index */
};

PyTypeObject FmType =
{
    PyVarObject_HEAD_INIT(NULL, 0)
    "_pyo.Fm_base",         /*tp_name*/
    sizeof(Fm),         /*tp_basicsize*/
    0,                         /*tp_itemsize*/
    (destructor)Fm_dealloc, /*tp_dealloc*/
    0,                         /*tp_print*/
    0,                         /*tp_getattr*/
    0,                         /*tp_setattr*/
    0,                         /*tp_as_async (tp_compare in Python 2)*/
    0,                         /*tp_repr*/
    &Fm_as_number,             /*tp_as_number*/
    0,                         /*tp_as_sequence*/
    0,                         /*tp_as_mapping*/
    0,                         /*tp_hash */
    0,                         /*tp_call*/
    0,                         /*tp_str*/
    0,                         /*tp_getattro*/
    0,                         /*tp_setattro*/
    0,                         /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,  /*tp_flags*/
    "Fm objects. Generates a frequency modulation synthesis.",           /* tp_doc */
    (traverseproc)Fm_traverse,   /* tp_traverse */
    (inquiry)Fm_clear,           /* tp_clear */
    0,                     /* tp_richcompare */
    0,                     /* tp_weaklistoffset */
    0,                     /* tp_iter */
    0,                     /* tp_iternext */
    Fm_methods,             /* tp_methods */
    Fm_members,             /* tp_members */
    0,                      /* tp_getset */
    0,                         /* tp_base */
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    0,                         /* tp_dictoffset */
    0,      /* tp_init */
    0,                         /* tp_alloc */
    Fm_new,                 /* tp_new */
};

/*************/
/* CrossFm object */
/*************/
typedef struct
{
    pyo_audio_HEAD
    PyObject *car;
    Stream *car_stream;
    PyObject *ratio;
    Stream *ratio_stream;
    PyObject *ind1;
    Stream *ind1_stream;
    PyObject *ind2;
    Stream *ind2_stream;
    int modebuffer[6];
    MYFLT pointerPos_car;
    MYFLT pointerPos_mod;
    MYFLT scaleFactor;
    MYFLT car_val;
} CrossFm;

static void
CrossFm_readframes(CrossFm *self)
{
    MYFLT mod_freq, mod_amp, mod_delta, mod_val, car_freq, car_amp, car_delta, fpart;
    int i, ipart;
    MYFLT car[self->bufsize];
    MYFLT rat[self->bufsize];
    MYFLT ind1[self->bufsize];
    MYFLT ind2[self->bufsize];

    if (self->modebuffer[2] == 0)
    {
        MYFLT tmpcar = PyFloat_AS_DOUBLE(self->car);

        for (i = 0; i < self->bufsize; i++)
        {
            car[i] = tmpcar;
        }
    }
    else
    {
        MYFLT *tmpcar = Stream_getData((Stream *)self->car_stream);

        for (i = 0; i < self->bufsize; i++)
        {
            car[i] = tmpcar[i];
        }
    }

    if (self->modebuffer[3] == 0)
    {
        MYFLT tmprat = PyFloat_AS_DOUBLE(self->ratio);

        for (i = 0; i < self->bufsize; i++)
        {
            rat[i] = tmprat;
        }
    }
    else
    {
        MYFLT *tmprat = Stream_getData((Stream *)self->ratio_stream);

        for (i = 0; i < self->bufsize; i++)
        {
            rat[i] = tmprat[i];
        }
    }

    if (self->modebuffer[4] == 0)
    {
        MYFLT tmpind1 = PyFloat_AS_DOUBLE(self->ind1);

        for (i = 0; i < self->bufsize; i++)
        {
            ind1[i] = tmpind1;
        }
    }
    else
    {
        MYFLT *tmpind1 = Stream_getData((Stream *)self->ind1_stream);

        for (i = 0; i < self->bufsize; i++)
        {
            ind1[i] = tmpind1[i];
        }
    }

    if (self->modebuffer[5] == 0)
    {
        MYFLT tmpind2 = PyFloat_AS_DOUBLE(self->ind2);

        for (i = 0; i < self->bufsize; i++)
        {
            ind2[i] = tmpind2;
        }
    }
    else
    {
        MYFLT *tmpind2 = Stream_getData((Stream *)self->ind2_stream);

        for (i = 0; i < self->bufsize; i++)
        {
            ind2[i] = tmpind2[i];
        }
    }

    for (i = 0; i < self->bufsize; i++)
    {
        car_amp = car[i] * ind1[i];
        mod_freq = car[i] * rat[i];
        mod_amp = mod_freq * ind2[i];
        mod_delta = (mod_freq + self->car_val * car_amp) * self->scaleFactor;
        self->pointerPos_mod = Sine_clip(self->pointerPos_mod);
        ipart = (int)self->pointerPos_mod;
        fpart = self->pointerPos_mod - ipart;
        mod_val = SINE_ARRAY[ipart] + (SINE_ARRAY[ipart + 1] - SINE_ARRAY[ipart]) * fpart;
        self->pointerPos_mod += mod_delta;

        car_freq = car[i] + (mod_val * mod_amp);
        car_delta = car_freq * self->scaleFactor;
        self->pointerPos_car = Sine_clip(self->pointerPos_car);
        ipart = (int)self->pointerPos_car;
        fpart = self->pointerPos_car - ipart;
        self->car_val = SINE_ARRAY[ipart] + (SINE_ARRAY[ipart + 1] - SINE_ARRAY[ipart]) * fpart;
        self->pointerPos_car += car_delta;
        self->data[i] = (self->car_val + mod_val) * 0.5;
    }
}

static void CrossFm_postprocessing_ii(CrossFm *self) { POST_PROCESSING_II };
static void CrossFm_postprocessing_ai(CrossFm *self) { POST_PROCESSING_AI };
static void CrossFm_postprocessing_ia(CrossFm *self) { POST_PROCESSING_IA };
static void CrossFm_postprocessing_aa(CrossFm *self) { POST_PROCESSING_AA };
static void CrossFm_postprocessing_ireva(CrossFm *self) { POST_PROCESSING_IREVA };
static void CrossFm_postprocessing_areva(CrossFm *self) { POST_PROCESSING_AREVA };
static void CrossFm_postprocessing_revai(CrossFm *self) { POST_PROCESSING_REVAI };
static void CrossFm_postprocessing_revaa(CrossFm *self) { POST_PROCESSING_REVAA };
static void CrossFm_postprocessing_revareva(CrossFm *self) { POST_PROCESSING_REVAREVA };

static void
CrossFm_setProcMode(CrossFm *self)
{
    int muladdmode;
    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;

    self->proc_func_ptr = CrossFm_readframes;

    switch (muladdmode)
    {
        case 0:
            self->muladd_func_ptr = CrossFm_postprocessing_ii;
            break;

        case 1:
            self->muladd_func_ptr = CrossFm_postprocessing_ai;
            break;

        case 2:
            self->muladd_func_ptr = CrossFm_postprocessing_revai;
            break;

        case 10:
            self->muladd_func_ptr = CrossFm_postprocessing_ia;
            break;

        case 11:
            self->muladd_func_ptr = CrossFm_postprocessing_aa;
            break;

        case 12:
            self->muladd_func_ptr = CrossFm_postprocessing_revaa;
            break;

        case 20:
            self->muladd_func_ptr = CrossFm_postprocessing_ireva;
            break;

        case 21:
            self->muladd_func_ptr = CrossFm_postprocessing_areva;
            break;

        case 22:
            self->muladd_func_ptr = CrossFm_postprocessing_revareva;
            break;
    }
}

static void
CrossFm_compute_next_data_frame(CrossFm *self)
{
    (*self->proc_func_ptr)(self);
    (*self->muladd_func_ptr)(self);
}

static int
CrossFm_traverse(CrossFm *self, visitproc visit, void *arg)
{
    pyo_VISIT
    Py_VISIT(self->car);
    Py_VISIT(self->ratio);
    Py_VISIT(self->ind1);
    Py_VISIT(self->ind2);
    return 0;
}

static int
CrossFm_clear(CrossFm *self)
{
    pyo_CLEAR
    Py_CLEAR(self->car);
    Py_CLEAR(self->ratio);
    Py_CLEAR(self->ind1);
    Py_CLEAR(self->ind2);
    return 0;
}

static void
CrossFm_dealloc(CrossFm* self)
{
    pyo_DEALLOC
    CrossFm_clear(self);
    Py_TYPE(self->stream)->tp_free((PyObject*)self->stream);
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject *
CrossFm_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    int i;
    PyObject *cartmp = NULL, *ratiotmp = NULL, *ind1tmp = NULL, *ind2tmp = NULL, *multmp = NULL, *addtmp = NULL;
    CrossFm *self;
    self = (CrossFm *)type->tp_alloc(type, 0);

    self->car = PyFloat_FromDouble(100);
    self->ratio = PyFloat_FromDouble(0.5);
    self->ind1 = PyFloat_FromDouble(2);
    self->ind2 = PyFloat_FromDouble(2);
    self->modebuffer[0] = 0;
    self->modebuffer[1] = 0;
    self->modebuffer[2] = 0;
    self->modebuffer[3] = 0;
    self->modebuffer[4] = 0;
    self->modebuffer[5] = 0;
    self->pointerPos_car = self->pointerPos_mod = 0.;
    self->car_val = 0.;

    INIT_OBJECT_COMMON
    Stream_setFunctionPtr(self->stream, CrossFm_compute_next_data_frame);
    self->mode_func_ptr = CrossFm_setProcMode;

    self->scaleFactor = 512.0 / self->sr;

    static char *kwlist[] = {"carrier", "ratio", "ind1", "ind2", "mul", "add", NULL};

    if (! PyArg_ParseTupleAndKeywords(args, kwds, "|OOOOOO", kwlist, &cartmp, &ratiotmp, &ind1tmp, &ind2tmp, &multmp, &addtmp))
        Py_RETURN_NONE;

    if (cartmp)
    {
        PyObject_CallMethod((PyObject *)self, "setCarrier", "O", cartmp);
    }

    if (ratiotmp)
    {
        PyObject_CallMethod((PyObject *)self, "setRatio", "O", ratiotmp);
    }

    if (ind1tmp)
    {
        PyObject_CallMethod((PyObject *)self, "setInd1", "O", ind1tmp);
    }

    if (ind2tmp)
    {
        PyObject_CallMethod((PyObject *)self, "setInd2", "O", ind2tmp);
    }

    if (multmp)
    {
        PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
    }

    if (addtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
    }

    PyObject_CallMethod(self->server, "addStream", "O", self->stream);

    (*self->mode_func_ptr)(self);

    return (PyObject *)self;
}

static PyObject * CrossFm_getServer(CrossFm* self) { GET_SERVER };
static PyObject * CrossFm_getStream(CrossFm* self) { GET_STREAM };
static PyObject * CrossFm_setMul(CrossFm *self, PyObject *arg) { SET_MUL };
static PyObject * CrossFm_setAdd(CrossFm *self, PyObject *arg) { SET_ADD };
static PyObject * CrossFm_setSub(CrossFm *self, PyObject *arg) { SET_SUB };
static PyObject * CrossFm_setDiv(CrossFm *self, PyObject *arg) { SET_DIV };

static PyObject * CrossFm_play(CrossFm *self, PyObject *args, PyObject *kwds) { PLAY };
static PyObject * CrossFm_out(CrossFm *self, PyObject *args, PyObject *kwds) { OUT };
static PyObject * CrossFm_stop(CrossFm *self, PyObject *args, PyObject *kwds) { STOP };

static PyObject * CrossFm_multiply(CrossFm *self, PyObject *arg) { MULTIPLY };
static PyObject * CrossFm_inplace_multiply(CrossFm *self, PyObject *arg) { INPLACE_MULTIPLY };
static PyObject * CrossFm_add(CrossFm *self, PyObject *arg) { ADD };
static PyObject * CrossFm_inplace_add(CrossFm *self, PyObject *arg) { INPLACE_ADD };
static PyObject * CrossFm_sub(CrossFm *self, PyObject *arg) { SUB };
static PyObject * CrossFm_inplace_sub(CrossFm *self, PyObject *arg) { INPLACE_SUB };
static PyObject * CrossFm_div(CrossFm *self, PyObject *arg) { DIV };
static PyObject * CrossFm_inplace_div(CrossFm *self, PyObject *arg) { INPLACE_DIV };

static PyObject * CrossFm_setCarrier(CrossFm *self, PyObject *arg) { SET_PARAM(self->car, self->car_stream, 2); }
static PyObject * CrossFm_setRatio(CrossFm *self, PyObject *arg) { SET_PARAM(self->ratio, self->ratio_stream, 3); }
static PyObject * CrossFm_setInd1(CrossFm *self, PyObject *arg) { SET_PARAM(self->ind1, self->ind1_stream, 4); }
static PyObject * CrossFm_setInd2(CrossFm *self, PyObject *arg) { SET_PARAM(self->ind2, self->ind2_stream, 5); }

static PyMemberDef CrossFm_members[] =
{
    {"server", T_OBJECT_EX, offsetof(CrossFm, server), 0, "Pyo server."},
    {"stream", T_OBJECT_EX, offsetof(CrossFm, stream), 0, "Stream object."},
    {"carrier", T_OBJECT_EX, offsetof(CrossFm, car), 0, "Frequency in cycle per second."},
    {"ratio", T_OBJECT_EX, offsetof(CrossFm, ratio), 0, "Ratio carrier:modulator (mod freq = car*mod)."},
    {"ind1", T_OBJECT_EX, offsetof(CrossFm, ind1), 0, "Modulation ind1 (car amp = car freq*ind1)."},
    {"ind2", T_OBJECT_EX, offsetof(CrossFm, ind2), 0, "Modulation ind2 (mod amp = mod freq*ind2)."},
    {"mul", T_OBJECT_EX, offsetof(CrossFm, mul), 0, "Mul factor."},
    {"add", T_OBJECT_EX, offsetof(CrossFm, add), 0, "Add factor."},
    {NULL}  /* Sentinel */
};

static PyMethodDef CrossFm_methods[] =
{
    {"getServer", (PyCFunction)CrossFm_getServer, METH_NOARGS, "Returns server object."},
    {"_getStream", (PyCFunction)CrossFm_getStream, METH_NOARGS, "Returns stream object."},
    {"play", (PyCFunction)CrossFm_play, METH_VARARGS | METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
    {"out", (PyCFunction)CrossFm_out, METH_VARARGS | METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
    {"stop", (PyCFunction)CrossFm_stop, METH_VARARGS | METH_KEYWORDS, "Stops computing."},
    {"setCarrier", (PyCFunction)CrossFm_setCarrier, METH_O, "Sets carrier frequency in cycle per second."},
    {"setRatio", (PyCFunction)CrossFm_setRatio, METH_O, "Sets car:mod ratio."},
    {"setInd1", (PyCFunction)CrossFm_setInd1, METH_O, "Sets carrier index."},
    {"setInd2", (PyCFunction)CrossFm_setInd2, METH_O, "Sets modulation index."},
    {"setMul", (PyCFunction)CrossFm_setMul, METH_O, "Sets CrossFm mul factor."},
    {"setAdd", (PyCFunction)CrossFm_setAdd, METH_O, "Sets CrossFm add factor."},
    {"setSub", (PyCFunction)CrossFm_setSub, METH_O, "Sets inverse add factor."},
    {"setDiv", (PyCFunction)CrossFm_setDiv, METH_O, "Sets inverse mul factor."},
    {NULL}  /* Sentinel */
};

static PyNumberMethods CrossFm_as_number =
{
    (binaryfunc)CrossFm_add,                      /*nb_add*/
    (binaryfunc)CrossFm_sub,                 /*nb_subtract*/
    (binaryfunc)CrossFm_multiply,                 /*nb_multiply*/
    0,                /*nb_remainder*/
    0,                   /*nb_divmod*/
    0,                   /*nb_power*/
    0,                  /*nb_neg*/
    0,                /*nb_pos*/
    0,                  /*(unaryfunc)array_abs*/
    0,                    /*nb_nonzero*/
    0,                    /*nb_invert*/
    0,               /*nb_lshift*/
    0,              /*nb_rshift*/
    0,              /*nb_and*/
    0,              /*nb_xor*/
    0,               /*nb_or*/
    0,                       /*nb_int*/
    0,                      /*nb_long*/
    0,                     /*nb_float*/
    (binaryfunc)CrossFm_inplace_add,              /*inplace_add*/
    (binaryfunc)CrossFm_inplace_sub,         /*inplace_subtract*/
    (binaryfunc)CrossFm_inplace_multiply,         /*inplace_multiply*/
    0,        /*inplace_remainder*/
    0,           /*inplace_power*/
    0,       /*inplace_lshift*/
    0,      /*inplace_rshift*/
    0,      /*inplace_and*/
    0,      /*inplace_xor*/
    0,       /*inplace_or*/
    0,             /*nb_floor_divide*/
    (binaryfunc)CrossFm_div,                       /*nb_true_divide*/
    0,     /*nb_inplace_floor_divide*/
    (binaryfunc)CrossFm_inplace_div,                       /*nb_inplace_true_divide*/
    0,                     /* nb_ind1 */
};

PyTypeObject CrossFmType =
{
    PyVarObject_HEAD_INIT(NULL, 0)
    "_pyo.CrossFm_base",         /*tp_name*/
    sizeof(CrossFm),         /*tp_basicsize*/
    0,                         /*tp_itemsize*/
    (destructor)CrossFm_dealloc, /*tp_dealloc*/
    0,                         /*tp_print*/
    0,                         /*tp_getattr*/
    0,                         /*tp_setattr*/
    0,                         /*tp_as_async (tp_compare in Python 2)*/
    0,                         /*tp_repr*/
    &CrossFm_as_number,             /*tp_as_number*/
    0,                         /*tp_as_sequence*/
    0,                         /*tp_as_mapping*/
    0,                         /*tp_hash */
    0,                         /*tp_call*/
    0,                         /*tp_str*/
    0,                         /*tp_getattro*/
    0,                         /*tp_setattro*/
    0,                         /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,  /*tp_flags*/
    "CrossFm objects. Generates a cross frequency modulation synthesis.",           /* tp_doc */
    (traverseproc)CrossFm_traverse,   /* tp_traverse */
    (inquiry)CrossFm_clear,           /* tp_clear */
    0,                     /* tp_richcompare */
    0,                     /* tp_weaklistoffset */
    0,                     /* tp_iter */
    0,                     /* tp_iternext */
    CrossFm_methods,             /* tp_methods */
    CrossFm_members,             /* tp_members */
    0,                      /* tp_getset */
    0,                         /* tp_base */
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    0,                         /* tp_dictoffset */
    0,      /* tp_init */
    0,                         /* tp_alloc */
    CrossFm_new,                 /* tp_new */
};

/*************/
/* Blit object */
/*************/
typedef struct
{
    pyo_audio_HEAD
    PyObject *freq;
    Stream *freq_stream;
    PyObject *harms;
    Stream *harms_stream;
    int modebuffer[4];
    MYFLT phase;

} Blit;

static void
Blit_readframes_ii(Blit *self)
{
    MYFLT p, m, rate, val;
    int i, nHarms;

    MYFLT freq = PyFloat_AS_DOUBLE(self->freq);
    MYFLT hrms = PyFloat_AS_DOUBLE(self->harms);

    nHarms = (int)hrms;
    m = 2.0 * nHarms + 1.0;
    p = self->sr / freq;
    rate = PI / p;

    for (i = 0; i < self->bufsize; i++)
    {
        if (self->phase <= 0.0)
            val = 1.0;
        else
        {
            val = MYSIN(m * self->phase);
            val /= m * MYSIN(self->phase);
        }

        self->phase += rate;

        if (self->phase >= PI)
            self->phase -= PI;

        self->data[i] = val;
    }
}

static void
Blit_readframes_ai(Blit *self)
{
    MYFLT p, m, rate, val;
    int i, nHarms;

    MYFLT *freq = Stream_getData((Stream *)self->freq_stream);
    MYFLT hrms = PyFloat_AS_DOUBLE(self->harms);

    nHarms = (int)hrms;
    m = 2.0 * nHarms + 1.0;

    for (i = 0; i < self->bufsize; i++)
    {
        p = self->sr / freq[i];
        rate = PI / p;

        if (self->phase <= 0.0)
            val = 1.0;
        else
        {
            val = MYSIN(m * self->phase);
            val /= m * MYSIN(self->phase);
        }

        self->phase += rate;

        if (self->phase >= PI)
            self->phase -= PI;

        self->data[i] = val;
    }
}

static void
Blit_readframes_ia(Blit *self)
{
    MYFLT p, m, rate, val;
    int i, nHarms;

    MYFLT freq = PyFloat_AS_DOUBLE(self->freq);
    MYFLT *hrms = Stream_getData((Stream *)self->harms_stream);

    p = self->sr / freq;
    rate = PI / p;

    for (i = 0; i < self->bufsize; i++)
    {
        nHarms = (int)hrms[i];
        m = 2.0 * nHarms + 1.0;

        if (self->phase <= 0.0)
            val = 1.0;
        else
        {
            val = MYSIN(m * self->phase);
            val /= m * MYSIN(self->phase);
        }

        self->phase += rate;

        if (self->phase >= PI)
            self->phase -= PI;

        self->data[i] = val;
    }
}

static void
Blit_readframes_aa(Blit *self)
{
    MYFLT p, m, rate, val;
    int i, nHarms;

    MYFLT *freq = Stream_getData((Stream *)self->freq_stream);
    MYFLT *hrms = Stream_getData((Stream *)self->harms_stream);

    for (i = 0; i < self->bufsize; i++)
    {
        nHarms = (int)hrms[i];
        m = 2.0 * nHarms + 1.0;
        p = self->sr / freq[i];
        rate = PI / p;

        if (self->phase <= 0.0)
            val = 1.0;
        else
        {
            val = MYSIN(m * self->phase);
            val /= m * MYSIN(self->phase);
        }

        self->phase += rate;

        if (self->phase >= PI)
            self->phase -= PI;

        self->data[i] = val;
    }
}

static void Blit_postprocessing_ii(Blit *self) { POST_PROCESSING_II };
static void Blit_postprocessing_ai(Blit *self) { POST_PROCESSING_AI };
static void Blit_postprocessing_ia(Blit *self) { POST_PROCESSING_IA };
static void Blit_postprocessing_aa(Blit *self) { POST_PROCESSING_AA };
static void Blit_postprocessing_ireva(Blit *self) { POST_PROCESSING_IREVA };
static void Blit_postprocessing_areva(Blit *self) { POST_PROCESSING_AREVA };
static void Blit_postprocessing_revai(Blit *self) { POST_PROCESSING_REVAI };
static void Blit_postprocessing_revaa(Blit *self) { POST_PROCESSING_REVAA };
static void Blit_postprocessing_revareva(Blit *self) { POST_PROCESSING_REVAREVA };

static void
Blit_setProcMode(Blit *self)
{
    int procmode, muladdmode;
    procmode = self->modebuffer[2] + self->modebuffer[3] * 10;
    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;

    switch (procmode)
    {
        case 0:
            self->proc_func_ptr = Blit_readframes_ii;
            break;

        case 1:
            self->proc_func_ptr = Blit_readframes_ai;
            break;

        case 10:
            self->proc_func_ptr = Blit_readframes_ia;
            break;

        case 11:
            self->proc_func_ptr = Blit_readframes_aa;
            break;
    }

    switch (muladdmode)
    {
        case 0:
            self->muladd_func_ptr = Blit_postprocessing_ii;
            break;

        case 1:
            self->muladd_func_ptr = Blit_postprocessing_ai;
            break;

        case 2:
            self->muladd_func_ptr = Blit_postprocessing_revai;
            break;

        case 10:
            self->muladd_func_ptr = Blit_postprocessing_ia;
            break;

        case 11:
            self->muladd_func_ptr = Blit_postprocessing_aa;
            break;

        case 12:
            self->muladd_func_ptr = Blit_postprocessing_revaa;
            break;

        case 20:
            self->muladd_func_ptr = Blit_postprocessing_ireva;
            break;

        case 21:
            self->muladd_func_ptr = Blit_postprocessing_areva;
            break;

        case 22:
            self->muladd_func_ptr = Blit_postprocessing_revareva;
            break;
    }
}

static void
Blit_compute_next_data_frame(Blit *self)
{
    (*self->proc_func_ptr)(self);
    (*self->muladd_func_ptr)(self);
}

static int
Blit_traverse(Blit *self, visitproc visit, void *arg)
{
    pyo_VISIT
    Py_VISIT(self->freq);
    Py_VISIT(self->harms);
    return 0;
}

static int
Blit_clear(Blit *self)
{
    pyo_CLEAR
    Py_CLEAR(self->freq);
    Py_CLEAR(self->harms);
    return 0;
}

static void
Blit_dealloc(Blit* self)
{
    pyo_DEALLOC
    Blit_clear(self);
    Py_TYPE(self->stream)->tp_free((PyObject*)self->stream);
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject *
Blit_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    int i;
    PyObject *freqtmp = NULL, *harmstmp = NULL, *multmp = NULL, *addtmp = NULL;
    Blit *self;
    self = (Blit *)type->tp_alloc(type, 0);

    self->freq = PyFloat_FromDouble(100);
    self->harms = PyFloat_FromDouble(40);
    self->modebuffer[0] = 0;
    self->modebuffer[1] = 0;
    self->modebuffer[2] = 0;
    self->modebuffer[3] = 0;
    self->phase = 0.0;

    INIT_OBJECT_COMMON
    Stream_setFunctionPtr(self->stream, Blit_compute_next_data_frame);
    self->mode_func_ptr = Blit_setProcMode;

    static char *kwlist[] = {"freq", "harms", "mul", "add", NULL};

    if (! PyArg_ParseTupleAndKeywords(args, kwds, "|OOOO", kwlist, &freqtmp, &harmstmp, &multmp, &addtmp))
        Py_RETURN_NONE;

    if (freqtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setFreq", "O", freqtmp);
    }

    if (harmstmp)
    {
        PyObject_CallMethod((PyObject *)self, "setHarms", "O", harmstmp);
    }

    if (multmp)
    {
        PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
    }

    if (addtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
    }

    PyObject_CallMethod(self->server, "addStream", "O", self->stream);

    (*self->mode_func_ptr)(self);

    return (PyObject *)self;
}

static PyObject * Blit_getServer(Blit* self) { GET_SERVER };
static PyObject * Blit_getStream(Blit* self) { GET_STREAM };
static PyObject * Blit_setMul(Blit *self, PyObject *arg) { SET_MUL };
static PyObject * Blit_setAdd(Blit *self, PyObject *arg) { SET_ADD };
static PyObject * Blit_setSub(Blit *self, PyObject *arg) { SET_SUB };
static PyObject * Blit_setDiv(Blit *self, PyObject *arg) { SET_DIV };

static PyObject * Blit_play(Blit *self, PyObject *args, PyObject *kwds) { PLAY };
static PyObject * Blit_out(Blit *self, PyObject *args, PyObject *kwds) { OUT };
static PyObject * Blit_stop(Blit *self, PyObject *args, PyObject *kwds) { STOP };

static PyObject * Blit_multiply(Blit *self, PyObject *arg) { MULTIPLY };
static PyObject * Blit_inplace_multiply(Blit *self, PyObject *arg) { INPLACE_MULTIPLY };
static PyObject * Blit_add(Blit *self, PyObject *arg) { ADD };
static PyObject * Blit_inplace_add(Blit *self, PyObject *arg) { INPLACE_ADD };
static PyObject * Blit_sub(Blit *self, PyObject *arg) { SUB };
static PyObject * Blit_inplace_sub(Blit *self, PyObject *arg) { INPLACE_SUB };
static PyObject * Blit_div(Blit *self, PyObject *arg) { DIV };
static PyObject * Blit_inplace_div(Blit *self, PyObject *arg) { INPLACE_DIV };

static PyObject * Blit_setFreq(Blit *self, PyObject *arg) { SET_PARAM(self->freq, self->freq_stream, 2); }
static PyObject * Blit_setHarms(Blit *self, PyObject *arg) { SET_PARAM(self->harms, self->harms_stream, 3); }

static PyMemberDef Blit_members[] =
{
    {"server", T_OBJECT_EX, offsetof(Blit, server), 0, "Pyo server."},
    {"stream", T_OBJECT_EX, offsetof(Blit, stream), 0, "Stream object."},
    {"freq", T_OBJECT_EX, offsetof(Blit, freq), 0, "Frequency in cycle per second."},
    {"harms", T_OBJECT_EX, offsetof(Blit, harms), 0, "Number of harmonics."},
    {"mul", T_OBJECT_EX, offsetof(Blit, mul), 0, "Mul factor."},
    {"add", T_OBJECT_EX, offsetof(Blit, add), 0, "Add factor."},
    {NULL}  /* Sentinel */
};

static PyMethodDef Blit_methods[] =
{
    {"getServer", (PyCFunction)Blit_getServer, METH_NOARGS, "Returns server object."},
    {"_getStream", (PyCFunction)Blit_getStream, METH_NOARGS, "Returns stream object."},
    {"play", (PyCFunction)Blit_play, METH_VARARGS | METH_KEYWORDS, "Starts computing without sending sound to soundfreqd."},
    {"out", (PyCFunction)Blit_out, METH_VARARGS | METH_KEYWORDS, "Starts computing and sends sound to soundfreqd channel speficied by argument."},
    {"stop", (PyCFunction)Blit_stop, METH_VARARGS | METH_KEYWORDS, "Stops computing."},
    {"setFreq", (PyCFunction)Blit_setFreq, METH_O, "Sets frequency in cycle per second."},
    {"setHarms", (PyCFunction)Blit_setHarms, METH_O, "Sets the number of harmonics."},
    {"setMul", (PyCFunction)Blit_setMul, METH_O, "Sets Blit mul factor."},
    {"setAdd", (PyCFunction)Blit_setAdd, METH_O, "Sets Blit add factor."},
    {"setSub", (PyCFunction)Blit_setSub, METH_O, "Sets inverse add factor."},
    {"setDiv", (PyCFunction)Blit_setDiv, METH_O, "Sets inverse mul factor."},
    {NULL}  /* Sentinel */
};

static PyNumberMethods Blit_as_number =
{
    (binaryfunc)Blit_add,                      /*nb_add*/
    (binaryfunc)Blit_sub,                 /*nb_subtract*/
    (binaryfunc)Blit_multiply,                 /*nb_multiply*/
    0,                /*nb_remainder*/
    0,                   /*nb_divmod*/
    0,                   /*nb_power*/
    0,                  /*nb_neg*/
    0,                /*nb_pos*/
    0,                  /*(unaryfunc)array_abs*/
    0,                    /*nb_nonzero*/
    0,                    /*nb_invert*/
    0,               /*nb_lshift*/
    0,              /*nb_rshift*/
    0,              /*nb_and*/
    0,              /*nb_xor*/
    0,               /*nb_or*/
    0,                       /*nb_int*/
    0,                      /*nb_long*/
    0,                     /*nb_float*/
    (binaryfunc)Blit_inplace_add,              /*inplace_add*/
    (binaryfunc)Blit_inplace_sub,         /*inplace_subtract*/
    (binaryfunc)Blit_inplace_multiply,         /*inplace_multiply*/
    0,        /*inplace_remainder*/
    0,           /*inplace_power*/
    0,       /*inplace_lshift*/
    0,      /*inplace_rshift*/
    0,      /*inplace_and*/
    0,      /*inplace_xor*/
    0,       /*inplace_or*/
    0,             /*nb_floor_divide*/
    (binaryfunc)Blit_div,                       /*nb_true_divide*/
    0,     /*nb_inplace_floor_divide*/
    (binaryfunc)Blit_inplace_div,                       /*nb_inplace_true_divide*/
    0,                     /* nb_cutoff */
};

PyTypeObject BlitType =
{
    PyVarObject_HEAD_INIT(NULL, 0)
    "_pyo.Blit_base",         /*tp_name*/
    sizeof(Blit),         /*tp_basicsize*/
    0,                         /*tp_itemsize*/
    (destructor)Blit_dealloc, /*tp_dealloc*/
    0,                         /*tp_print*/
    0,                         /*tp_getattr*/
    0,                         /*tp_setattr*/
    0,                         /*tp_as_async (tp_compare in Python 2)*/
    0,                         /*tp_repr*/
    &Blit_as_number,             /*tp_as_number*/
    0,                         /*tp_as_sequence*/
    0,                         /*tp_as_mapping*/
    0,                         /*tp_hash */
    0,                         /*tp_call*/
    0,                         /*tp_str*/
    0,                         /*tp_getattro*/
    0,                         /*tp_setattro*/
    0,                         /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,  /*tp_flags*/
    "Blit objects. Generates a band limited impulse train.",           /* tp_doc */
    (traverseproc)Blit_traverse,   /* tp_traverse */
    (inquiry)Blit_clear,           /* tp_clear */
    0,                     /* tp_richcompare */
    0,                     /* tp_weaklistoffset */
    0,                     /* tp_iter */
    0,                     /* tp_iternext */
    Blit_methods,             /* tp_methods */
    Blit_members,             /* tp_members */
    0,                      /* tp_getset */
    0,                         /* tp_base */
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    0,                         /* tp_dictoffset */
    0,      /* tp_init */
    0,                         /* tp_alloc */
    Blit_new,                 /* tp_new */
};

/* Rossler object */
typedef struct
{
    pyo_audio_HEAD
    PyObject *pitch;
    Stream *pitch_stream;
    PyObject *chaos;
    Stream *chaos_stream;
    MYFLT *altBuffer;
    MYFLT vDX;
    MYFLT vDY;
    MYFLT vDZ;
    MYFLT vX;
    MYFLT vY;
    MYFLT vZ;
    MYFLT pA;
    MYFLT pB;
    MYFLT scalePitch;
    int modebuffer[4];
} Rossler;

static void
Rossler_readframes_ii(Rossler *self)
{
    MYFLT delta, pit, chao;
    int i;

    pit = PyFloat_AS_DOUBLE(self->pitch);
    chao = PyFloat_AS_DOUBLE(self->chaos);

    if (pit < 0.0)
        pit = 1.0;
    else if (pit > 1.0)
        pit = 1000.0;
    else
        pit = pit * 999.0 + 1.0;

    delta = self->scalePitch * pit;

    if (chao < 0.0)
        chao = 3.0;
    else if (chao > 1.0)
        chao = 10.0;
    else
        chao = chao * 7.0 + 3.0;

    for (i = 0; i < self->bufsize; i++)
    {
        self->vDX = -self->vY - self->vZ;
        self->vDY = self->vX + self->pA * self->vY;
        self->vDZ = self->pB + self->vZ * (self->vX - chao);

        self->vX += self->vDX * delta;
        self->vY += self->vDY * delta;
        self->vZ += self->vDZ * delta;

        self->data[i] = self->vX * ROSSLER_SCALE;
        self->altBuffer[i] = self->vY * ROSSLER_ALT_SCALE;
    }
}

static void
Rossler_readframes_ai(Rossler *self)
{
    MYFLT delta, pit, chao;
    int i;

    MYFLT *fr = Stream_getData((Stream *)self->pitch_stream);
    chao = PyFloat_AS_DOUBLE(self->chaos);

    if (chao < 0.0)
        chao = 3.0;
    else if (chao > 1.0)
        chao = 10.0;
    else
        chao = chao * 7.0 + 3.0;

    for (i = 0; i < self->bufsize; i++)
    {
        pit = fr[i];

        if (pit < 0.0)
            pit = 1.0;
        else if (pit > 1.0)
            pit = 1000.0;
        else
            pit = pit * 999.0 + 1.0;

        delta = self->scalePitch * pit;
        self->vDX = -self->vY - self->vZ;
        self->vDY = self->vX + self->pA * self->vY;
        self->vDZ = self->pB + self->vZ * (self->vX - chao);

        self->vX += self->vDX * delta;
        self->vY += self->vDY * delta;
        self->vZ += self->vDZ * delta;

        self->data[i] = self->vX * ROSSLER_SCALE;
        self->altBuffer[i] = self->vY * ROSSLER_ALT_SCALE;
    }
}

static void
Rossler_readframes_ia(Rossler *self)
{
    MYFLT delta, pit, chao;
    int i;

    pit = PyFloat_AS_DOUBLE(self->pitch);
    MYFLT *ch = Stream_getData((Stream *)self->chaos_stream);

    if (pit < 0.0)
        pit = 1.0;
    else if (pit > 1.0)
        pit = 1000.0;
    else
        pit = pit * 999.0 + 1.0;

    delta = self->scalePitch * pit;

    for (i = 0; i < self->bufsize; i++)
    {
        chao = ch[i];

        if (chao < 0.0)
            chao = 3.0;
        else if (chao > 1.0)
            chao = 10.0;
        else
            chao = chao * 7.0 + 3.0;

        self->vDX = -self->vY - self->vZ;
        self->vDY = self->vX + self->pA * self->vY;
        self->vDZ = self->pB + self->vZ * (self->vX - chao);

        self->vX += self->vDX * delta;
        self->vY += self->vDY * delta;
        self->vZ += self->vDZ * delta;

        self->data[i] = self->vX * ROSSLER_SCALE;
        self->altBuffer[i] = self->vY * ROSSLER_ALT_SCALE;
    }
}

static void
Rossler_readframes_aa(Rossler *self)
{
    MYFLT delta, pit, chao;
    int i;

    MYFLT *fr = Stream_getData((Stream *)self->pitch_stream);
    MYFLT *ch = Stream_getData((Stream *)self->chaos_stream);

    for (i = 0; i < self->bufsize; i++)
    {
        pit = fr[i];

        if (pit < 0.0)
            pit = 1.0;
        else if (pit > 1.0)
            pit = 1000.0;
        else
            pit = pit * 999.0 + 1.0;

        delta = self->scalePitch * pit;

        chao = ch[i];

        if (chao < 0.0)
            chao = 3.0;
        else if (chao > 1.0)
            chao = 10.0;
        else
            chao = chao * 7.0 + 3.0;

        self->vDX = -self->vY - self->vZ;
        self->vDY = self->vX + self->pA * self->vY;
        self->vDZ = self->pB + self->vZ * (self->vX - chao);

        self->vX += self->vDX * delta;
        self->vY += self->vDY * delta;
        self->vZ += self->vDZ * delta;

        self->data[i] = self->vX * ROSSLER_SCALE;
        self->altBuffer[i] = self->vY * ROSSLER_ALT_SCALE;
    }
}

static void Rossler_postprocessing_ii(Rossler *self) { POST_PROCESSING_II };
static void Rossler_postprocessing_ai(Rossler *self) { POST_PROCESSING_AI };
static void Rossler_postprocessing_ia(Rossler *self) { POST_PROCESSING_IA };
static void Rossler_postprocessing_aa(Rossler *self) { POST_PROCESSING_AA };
static void Rossler_postprocessing_ireva(Rossler *self) { POST_PROCESSING_IREVA };
static void Rossler_postprocessing_areva(Rossler *self) { POST_PROCESSING_AREVA };
static void Rossler_postprocessing_revai(Rossler *self) { POST_PROCESSING_REVAI };
static void Rossler_postprocessing_revaa(Rossler *self) { POST_PROCESSING_REVAA };
static void Rossler_postprocessing_revareva(Rossler *self) { POST_PROCESSING_REVAREVA };

static void
Rossler_setProcMode(Rossler *self)
{
    int procmode, muladdmode;
    procmode = self->modebuffer[2] + self->modebuffer[3] * 10;
    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;

    switch (procmode)
    {
        case 0:
            self->proc_func_ptr = Rossler_readframes_ii;
            break;

        case 1:
            self->proc_func_ptr = Rossler_readframes_ai;
            break;

        case 10:
            self->proc_func_ptr = Rossler_readframes_ia;
            break;

        case 11:
            self->proc_func_ptr = Rossler_readframes_aa;
            break;
    }

    switch (muladdmode)
    {
        case 0:
            self->muladd_func_ptr = Rossler_postprocessing_ii;
            break;

        case 1:
            self->muladd_func_ptr = Rossler_postprocessing_ai;
            break;

        case 2:
            self->muladd_func_ptr = Rossler_postprocessing_revai;
            break;

        case 10:
            self->muladd_func_ptr = Rossler_postprocessing_ia;
            break;

        case 11:
            self->muladd_func_ptr = Rossler_postprocessing_aa;
            break;

        case 12:
            self->muladd_func_ptr = Rossler_postprocessing_revaa;
            break;

        case 20:
            self->muladd_func_ptr = Rossler_postprocessing_ireva;
            break;

        case 21:
            self->muladd_func_ptr = Rossler_postprocessing_areva;
            break;

        case 22:
            self->muladd_func_ptr = Rossler_postprocessing_revareva;
            break;
    }
}

static void
Rossler_compute_next_data_frame(Rossler *self)
{
    (*self->proc_func_ptr)(self);
    (*self->muladd_func_ptr)(self);
}

static int
Rossler_traverse(Rossler *self, visitproc visit, void *arg)
{
    pyo_VISIT
    Py_VISIT(self->pitch);
    Py_VISIT(self->chaos);
    return 0;
}

static int
Rossler_clear(Rossler *self)
{
    pyo_CLEAR
    Py_CLEAR(self->pitch);
    Py_CLEAR(self->chaos);
    return 0;
}

static void
Rossler_dealloc(Rossler* self)
{
    pyo_DEALLOC
    PyMem_RawFree(self->altBuffer);
    Rossler_clear(self);
    Py_TYPE(self->stream)->tp_free((PyObject*)self->stream);
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject *
Rossler_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    int i;
    PyObject *pitchtmp = NULL, *chaostmp = NULL, *multmp = NULL, *addtmp = NULL;
    Rossler *self;
    self = (Rossler *)type->tp_alloc(type, 0);

    self->pitch = PyFloat_FromDouble(0.25);
    self->chaos = PyFloat_FromDouble(0.5);
    self->pA = 0.15;
    self->pB = 0.20;
    self->vDX = self->vDY = self->vDZ = 0.0;
    self->vX = self->vY = self->vZ = 1.0;
    self->modebuffer[0] = 0;
    self->modebuffer[1] = 0;
    self->modebuffer[2] = 0;
    self->modebuffer[3] = 0;

    INIT_OBJECT_COMMON
    Stream_setFunctionPtr(self->stream, Rossler_compute_next_data_frame);
    self->mode_func_ptr = Rossler_setProcMode;

    self->scalePitch = 2.91 / self->sr;

    static char *kwlist[] = {"pitch", "chaos", "mul", "add", NULL};

    if (! PyArg_ParseTupleAndKeywords(args, kwds, "|OOOO", kwlist, &pitchtmp, &chaostmp, &multmp, &addtmp))
        Py_RETURN_NONE;

    if (pitchtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setPitch", "O", pitchtmp);
    }

    if (chaostmp)
    {
        PyObject_CallMethod((PyObject *)self, "setChaos", "O", chaostmp);
    }

    if (multmp)
    {
        PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
    }

    if (addtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
    }

    PyObject_CallMethod(self->server, "addStream", "O", self->stream);

    self->altBuffer = (MYFLT *)PyMem_RawRealloc(self->altBuffer, self->bufsize * sizeof(MYFLT));

    for (i = 0; i < self->bufsize; i++)
    {
        self->altBuffer[i] = 0.0;
    }

    (*self->mode_func_ptr)(self);

    return (PyObject *)self;
}

static PyObject * Rossler_getServer(Rossler* self) { GET_SERVER };
static PyObject * Rossler_getStream(Rossler* self) { GET_STREAM };
static PyObject * Rossler_setMul(Rossler *self, PyObject *arg) { SET_MUL };
static PyObject * Rossler_setAdd(Rossler *self, PyObject *arg) { SET_ADD };
static PyObject * Rossler_setSub(Rossler *self, PyObject *arg) { SET_SUB };
static PyObject * Rossler_setDiv(Rossler *self, PyObject *arg) { SET_DIV };

static PyObject * Rossler_play(Rossler *self, PyObject *args, PyObject *kwds) { PLAY };
static PyObject * Rossler_out(Rossler *self, PyObject *args, PyObject *kwds) { OUT };
static PyObject * Rossler_stop(Rossler *self, PyObject *args, PyObject *kwds) { STOP };

static PyObject * Rossler_multiply(Rossler *self, PyObject *arg) { MULTIPLY };
static PyObject * Rossler_inplace_multiply(Rossler *self, PyObject *arg) { INPLACE_MULTIPLY };
static PyObject * Rossler_add(Rossler *self, PyObject *arg) { ADD };
static PyObject * Rossler_inplace_add(Rossler *self, PyObject *arg) { INPLACE_ADD };
static PyObject * Rossler_sub(Rossler *self, PyObject *arg) { SUB };
static PyObject * Rossler_inplace_sub(Rossler *self, PyObject *arg) { INPLACE_SUB };
static PyObject * Rossler_div(Rossler *self, PyObject *arg) { DIV };
static PyObject * Rossler_inplace_div(Rossler *self, PyObject *arg) { INPLACE_DIV };

static PyObject * Rossler_setPitch(Rossler *self, PyObject *arg) { SET_PARAM(self->pitch, self->pitch_stream, 2); }
static PyObject * Rossler_setChaos(Rossler *self, PyObject *arg) { SET_PARAM(self->chaos, self->chaos_stream, 3); }

MYFLT *
Rossler_getAltBuffer(Rossler *self)
{
    return (MYFLT *)self->altBuffer;
}

static PyMemberDef Rossler_members[] =
{
    {"server", T_OBJECT_EX, offsetof(Rossler, server), 0, "Pyo server."},
    {"stream", T_OBJECT_EX, offsetof(Rossler, stream), 0, "Stream object."},
    {"pitch", T_OBJECT_EX, offsetof(Rossler, pitch), 0, "Pitch."},
    {"chaos", T_OBJECT_EX, offsetof(Rossler, chaos), 0, "Chaotic behavior."},
    {"mul", T_OBJECT_EX, offsetof(Rossler, mul), 0, "Mul factor."},
    {"add", T_OBJECT_EX, offsetof(Rossler, add), 0, "Add factor."},
    {NULL}  /* Sentinel */
};

static PyMethodDef Rossler_methods[] =
{
    {"getServer", (PyCFunction)Rossler_getServer, METH_NOARGS, "Returns server object."},
    {"_getStream", (PyCFunction)Rossler_getStream, METH_NOARGS, "Returns stream object."},
    {"play", (PyCFunction)Rossler_play, METH_VARARGS | METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
    {"out", (PyCFunction)Rossler_out, METH_VARARGS | METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
    {"stop", (PyCFunction)Rossler_stop, METH_VARARGS | METH_KEYWORDS, "Stops computing."},
    {"setPitch", (PyCFunction)Rossler_setPitch, METH_O, "Sets oscillator pitch."},
    {"setChaos", (PyCFunction)Rossler_setChaos, METH_O, "Sets oscillator chaotic behavior."},
    {"setMul", (PyCFunction)Rossler_setMul, METH_O, "Sets Rossler mul factor."},
    {"setAdd", (PyCFunction)Rossler_setAdd, METH_O, "Sets Rossler add factor."},
    {"setSub", (PyCFunction)Rossler_setSub, METH_O, "Sets inverse add factor."},
    {"setDiv", (PyCFunction)Rossler_setDiv, METH_O, "Sets inverse mul factor."},
    {NULL}  /* Sentinel */
};

static PyNumberMethods Rossler_as_number =
{
    (binaryfunc)Rossler_add,                      /*nb_add*/
    (binaryfunc)Rossler_sub,                 /*nb_subtract*/
    (binaryfunc)Rossler_multiply,                 /*nb_multiply*/
    0,                /*nb_remainder*/
    0,                   /*nb_divmod*/
    0,                   /*nb_power*/
    0,                  /*nb_neg*/
    0,                /*nb_pos*/
    0,                  /*(unaryfunc)array_abs*/
    0,                    /*nb_nonzero*/
    0,                    /*nb_invert*/
    0,               /*nb_lshift*/
    0,              /*nb_rshift*/
    0,              /*nb_and*/
    0,              /*nb_xor*/
    0,               /*nb_or*/
    0,                       /*nb_int*/
    0,                      /*nb_long*/
    0,                     /*nb_float*/
    (binaryfunc)Rossler_inplace_add,              /*inplace_add*/
    (binaryfunc)Rossler_inplace_sub,         /*inplace_subtract*/
    (binaryfunc)Rossler_inplace_multiply,         /*inplace_multiply*/
    0,        /*inplace_remainder*/
    0,           /*inplace_power*/
    0,       /*inplace_lshift*/
    0,      /*inplace_rshift*/
    0,      /*inplace_and*/
    0,      /*inplace_xor*/
    0,       /*inplace_or*/
    0,             /*nb_floor_divide*/
    (binaryfunc)Rossler_div,                       /*nb_true_divide*/
    0,     /*nb_inplace_floor_divide*/
    (binaryfunc)Rossler_inplace_div,                       /*nb_inplace_true_divide*/
    0,                     /* nb_index */
};

PyTypeObject RosslerType =
{
    PyVarObject_HEAD_INIT(NULL, 0)
    "_pyo.Rossler_base",         /*tp_name*/
    sizeof(Rossler),         /*tp_basicsize*/
    0,                         /*tp_itemsize*/
    (destructor)Rossler_dealloc, /*tp_dealloc*/
    0,                         /*tp_print*/
    0,                         /*tp_getattr*/
    0,                         /*tp_setattr*/
    0,                         /*tp_as_async (tp_compare in Python 2)*/
    0,                         /*tp_repr*/
    &Rossler_as_number,             /*tp_as_number*/
    0,                         /*tp_as_sequence*/
    0,                         /*tp_as_mapping*/
    0,                         /*tp_hash */
    0,                         /*tp_call*/
    0,                         /*tp_str*/
    0,                         /*tp_getattro*/
    0,                         /*tp_setattro*/
    0,                         /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,  /*tp_flags*/
    "Rossler objects. Rossler attractor.",           /* tp_doc */
    (traverseproc)Rossler_traverse,   /* tp_traverse */
    (inquiry)Rossler_clear,           /* tp_clear */
    0,                     /* tp_richcompare */
    0,                     /* tp_weaklistoffset */
    0,                     /* tp_iter */
    0,                     /* tp_iternext */
    Rossler_methods,             /* tp_methods */
    Rossler_members,             /* tp_members */
    0,                      /* tp_getset */
    0,                         /* tp_base */
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    0,                         /* tp_dictoffset */
    0,      /* tp_init */
    0,                         /* tp_alloc */
    Rossler_new,                 /* tp_new */
};

typedef struct
{
    pyo_audio_HEAD
    Rossler *mainRossler;
    int modebuffer[2];
} RosslerAlt;

static void RosslerAlt_postprocessing_ii(RosslerAlt *self) { POST_PROCESSING_II };
static void RosslerAlt_postprocessing_ai(RosslerAlt *self) { POST_PROCESSING_AI };
static void RosslerAlt_postprocessing_ia(RosslerAlt *self) { POST_PROCESSING_IA };
static void RosslerAlt_postprocessing_aa(RosslerAlt *self) { POST_PROCESSING_AA };
static void RosslerAlt_postprocessing_ireva(RosslerAlt *self) { POST_PROCESSING_IREVA };
static void RosslerAlt_postprocessing_areva(RosslerAlt *self) { POST_PROCESSING_AREVA };
static void RosslerAlt_postprocessing_revai(RosslerAlt *self) { POST_PROCESSING_REVAI };
static void RosslerAlt_postprocessing_revaa(RosslerAlt *self) { POST_PROCESSING_REVAA };
static void RosslerAlt_postprocessing_revareva(RosslerAlt *self) { POST_PROCESSING_REVAREVA };

static void
RosslerAlt_setProcMode(RosslerAlt *self)
{
    int muladdmode;
    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;

    switch (muladdmode)
    {
        case 0:
            self->muladd_func_ptr = RosslerAlt_postprocessing_ii;
            break;

        case 1:
            self->muladd_func_ptr = RosslerAlt_postprocessing_ai;
            break;

        case 2:
            self->muladd_func_ptr = RosslerAlt_postprocessing_revai;
            break;

        case 10:
            self->muladd_func_ptr = RosslerAlt_postprocessing_ia;
            break;

        case 11:
            self->muladd_func_ptr = RosslerAlt_postprocessing_aa;
            break;

        case 12:
            self->muladd_func_ptr = RosslerAlt_postprocessing_revaa;
            break;

        case 20:
            self->muladd_func_ptr = RosslerAlt_postprocessing_ireva;
            break;

        case 21:
            self->muladd_func_ptr = RosslerAlt_postprocessing_areva;
            break;

        case 22:
            self->muladd_func_ptr = RosslerAlt_postprocessing_revareva;
            break;
    }
}

static void
RosslerAlt_compute_next_data_frame(RosslerAlt *self)
{
    int i;
    MYFLT *tmp;
    tmp = Rossler_getAltBuffer((Rossler *)self->mainRossler);

    for (i = 0; i < self->bufsize; i++)
    {
        self->data[i] = tmp[i];
    }

    (*self->muladd_func_ptr)(self);
}

static int
RosslerAlt_traverse(RosslerAlt *self, visitproc visit, void *arg)
{
    pyo_VISIT
    Py_VISIT(self->mainRossler);
    return 0;
}

static int
RosslerAlt_clear(RosslerAlt *self)
{
    pyo_CLEAR
    Py_CLEAR(self->mainRossler);
    return 0;
}

static void
RosslerAlt_dealloc(RosslerAlt* self)
{
    pyo_DEALLOC
    RosslerAlt_clear(self);
    Py_TYPE(self->stream)->tp_free((PyObject*)self->stream);
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject *
RosslerAlt_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    int i;
    PyObject *maintmp = NULL, *multmp = NULL, *addtmp = NULL;
    RosslerAlt *self;
    self = (RosslerAlt *)type->tp_alloc(type, 0);

    self->modebuffer[0] = 0;
    self->modebuffer[1] = 0;

    INIT_OBJECT_COMMON
    Stream_setFunctionPtr(self->stream, RosslerAlt_compute_next_data_frame);
    self->mode_func_ptr = RosslerAlt_setProcMode;

    static char *kwlist[] = {"mainRossler", "mul", "alt", NULL};

    if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|OO", kwlist, &maintmp, &multmp, &addtmp))
        Py_RETURN_NONE;

    self->mainRossler = (Rossler *)maintmp;
    Py_INCREF(self->mainRossler);

    if (multmp)
    {
        PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
    }

    if (addtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
    }

    PyObject_CallMethod(self->server, "addStream", "O", self->stream);

    (*self->mode_func_ptr)(self);

    return (PyObject *)self;
}

static PyObject * RosslerAlt_getServer(RosslerAlt* self) { GET_SERVER };
static PyObject * RosslerAlt_getStream(RosslerAlt* self) { GET_STREAM };
static PyObject * RosslerAlt_setMul(RosslerAlt *self, PyObject *arg) { SET_MUL };
static PyObject * RosslerAlt_setAdd(RosslerAlt *self, PyObject *arg) { SET_ADD };
static PyObject * RosslerAlt_setSub(RosslerAlt *self, PyObject *arg) { SET_SUB };
static PyObject * RosslerAlt_setDiv(RosslerAlt *self, PyObject *arg) { SET_DIV };

static PyObject * RosslerAlt_play(RosslerAlt *self, PyObject *args, PyObject *kwds) { PLAY };
static PyObject * RosslerAlt_out(RosslerAlt *self, PyObject *args, PyObject *kwds) { OUT };
static PyObject * RosslerAlt_stop(RosslerAlt *self, PyObject *args, PyObject *kwds) { STOP };

static PyObject * RosslerAlt_multiply(RosslerAlt *self, PyObject *arg) { MULTIPLY };
static PyObject * RosslerAlt_inplace_multiply(RosslerAlt *self, PyObject *arg) { INPLACE_MULTIPLY };
static PyObject * RosslerAlt_add(RosslerAlt *self, PyObject *arg) { ADD };
static PyObject * RosslerAlt_inplace_add(RosslerAlt *self, PyObject *arg) { INPLACE_ADD };
static PyObject * RosslerAlt_sub(RosslerAlt *self, PyObject *arg) { SUB };
static PyObject * RosslerAlt_inplace_sub(RosslerAlt *self, PyObject *arg) { INPLACE_SUB };
static PyObject * RosslerAlt_div(RosslerAlt *self, PyObject *arg) { DIV };
static PyObject * RosslerAlt_inplace_div(RosslerAlt *self, PyObject *arg) { INPLACE_DIV };

static PyMemberDef RosslerAlt_members[] =
{
    {"server", T_OBJECT_EX, offsetof(RosslerAlt, server), 0, "Pyo server."},
    {"stream", T_OBJECT_EX, offsetof(RosslerAlt, stream), 0, "Stream object."},
    {"mul", T_OBJECT_EX, offsetof(RosslerAlt, mul), 0, "Mul factor."},
    {"add", T_OBJECT_EX, offsetof(RosslerAlt, add), 0, "Add factor."},
    {NULL}  /* Sentinel */
};

static PyMethodDef RosslerAlt_methods[] =
{
    {"getServer", (PyCFunction)RosslerAlt_getServer, METH_NOARGS, "Returns server object."},
    {"_getStream", (PyCFunction)RosslerAlt_getStream, METH_NOARGS, "Returns stream object."},
    {"play", (PyCFunction)RosslerAlt_play, METH_VARARGS | METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
    {"out", (PyCFunction)RosslerAlt_out, METH_VARARGS | METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
    {"stop", (PyCFunction)RosslerAlt_stop, METH_VARARGS | METH_KEYWORDS, "Stops computing."},
    {"setMul", (PyCFunction)RosslerAlt_setMul, METH_O, "Sets oscillator mul factor."},
    {"setAdd", (PyCFunction)RosslerAlt_setAdd, METH_O, "Sets oscillator add factor."},
    {"setSub", (PyCFunction)RosslerAlt_setSub, METH_O, "Sets inverse add factor."},
    {"setDiv", (PyCFunction)RosslerAlt_setDiv, METH_O, "Sets inverse mul factor."},
    {NULL}  /* Sentinel */
};
static PyNumberMethods RosslerAlt_as_number =
{
    (binaryfunc)RosslerAlt_add,                         /*nb_add*/
    (binaryfunc)RosslerAlt_sub,                         /*nb_subtract*/
    (binaryfunc)RosslerAlt_multiply,                    /*nb_multiply*/
    0,                                              /*nb_remainder*/
    0,                                              /*nb_divmod*/
    0,                                              /*nb_power*/
    0,                                              /*nb_neg*/
    0,                                              /*nb_pos*/
    0,                                              /*(unaryfunc)array_abs,*/
    0,                                              /*nb_nonzero*/
    0,                                              /*nb_invert*/
    0,                                              /*nb_lshift*/
    0,                                              /*nb_rshift*/
    0,                                              /*nb_and*/
    0,                                              /*nb_xor*/
    0,                                              /*nb_or*/
    0,                                              /*nb_int*/
    0,                                              /*nb_long*/
    0,                                              /*nb_float*/
    (binaryfunc)RosslerAlt_inplace_add,                 /*inplace_add*/
    (binaryfunc)RosslerAlt_inplace_sub,                 /*inplace_subtract*/
    (binaryfunc)RosslerAlt_inplace_multiply,            /*inplace_multiply*/
    0,                                              /*inplace_remainder*/
    0,                                              /*inplace_power*/
    0,                                              /*inplace_lshift*/
    0,                                              /*inplace_rshift*/
    0,                                              /*inplace_and*/
    0,                                              /*inplace_xor*/
    0,                                              /*inplace_or*/
    0,                                              /*nb_floor_divide*/
    (binaryfunc)RosslerAlt_div,                       /*nb_true_divide*/
    0,                                              /*nb_inplace_floor_divide*/
    (binaryfunc)RosslerAlt_inplace_div,                       /*nb_inplace_true_divide*/
    0,                                              /* nb_index */
};

PyTypeObject RosslerAltType =
{
    PyVarObject_HEAD_INIT(NULL, 0)
    "_pyo.RosslerAlt_base",         /*tp_name*/
    sizeof(RosslerAlt),         /*tp_basicsize*/
    0,                         /*tp_itemsize*/
    (destructor)RosslerAlt_dealloc, /*tp_dealloc*/
    0,                         /*tp_print*/
    0,                         /*tp_getattr*/
    0,                         /*tp_setattr*/
    0,                         /*tp_as_async (tp_compare in Python 2)*/
    0,                         /*tp_repr*/
    &RosslerAlt_as_number,             /*tp_as_number*/
    0,                         /*tp_as_sequence*/
    0,                         /*tp_as_mapping*/
    0,                         /*tp_hash */
    0,                         /*tp_call*/
    0,                         /*tp_str*/
    0,                         /*tp_getattro*/
    0,                         /*tp_setattro*/
    0,                         /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,  /*tp_flags*/
    "RosslerAlt objects. Sends the alternate signal of a Rossler attractor.",           /* tp_doc */
    (traverseproc)RosslerAlt_traverse,   /* tp_traverse */
    (inquiry)RosslerAlt_clear,           /* tp_clear */
    0,                     /* tp_richcompare */
    0,                     /* tp_weaklistoffset */
    0,                     /* tp_iter */
    0,                     /* tp_iternext */
    RosslerAlt_methods,             /* tp_methods */
    RosslerAlt_members,             /* tp_members */
    0,                      /* tp_getset */
    0,                         /* tp_base */
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    0,                         /* tp_dictoffset */
    0,      /* tp_init */
    0,                         /* tp_alloc */
    RosslerAlt_new,                 /* tp_new */
};

/* Lorenz object */
typedef struct
{
    pyo_audio_HEAD
    PyObject *pitch;
    Stream *pitch_stream;
    PyObject *chaos;
    Stream *chaos_stream;
    MYFLT *altBuffer;
    MYFLT vDX;
    MYFLT vDY;
    MYFLT vDZ;
    MYFLT vX;
    MYFLT vY;
    MYFLT vZ;
    MYFLT pA;
    MYFLT pB;
    MYFLT oneOnSr;
    int modebuffer[4];
} Lorenz;

static void
Lorenz_readframes_ii(Lorenz *self)
{
    MYFLT delta, pit, chao;
    int i;

    pit = PyFloat_AS_DOUBLE(self->pitch);
    chao = PyFloat_AS_DOUBLE(self->chaos);

    if (pit < 0.0)
        pit = 1.0;
    else if (pit > 1.0)
        pit = 750.0;
    else
        pit = pit * 749.0 + 1.0;

    delta = self->oneOnSr * pit;

    if (chao < 0.0)
        chao = 0.5;
    else if (chao > 1.0)
        chao = 3.0;
    else
        chao = chao * 2.5 + 0.5;

    for (i = 0; i < self->bufsize; i++)
    {
        self->vDX = self->pA * (self->vY - self->vX);
        self->vDY = self->vX * (self->pB - self->vZ) - self->vY;
        self->vDZ = self->vX * self->vY - chao * self->vZ;

        self->vX += self->vDX * delta;
        self->vY += self->vDY * delta;
        self->vZ += self->vDZ * delta;

        self->data[i] = self->vX * LORENZ_SCALE;
        self->altBuffer[i] = self->vY * LORENZ_ALT_SCALE;
    }
}

static void
Lorenz_readframes_ai(Lorenz *self)
{
    MYFLT delta, pit, chao;
    int i;

    MYFLT *fr = Stream_getData((Stream *)self->pitch_stream);
    chao = PyFloat_AS_DOUBLE(self->chaos);

    if (chao < 0.0)
        chao = 0.5;
    else if (chao > 1.0)
        chao = 3.0;
    else
        chao = chao * 2.5 + 0.5;

    for (i = 0; i < self->bufsize; i++)
    {
        pit = fr[i];

        if (pit < 0.0)
            pit = 1.0;
        else if (pit > 1.0)
            pit = 750.0;
        else
            pit = pit * 749.0 + 1.0;

        delta = self->oneOnSr * pit;
        self->vDX = self->pA * (self->vY - self->vX);
        self->vDY = self->vX * (self->pB - self->vZ) - self->vY;
        self->vDZ = self->vX * self->vY - chao * self->vZ;

        self->vX += self->vDX * delta;
        self->vY += self->vDY * delta;
        self->vZ += self->vDZ * delta;

        self->data[i] = self->vX * LORENZ_SCALE;
        self->altBuffer[i] = self->vY * LORENZ_ALT_SCALE;
    }
}

static void
Lorenz_readframes_ia(Lorenz *self)
{
    MYFLT delta, pit, chao;
    int i;

    pit = PyFloat_AS_DOUBLE(self->pitch);
    MYFLT *ch = Stream_getData((Stream *)self->chaos_stream);

    if (pit < 0.0)
        pit = 1.0;
    else if (pit > 1.0)
        pit = 750.0;
    else
        pit = pit * 749.0 + 1.0;

    delta = self->oneOnSr * pit;

    for (i = 0; i < self->bufsize; i++)
    {
        chao = ch[i];

        if (chao < 0.0)
            chao = 0.5;
        else if (chao > 1.0)
            chao = 3.0;
        else
            chao = chao * 2.5 + 0.5;

        self->vDX = self->pA * (self->vY - self->vX);
        self->vDY = self->vX * (self->pB - self->vZ) - self->vY;
        self->vDZ = self->vX * self->vY - chao * self->vZ;

        self->vX += self->vDX * delta;
        self->vY += self->vDY * delta;
        self->vZ += self->vDZ * delta;

        self->data[i] = self->vX * LORENZ_SCALE;
        self->altBuffer[i] = self->vY * LORENZ_ALT_SCALE;
    }
}

static void
Lorenz_readframes_aa(Lorenz *self)
{
    MYFLT delta, pit, chao;
    int i;

    MYFLT *fr = Stream_getData((Stream *)self->pitch_stream);
    MYFLT *ch = Stream_getData((Stream *)self->chaos_stream);

    for (i = 0; i < self->bufsize; i++)
    {
        pit = fr[i];

        if (pit < 0.0)
            pit = 1.0;
        else if (pit > 1.0)
            pit = 750.0;
        else
            pit = pit * 749.0 + 1.0;

        delta = self->oneOnSr * pit;

        chao = ch[i];

        if (chao < 0.0)
            chao = 0.5;
        else if (chao > 1.0)
            chao = 3.0;
        else
            chao = chao * 2.5 + 0.5;

        self->vDX = self->pA * (self->vY - self->vX);
        self->vDY = self->vX * (self->pB - self->vZ) - self->vY;
        self->vDZ = self->vX * self->vY - chao * self->vZ;

        self->vX += self->vDX * delta;
        self->vY += self->vDY * delta;
        self->vZ += self->vDZ * delta;

        self->data[i] = self->vX * LORENZ_SCALE;
        self->altBuffer[i] = self->vY * LORENZ_ALT_SCALE;
    }
}

static void Lorenz_postprocessing_ii(Lorenz *self) { POST_PROCESSING_II };
static void Lorenz_postprocessing_ai(Lorenz *self) { POST_PROCESSING_AI };
static void Lorenz_postprocessing_ia(Lorenz *self) { POST_PROCESSING_IA };
static void Lorenz_postprocessing_aa(Lorenz *self) { POST_PROCESSING_AA };
static void Lorenz_postprocessing_ireva(Lorenz *self) { POST_PROCESSING_IREVA };
static void Lorenz_postprocessing_areva(Lorenz *self) { POST_PROCESSING_AREVA };
static void Lorenz_postprocessing_revai(Lorenz *self) { POST_PROCESSING_REVAI };
static void Lorenz_postprocessing_revaa(Lorenz *self) { POST_PROCESSING_REVAA };
static void Lorenz_postprocessing_revareva(Lorenz *self) { POST_PROCESSING_REVAREVA };

static void
Lorenz_setProcMode(Lorenz *self)
{
    int procmode, muladdmode;
    procmode = self->modebuffer[2] + self->modebuffer[3] * 10;
    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;

    switch (procmode)
    {
        case 0:
            self->proc_func_ptr = Lorenz_readframes_ii;
            break;

        case 1:
            self->proc_func_ptr = Lorenz_readframes_ai;
            break;

        case 10:
            self->proc_func_ptr = Lorenz_readframes_ia;
            break;

        case 11:
            self->proc_func_ptr = Lorenz_readframes_aa;
            break;
    }

    switch (muladdmode)
    {
        case 0:
            self->muladd_func_ptr = Lorenz_postprocessing_ii;
            break;

        case 1:
            self->muladd_func_ptr = Lorenz_postprocessing_ai;
            break;

        case 2:
            self->muladd_func_ptr = Lorenz_postprocessing_revai;
            break;

        case 10:
            self->muladd_func_ptr = Lorenz_postprocessing_ia;
            break;

        case 11:
            self->muladd_func_ptr = Lorenz_postprocessing_aa;
            break;

        case 12:
            self->muladd_func_ptr = Lorenz_postprocessing_revaa;
            break;

        case 20:
            self->muladd_func_ptr = Lorenz_postprocessing_ireva;
            break;

        case 21:
            self->muladd_func_ptr = Lorenz_postprocessing_areva;
            break;

        case 22:
            self->muladd_func_ptr = Lorenz_postprocessing_revareva;
            break;
    }
}

static void
Lorenz_compute_next_data_frame(Lorenz *self)
{
    (*self->proc_func_ptr)(self);
    (*self->muladd_func_ptr)(self);
}

static int
Lorenz_traverse(Lorenz *self, visitproc visit, void *arg)
{
    pyo_VISIT
    Py_VISIT(self->pitch);
    Py_VISIT(self->chaos);
    return 0;
}

static int
Lorenz_clear(Lorenz *self)
{
    pyo_CLEAR
    Py_CLEAR(self->pitch);
    Py_CLEAR(self->chaos);
    return 0;
}

static void
Lorenz_dealloc(Lorenz* self)
{
    pyo_DEALLOC
    PyMem_RawFree(self->altBuffer);
    Lorenz_clear(self);
    Py_TYPE(self->stream)->tp_free((PyObject*)self->stream);
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject *
Lorenz_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    int i;
    PyObject *pitchtmp = NULL, *chaostmp = NULL, *multmp = NULL, *addtmp = NULL;
    Lorenz *self;
    self = (Lorenz *)type->tp_alloc(type, 0);

    self->pitch = PyFloat_FromDouble(0.25);
    self->chaos = PyFloat_FromDouble(0.5);
    self->pA = 10.0;
    self->pB = 28.0;
    self->vDX = self->vDY = self->vDZ = 0.0;
    self->vX = self->vY = self->vZ = 1.0;
    self->modebuffer[0] = 0;
    self->modebuffer[1] = 0;
    self->modebuffer[2] = 0;
    self->modebuffer[3] = 0;

    INIT_OBJECT_COMMON
    Stream_setFunctionPtr(self->stream, Lorenz_compute_next_data_frame);
    self->mode_func_ptr = Lorenz_setProcMode;

    self->oneOnSr = 1.0 / self->sr;

    static char *kwlist[] = {"pitch", "chaos", "mul", "add", NULL};

    if (! PyArg_ParseTupleAndKeywords(args, kwds, "|OOOO", kwlist, &pitchtmp, &chaostmp, &multmp, &addtmp))
        Py_RETURN_NONE;

    if (pitchtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setPitch", "O", pitchtmp);
    }

    if (chaostmp)
    {
        PyObject_CallMethod((PyObject *)self, "setChaos", "O", chaostmp);
    }

    if (multmp)
    {
        PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
    }

    if (addtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
    }

    PyObject_CallMethod(self->server, "addStream", "O", self->stream);

    self->altBuffer = (MYFLT *)PyMem_RawRealloc(self->altBuffer, self->bufsize * sizeof(MYFLT));

    for (i = 0; i < self->bufsize; i++)
    {
        self->altBuffer[i] = 0.0;
    }

    (*self->mode_func_ptr)(self);

    return (PyObject *)self;
}

static PyObject * Lorenz_getServer(Lorenz* self) { GET_SERVER };
static PyObject * Lorenz_getStream(Lorenz* self) { GET_STREAM };
static PyObject * Lorenz_setMul(Lorenz *self, PyObject *arg) { SET_MUL };
static PyObject * Lorenz_setAdd(Lorenz *self, PyObject *arg) { SET_ADD };
static PyObject * Lorenz_setSub(Lorenz *self, PyObject *arg) { SET_SUB };
static PyObject * Lorenz_setDiv(Lorenz *self, PyObject *arg) { SET_DIV };

static PyObject * Lorenz_play(Lorenz *self, PyObject *args, PyObject *kwds) { PLAY };
static PyObject * Lorenz_out(Lorenz *self, PyObject *args, PyObject *kwds) { OUT };
static PyObject * Lorenz_stop(Lorenz *self, PyObject *args, PyObject *kwds) { STOP };

static PyObject * Lorenz_multiply(Lorenz *self, PyObject *arg) { MULTIPLY };
static PyObject * Lorenz_inplace_multiply(Lorenz *self, PyObject *arg) { INPLACE_MULTIPLY };
static PyObject * Lorenz_add(Lorenz *self, PyObject *arg) { ADD };
static PyObject * Lorenz_inplace_add(Lorenz *self, PyObject *arg) { INPLACE_ADD };
static PyObject * Lorenz_sub(Lorenz *self, PyObject *arg) { SUB };
static PyObject * Lorenz_inplace_sub(Lorenz *self, PyObject *arg) { INPLACE_SUB };
static PyObject * Lorenz_div(Lorenz *self, PyObject *arg) { DIV };
static PyObject * Lorenz_inplace_div(Lorenz *self, PyObject *arg) { INPLACE_DIV };

static PyObject * Lorenz_setPitch(Lorenz *self, PyObject *arg) { SET_PARAM(self->pitch, self->pitch_stream, 2); }
static PyObject * Lorenz_setChaos(Lorenz *self, PyObject *arg) { SET_PARAM(self->chaos, self->chaos_stream, 3); }

MYFLT *
Lorenz_getAltBuffer(Lorenz *self)
{
    return (MYFLT *)self->altBuffer;
}

static PyMemberDef Lorenz_members[] =
{
    {"server", T_OBJECT_EX, offsetof(Lorenz, server), 0, "Pyo server."},
    {"stream", T_OBJECT_EX, offsetof(Lorenz, stream), 0, "Stream object."},
    {"pitch", T_OBJECT_EX, offsetof(Lorenz, pitch), 0, "Pitch."},
    {"chaos", T_OBJECT_EX, offsetof(Lorenz, chaos), 0, "Chaotic behavior."},
    {"mul", T_OBJECT_EX, offsetof(Lorenz, mul), 0, "Mul factor."},
    {"add", T_OBJECT_EX, offsetof(Lorenz, add), 0, "Add factor."},
    {NULL}  /* Sentinel */
};

static PyMethodDef Lorenz_methods[] =
{
    {"getServer", (PyCFunction)Lorenz_getServer, METH_NOARGS, "Returns server object."},
    {"_getStream", (PyCFunction)Lorenz_getStream, METH_NOARGS, "Returns stream object."},
    {"play", (PyCFunction)Lorenz_play, METH_VARARGS | METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
    {"out", (PyCFunction)Lorenz_out, METH_VARARGS | METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
    {"stop", (PyCFunction)Lorenz_stop, METH_VARARGS | METH_KEYWORDS, "Stops computing."},
    {"setPitch", (PyCFunction)Lorenz_setPitch, METH_O, "Sets oscillator pitch."},
    {"setChaos", (PyCFunction)Lorenz_setChaos, METH_O, "Sets oscillator chaotic behavior."},
    {"setMul", (PyCFunction)Lorenz_setMul, METH_O, "Sets Lorenz mul factor."},
    {"setAdd", (PyCFunction)Lorenz_setAdd, METH_O, "Sets Lorenz add factor."},
    {"setSub", (PyCFunction)Lorenz_setSub, METH_O, "Sets inverse add factor."},
    {"setDiv", (PyCFunction)Lorenz_setDiv, METH_O, "Sets inverse mul factor."},
    {NULL}  /* Sentinel */
};

static PyNumberMethods Lorenz_as_number =
{
    (binaryfunc)Lorenz_add,                      /*nb_add*/
    (binaryfunc)Lorenz_sub,                 /*nb_subtract*/
    (binaryfunc)Lorenz_multiply,                 /*nb_multiply*/
    0,                /*nb_remainder*/
    0,                   /*nb_divmod*/
    0,                   /*nb_power*/
    0,                  /*nb_neg*/
    0,                /*nb_pos*/
    0,                  /*(unaryfunc)array_abs*/
    0,                    /*nb_nonzero*/
    0,                    /*nb_invert*/
    0,               /*nb_lshift*/
    0,              /*nb_rshift*/
    0,              /*nb_and*/
    0,              /*nb_xor*/
    0,               /*nb_or*/
    0,                       /*nb_int*/
    0,                      /*nb_long*/
    0,                     /*nb_float*/
    (binaryfunc)Lorenz_inplace_add,              /*inplace_add*/
    (binaryfunc)Lorenz_inplace_sub,         /*inplace_subtract*/
    (binaryfunc)Lorenz_inplace_multiply,         /*inplace_multiply*/
    0,        /*inplace_remainder*/
    0,           /*inplace_power*/
    0,       /*inplace_lshift*/
    0,      /*inplace_rshift*/
    0,      /*inplace_and*/
    0,      /*inplace_xor*/
    0,       /*inplace_or*/
    0,             /*nb_floor_divide*/
    (binaryfunc)Lorenz_div,                       /*nb_true_divide*/
    0,     /*nb_inplace_floor_divide*/
    (binaryfunc)Lorenz_inplace_div,                       /*nb_inplace_true_divide*/
    0,                     /* nb_index */
};

PyTypeObject LorenzType =
{
    PyVarObject_HEAD_INIT(NULL, 0)
    "_pyo.Lorenz_base",         /*tp_name*/
    sizeof(Lorenz),         /*tp_basicsize*/
    0,                         /*tp_itemsize*/
    (destructor)Lorenz_dealloc, /*tp_dealloc*/
    0,                         /*tp_print*/
    0,                         /*tp_getattr*/
    0,                         /*tp_setattr*/
    0,                         /*tp_as_async (tp_compare in Python 2)*/
    0,                         /*tp_repr*/
    &Lorenz_as_number,             /*tp_as_number*/
    0,                         /*tp_as_sequence*/
    0,                         /*tp_as_mapping*/
    0,                         /*tp_hash */
    0,                         /*tp_call*/
    0,                         /*tp_str*/
    0,                         /*tp_getattro*/
    0,                         /*tp_setattro*/
    0,                         /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,  /*tp_flags*/
    "Lorenz objects. Lorenz attractor.",           /* tp_doc */
    (traverseproc)Lorenz_traverse,   /* tp_traverse */
    (inquiry)Lorenz_clear,           /* tp_clear */
    0,                     /* tp_richcompare */
    0,                     /* tp_weaklistoffset */
    0,                     /* tp_iter */
    0,                     /* tp_iternext */
    Lorenz_methods,             /* tp_methods */
    Lorenz_members,             /* tp_members */
    0,                      /* tp_getset */
    0,                         /* tp_base */
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    0,                         /* tp_dictoffset */
    0,      /* tp_init */
    0,                         /* tp_alloc */
    Lorenz_new,                 /* tp_new */
};

typedef struct
{
    pyo_audio_HEAD
    Lorenz *mainLorenz;
    int modebuffer[2];
} LorenzAlt;

static void LorenzAlt_postprocessing_ii(LorenzAlt *self) { POST_PROCESSING_II };
static void LorenzAlt_postprocessing_ai(LorenzAlt *self) { POST_PROCESSING_AI };
static void LorenzAlt_postprocessing_ia(LorenzAlt *self) { POST_PROCESSING_IA };
static void LorenzAlt_postprocessing_aa(LorenzAlt *self) { POST_PROCESSING_AA };
static void LorenzAlt_postprocessing_ireva(LorenzAlt *self) { POST_PROCESSING_IREVA };
static void LorenzAlt_postprocessing_areva(LorenzAlt *self) { POST_PROCESSING_AREVA };
static void LorenzAlt_postprocessing_revai(LorenzAlt *self) { POST_PROCESSING_REVAI };
static void LorenzAlt_postprocessing_revaa(LorenzAlt *self) { POST_PROCESSING_REVAA };
static void LorenzAlt_postprocessing_revareva(LorenzAlt *self) { POST_PROCESSING_REVAREVA };

static void
LorenzAlt_setProcMode(LorenzAlt *self)
{
    int muladdmode;
    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;

    switch (muladdmode)
    {
        case 0:
            self->muladd_func_ptr = LorenzAlt_postprocessing_ii;
            break;

        case 1:
            self->muladd_func_ptr = LorenzAlt_postprocessing_ai;
            break;

        case 2:
            self->muladd_func_ptr = LorenzAlt_postprocessing_revai;
            break;

        case 10:
            self->muladd_func_ptr = LorenzAlt_postprocessing_ia;
            break;

        case 11:
            self->muladd_func_ptr = LorenzAlt_postprocessing_aa;
            break;

        case 12:
            self->muladd_func_ptr = LorenzAlt_postprocessing_revaa;
            break;

        case 20:
            self->muladd_func_ptr = LorenzAlt_postprocessing_ireva;
            break;

        case 21:
            self->muladd_func_ptr = LorenzAlt_postprocessing_areva;
            break;

        case 22:
            self->muladd_func_ptr = LorenzAlt_postprocessing_revareva;
            break;
    }
}

static void
LorenzAlt_compute_next_data_frame(LorenzAlt *self)
{
    int i;
    MYFLT *tmp;
    tmp = Lorenz_getAltBuffer((Lorenz *)self->mainLorenz);

    for (i = 0; i < self->bufsize; i++)
    {
        self->data[i] = tmp[i];
    }

    (*self->muladd_func_ptr)(self);
}

static int
LorenzAlt_traverse(LorenzAlt *self, visitproc visit, void *arg)
{
    pyo_VISIT
    Py_VISIT(self->mainLorenz);
    return 0;
}

static int
LorenzAlt_clear(LorenzAlt *self)
{
    pyo_CLEAR
    Py_CLEAR(self->mainLorenz);
    return 0;
}

static void
LorenzAlt_dealloc(LorenzAlt* self)
{
    pyo_DEALLOC
    LorenzAlt_clear(self);
    Py_TYPE(self->stream)->tp_free((PyObject*)self->stream);
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject *
LorenzAlt_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    int i;
    PyObject *maintmp = NULL, *multmp = NULL, *addtmp = NULL;
    LorenzAlt *self;
    self = (LorenzAlt *)type->tp_alloc(type, 0);

    self->modebuffer[0] = 0;
    self->modebuffer[1] = 0;

    INIT_OBJECT_COMMON
    Stream_setFunctionPtr(self->stream, LorenzAlt_compute_next_data_frame);
    self->mode_func_ptr = LorenzAlt_setProcMode;

    static char *kwlist[] = {"mainLorenz", "mul", "alt", NULL};

    if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|OO", kwlist, &maintmp, &multmp, &addtmp))
        Py_RETURN_NONE;

    self->mainLorenz = (Lorenz *)maintmp;
    Py_INCREF(self->mainLorenz);

    if (multmp)
    {
        PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
    }

    if (addtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
    }

    PyObject_CallMethod(self->server, "addStream", "O", self->stream);

    (*self->mode_func_ptr)(self);

    return (PyObject *)self;
}

static PyObject * LorenzAlt_getServer(LorenzAlt* self) { GET_SERVER };
static PyObject * LorenzAlt_getStream(LorenzAlt* self) { GET_STREAM };
static PyObject * LorenzAlt_setMul(LorenzAlt *self, PyObject *arg) { SET_MUL };
static PyObject * LorenzAlt_setAdd(LorenzAlt *self, PyObject *arg) { SET_ADD };
static PyObject * LorenzAlt_setSub(LorenzAlt *self, PyObject *arg) { SET_SUB };
static PyObject * LorenzAlt_setDiv(LorenzAlt *self, PyObject *arg) { SET_DIV };

static PyObject * LorenzAlt_play(LorenzAlt *self, PyObject *args, PyObject *kwds) { PLAY };
static PyObject * LorenzAlt_out(LorenzAlt *self, PyObject *args, PyObject *kwds) { OUT };
static PyObject * LorenzAlt_stop(LorenzAlt *self, PyObject *args, PyObject *kwds) { STOP };

static PyObject * LorenzAlt_multiply(LorenzAlt *self, PyObject *arg) { MULTIPLY };
static PyObject * LorenzAlt_inplace_multiply(LorenzAlt *self, PyObject *arg) { INPLACE_MULTIPLY };
static PyObject * LorenzAlt_add(LorenzAlt *self, PyObject *arg) { ADD };
static PyObject * LorenzAlt_inplace_add(LorenzAlt *self, PyObject *arg) { INPLACE_ADD };
static PyObject * LorenzAlt_sub(LorenzAlt *self, PyObject *arg) { SUB };
static PyObject * LorenzAlt_inplace_sub(LorenzAlt *self, PyObject *arg) { INPLACE_SUB };
static PyObject * LorenzAlt_div(LorenzAlt *self, PyObject *arg) { DIV };
static PyObject * LorenzAlt_inplace_div(LorenzAlt *self, PyObject *arg) { INPLACE_DIV };

static PyMemberDef LorenzAlt_members[] =
{
    {"server", T_OBJECT_EX, offsetof(LorenzAlt, server), 0, "Pyo server."},
    {"stream", T_OBJECT_EX, offsetof(LorenzAlt, stream), 0, "Stream object."},
    {"mul", T_OBJECT_EX, offsetof(LorenzAlt, mul), 0, "Mul factor."},
    {"add", T_OBJECT_EX, offsetof(LorenzAlt, add), 0, "Add factor."},
    {NULL}  /* Sentinel */
};

static PyMethodDef LorenzAlt_methods[] =
{
    {"getServer", (PyCFunction)LorenzAlt_getServer, METH_NOARGS, "Returns server object."},
    {"_getStream", (PyCFunction)LorenzAlt_getStream, METH_NOARGS, "Returns stream object."},
    {"play", (PyCFunction)LorenzAlt_play, METH_VARARGS | METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
    {"out", (PyCFunction)LorenzAlt_out, METH_VARARGS | METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
    {"stop", (PyCFunction)LorenzAlt_stop, METH_VARARGS | METH_KEYWORDS, "Stops computing."},
    {"setMul", (PyCFunction)LorenzAlt_setMul, METH_O, "Sets oscillator mul factor."},
    {"setAdd", (PyCFunction)LorenzAlt_setAdd, METH_O, "Sets oscillator add factor."},
    {"setSub", (PyCFunction)LorenzAlt_setSub, METH_O, "Sets inverse add factor."},
    {"setDiv", (PyCFunction)LorenzAlt_setDiv, METH_O, "Sets inverse mul factor."},
    {NULL}  /* Sentinel */
};
static PyNumberMethods LorenzAlt_as_number =
{
    (binaryfunc)LorenzAlt_add,                         /*nb_add*/
    (binaryfunc)LorenzAlt_sub,                         /*nb_subtract*/
    (binaryfunc)LorenzAlt_multiply,                    /*nb_multiply*/
    0,                                              /*nb_remainder*/
    0,                                              /*nb_divmod*/
    0,                                              /*nb_power*/
    0,                                              /*nb_neg*/
    0,                                              /*nb_pos*/
    0,                                              /*(unaryfunc)array_abs,*/
    0,                                              /*nb_nonzero*/
    0,                                              /*nb_invert*/
    0,                                              /*nb_lshift*/
    0,                                              /*nb_rshift*/
    0,                                              /*nb_and*/
    0,                                              /*nb_xor*/
    0,                                              /*nb_or*/
    0,                                              /*nb_int*/
    0,                                              /*nb_long*/
    0,                                              /*nb_float*/
    (binaryfunc)LorenzAlt_inplace_add,                 /*inplace_add*/
    (binaryfunc)LorenzAlt_inplace_sub,                 /*inplace_subtract*/
    (binaryfunc)LorenzAlt_inplace_multiply,            /*inplace_multiply*/
    0,                                              /*inplace_remainder*/
    0,                                              /*inplace_power*/
    0,                                              /*inplace_lshift*/
    0,                                              /*inplace_rshift*/
    0,                                              /*inplace_and*/
    0,                                              /*inplace_xor*/
    0,                                              /*inplace_or*/
    0,                                              /*nb_floor_divide*/
    (binaryfunc)LorenzAlt_div,                       /*nb_true_divide*/
    0,                                              /*nb_inplace_floor_divide*/
    (binaryfunc)LorenzAlt_inplace_div,                       /*nb_inplace_true_divide*/
    0,                                              /* nb_index */
};

PyTypeObject LorenzAltType =
{
    PyVarObject_HEAD_INIT(NULL, 0)
    "_pyo.LorenzAlt_base",         /*tp_name*/
    sizeof(LorenzAlt),         /*tp_basicsize*/
    0,                         /*tp_itemsize*/
    (destructor)LorenzAlt_dealloc, /*tp_dealloc*/
    0,                         /*tp_print*/
    0,                         /*tp_getattr*/
    0,                         /*tp_setattr*/
    0,                         /*tp_as_async (tp_compare in Python 2)*/
    0,                         /*tp_repr*/
    &LorenzAlt_as_number,             /*tp_as_number*/
    0,                         /*tp_as_sequence*/
    0,                         /*tp_as_mapping*/
    0,                         /*tp_hash */
    0,                         /*tp_call*/
    0,                         /*tp_str*/
    0,                         /*tp_getattro*/
    0,                         /*tp_setattro*/
    0,                         /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,  /*tp_flags*/
    "LorenzAlt objects. Sends the alternate signal of a Lorenz attractor.",           /* tp_doc */
    (traverseproc)LorenzAlt_traverse,   /* tp_traverse */
    (inquiry)LorenzAlt_clear,           /* tp_clear */
    0,                     /* tp_richcompare */
    0,                     /* tp_weaklistoffset */
    0,                     /* tp_iter */
    0,                     /* tp_iternext */
    LorenzAlt_methods,             /* tp_methods */
    LorenzAlt_members,             /* tp_members */
    0,                      /* tp_getset */
    0,                         /* tp_base */
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    0,                         /* tp_dictoffset */
    0,      /* tp_init */
    0,                         /* tp_alloc */
    LorenzAlt_new,                 /* tp_new */
};

/* ChenLee object */
typedef struct
{
    pyo_audio_HEAD
    PyObject *pitch;
    Stream *pitch_stream;
    PyObject *chaos;
    Stream *chaos_stream;
    MYFLT *altBuffer;
    MYFLT vDX;
    MYFLT vDY;
    MYFLT vDZ;
    MYFLT vX;
    MYFLT vY;
    MYFLT vZ;
    MYFLT pA;
    MYFLT pB;
    MYFLT oneOnSr;
    int modebuffer[4];
} ChenLee;

static void
ChenLee_readframes_ii(ChenLee *self)
{
    MYFLT delta, pit, chao;
    int i;

    pit = PyFloat_AS_DOUBLE(self->pitch);
    chao = PyFloat_AS_DOUBLE(self->chaos);

    if (pit < 0.0)
        pit = 1.0;
    else if (pit > 1.0)
        pit = 125.0;
    else
        pit = pit * 124.0 + 1.0;

    delta = self->oneOnSr * pit;

    if (chao < 0.0)
        chao = 4.0;
    else if (chao > 1.0)
        chao = 2.51;
    else
        chao = (1.0 - chao) * 1.49 + 2.51;

    for (i = 0; i < self->bufsize; i++)
    {
        self->vDX = -self->vY * self->vZ + self->pA * self->vX;
        self->vDY = self->vX * self->vZ - self->pB * self->vY;
        self->vDZ = self->vX * self->vY / 3.0 - chao * self->vZ;

        self->vX += self->vDX * delta;
        self->vX = (self->vX > 50.0) ? 50.0 : (self->vX < -50.0) ? -50.0 : self->vX;
        self->vY += self->vDY * delta;
        self->vY = (self->vY > 50.0) ? 50.0 : (self->vY < -50.0) ? -50.0 : self->vY;
        self->vZ += self->vDZ * delta;

        self->data[i] = self->vX * CHENLEE_SCALE;
        self->altBuffer[i] = self->vY * CHENLEE_ALT_SCALE;
    }
}

static void
ChenLee_readframes_ai(ChenLee *self)
{
    MYFLT delta, pit, chao;
    int i;

    MYFLT *fr = Stream_getData((Stream *)self->pitch_stream);
    chao = PyFloat_AS_DOUBLE(self->chaos);

    if (chao < 0.0)
        chao = 4.0;
    else if (chao > 1.0)
        chao = 2.51;
    else
        chao = (1.0 - chao) * 1.49 + 2.51;

    for (i = 0; i < self->bufsize; i++)
    {
        pit = fr[i];

        if (pit < 0.0)
            pit = 1.0;
        else if (pit > 1.0)
            pit = 125.0;
        else
            pit = pit * 124.0 + 1.0;

        delta = self->oneOnSr * pit;
        self->vDX = -self->vY * self->vZ + self->pA * self->vX;
        self->vDY = self->vX * self->vZ - self->pB * self->vY;
        self->vDZ = self->vX * self->vY / 3.0 - chao * self->vZ;

        self->vX += self->vDX * delta;
        self->vX = (self->vX > 50.0) ? 50.0 : (self->vX < -50.0) ? -50.0 : self->vX;
        self->vY += self->vDY * delta;
        self->vY = (self->vY > 50.0) ? 50.0 : (self->vY < -50.0) ? -50.0 : self->vY;
        self->vZ += self->vDZ * delta;

        self->data[i] = self->vX * CHENLEE_SCALE;
        self->altBuffer[i] = self->vY * CHENLEE_ALT_SCALE;
    }
}

static void
ChenLee_readframes_ia(ChenLee *self)
{
    MYFLT delta, pit, chao;
    int i;

    pit = PyFloat_AS_DOUBLE(self->pitch);
    MYFLT *ch = Stream_getData((Stream *)self->chaos_stream);

    if (pit < 0.0)
        pit = 1.0;
    else if (pit > 1.0)
        pit = 125.0;
    else
        pit = pit * 124.0 + 1.0;

    delta = self->oneOnSr * pit;

    for (i = 0; i < self->bufsize; i++)
    {
        chao = ch[i];

        if (chao < 0.0)
            chao = 4.0;
        else if (chao > 1.0)
            chao = 2.51;
        else
            chao = (1.0 - chao) * 1.49 + 2.51;

        self->vDX = -self->vY * self->vZ + self->pA * self->vX;
        self->vDY = self->vX * self->vZ - self->pB * self->vY;
        self->vDZ = self->vX * self->vY / 3.0 - chao * self->vZ;

        self->vX += self->vDX * delta;
        self->vX = (self->vX > 50.0) ? 50.0 : (self->vX < -50.0) ? -50.0 : self->vX;
        self->vY += self->vDY * delta;
        self->vY = (self->vY > 50.0) ? 50.0 : (self->vY < -50.0) ? -50.0 : self->vY;
        self->vZ += self->vDZ * delta;

        self->data[i] = self->vX * CHENLEE_SCALE;
        self->altBuffer[i] = self->vY * CHENLEE_ALT_SCALE;
    }
}

static void
ChenLee_readframes_aa(ChenLee *self)
{
    MYFLT delta, pit, chao;
    int i;

    MYFLT *fr = Stream_getData((Stream *)self->pitch_stream);
    MYFLT *ch = Stream_getData((Stream *)self->chaos_stream);

    for (i = 0; i < self->bufsize; i++)
    {
        pit = fr[i];

        if (pit < 0.0)
            pit = 1.0;
        else if (pit > 1.0)
            pit = 125.0;
        else
            pit = pit * 124.0 + 1.0;

        delta = self->oneOnSr * pit;

        chao = ch[i];

        if (chao < 0.0)
            chao = 4.0;
        else if (chao > 1.0)
            chao = 2.51;
        else
            chao = (1.0 - chao) * 1.49 + 2.51;

        self->vDX = -self->vY * self->vZ + self->pA * self->vX;
        self->vDY = self->vX * self->vZ - self->pB * self->vY;
        self->vDZ = self->vX * self->vY / 3.0 - chao * self->vZ;

        self->vX += self->vDX * delta;
        self->vX = (self->vX > 50.0) ? 50.0 : (self->vX < -50.0) ? -50.0 : self->vX;
        self->vY += self->vDY * delta;
        self->vY = (self->vY > 50.0) ? 50.0 : (self->vY < -50.0) ? -50.0 : self->vY;
        self->vZ += self->vDZ * delta;

        self->data[i] = self->vX * CHENLEE_SCALE;
        self->altBuffer[i] = self->vY * CHENLEE_ALT_SCALE;
    }
}

static void ChenLee_postprocessing_ii(ChenLee *self) { POST_PROCESSING_II };
static void ChenLee_postprocessing_ai(ChenLee *self) { POST_PROCESSING_AI };
static void ChenLee_postprocessing_ia(ChenLee *self) { POST_PROCESSING_IA };
static void ChenLee_postprocessing_aa(ChenLee *self) { POST_PROCESSING_AA };
static void ChenLee_postprocessing_ireva(ChenLee *self) { POST_PROCESSING_IREVA };
static void ChenLee_postprocessing_areva(ChenLee *self) { POST_PROCESSING_AREVA };
static void ChenLee_postprocessing_revai(ChenLee *self) { POST_PROCESSING_REVAI };
static void ChenLee_postprocessing_revaa(ChenLee *self) { POST_PROCESSING_REVAA };
static void ChenLee_postprocessing_revareva(ChenLee *self) { POST_PROCESSING_REVAREVA };

static void
ChenLee_setProcMode(ChenLee *self)
{
    int procmode, muladdmode;
    procmode = self->modebuffer[2] + self->modebuffer[3] * 10;
    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;

    switch (procmode)
    {
        case 0:
            self->proc_func_ptr = ChenLee_readframes_ii;
            break;

        case 1:
            self->proc_func_ptr = ChenLee_readframes_ai;
            break;

        case 10:
            self->proc_func_ptr = ChenLee_readframes_ia;
            break;

        case 11:
            self->proc_func_ptr = ChenLee_readframes_aa;
            break;
    }

    switch (muladdmode)
    {
        case 0:
            self->muladd_func_ptr = ChenLee_postprocessing_ii;
            break;

        case 1:
            self->muladd_func_ptr = ChenLee_postprocessing_ai;
            break;

        case 2:
            self->muladd_func_ptr = ChenLee_postprocessing_revai;
            break;

        case 10:
            self->muladd_func_ptr = ChenLee_postprocessing_ia;
            break;

        case 11:
            self->muladd_func_ptr = ChenLee_postprocessing_aa;
            break;

        case 12:
            self->muladd_func_ptr = ChenLee_postprocessing_revaa;
            break;

        case 20:
            self->muladd_func_ptr = ChenLee_postprocessing_ireva;
            break;

        case 21:
            self->muladd_func_ptr = ChenLee_postprocessing_areva;
            break;

        case 22:
            self->muladd_func_ptr = ChenLee_postprocessing_revareva;
            break;
    }
}

static void
ChenLee_compute_next_data_frame(ChenLee *self)
{
    (*self->proc_func_ptr)(self);
    (*self->muladd_func_ptr)(self);
}

static int
ChenLee_traverse(ChenLee *self, visitproc visit, void *arg)
{
    pyo_VISIT
    Py_VISIT(self->pitch);
    Py_VISIT(self->chaos);
    return 0;
}

static int
ChenLee_clear(ChenLee *self)
{
    pyo_CLEAR
    Py_CLEAR(self->pitch);
    Py_CLEAR(self->chaos);
    return 0;
}

static void
ChenLee_dealloc(ChenLee* self)
{
    pyo_DEALLOC
    PyMem_RawFree(self->altBuffer);
    ChenLee_clear(self);
    Py_TYPE(self->stream)->tp_free((PyObject*)self->stream);
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject *
ChenLee_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    int i;
    PyObject *pitchtmp = NULL, *chaostmp = NULL, *multmp = NULL, *addtmp = NULL;
    ChenLee *self;
    self = (ChenLee *)type->tp_alloc(type, 0);

    self->pitch = PyFloat_FromDouble(0.25);
    self->chaos = PyFloat_FromDouble(0.5);
    self->pA = 5.0;
    self->pB = 10.0;
    self->vDX = self->vDY = self->vDZ = 0.0;
    self->vX = self->vY = self->vZ = 1.0;
    self->modebuffer[0] = 0;
    self->modebuffer[1] = 0;
    self->modebuffer[2] = 0;
    self->modebuffer[3] = 0;

    INIT_OBJECT_COMMON
    Stream_setFunctionPtr(self->stream, ChenLee_compute_next_data_frame);
    self->mode_func_ptr = ChenLee_setProcMode;

    self->oneOnSr = 1.0 / self->sr;

    static char *kwlist[] = {"pitch", "chaos", "mul", "add", NULL};

    if (! PyArg_ParseTupleAndKeywords(args, kwds, "|OOOO", kwlist, &pitchtmp, &chaostmp, &multmp, &addtmp))
        Py_RETURN_NONE;

    if (pitchtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setPitch", "O", pitchtmp);
    }

    if (chaostmp)
    {
        PyObject_CallMethod((PyObject *)self, "setChaos", "O", chaostmp);
    }

    if (multmp)
    {
        PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
    }

    if (addtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
    }

    PyObject_CallMethod(self->server, "addStream", "O", self->stream);

    self->altBuffer = (MYFLT *)PyMem_RawRealloc(self->altBuffer, self->bufsize * sizeof(MYFLT));

    for (i = 0; i < self->bufsize; i++)
    {
        self->altBuffer[i] = 0.0;
    }

    (*self->mode_func_ptr)(self);

    return (PyObject *)self;
}

static PyObject * ChenLee_getServer(ChenLee* self) { GET_SERVER };
static PyObject * ChenLee_getStream(ChenLee* self) { GET_STREAM };
static PyObject * ChenLee_setMul(ChenLee *self, PyObject *arg) { SET_MUL };
static PyObject * ChenLee_setAdd(ChenLee *self, PyObject *arg) { SET_ADD };
static PyObject * ChenLee_setSub(ChenLee *self, PyObject *arg) { SET_SUB };
static PyObject * ChenLee_setDiv(ChenLee *self, PyObject *arg) { SET_DIV };

static PyObject * ChenLee_play(ChenLee *self, PyObject *args, PyObject *kwds) { PLAY };
static PyObject * ChenLee_out(ChenLee *self, PyObject *args, PyObject *kwds) { OUT };
static PyObject * ChenLee_stop(ChenLee *self, PyObject *args, PyObject *kwds) { STOP };

static PyObject * ChenLee_multiply(ChenLee *self, PyObject *arg) { MULTIPLY };
static PyObject * ChenLee_inplace_multiply(ChenLee *self, PyObject *arg) { INPLACE_MULTIPLY };
static PyObject * ChenLee_add(ChenLee *self, PyObject *arg) { ADD };
static PyObject * ChenLee_inplace_add(ChenLee *self, PyObject *arg) { INPLACE_ADD };
static PyObject * ChenLee_sub(ChenLee *self, PyObject *arg) { SUB };
static PyObject * ChenLee_inplace_sub(ChenLee *self, PyObject *arg) { INPLACE_SUB };
static PyObject * ChenLee_div(ChenLee *self, PyObject *arg) { DIV };
static PyObject * ChenLee_inplace_div(ChenLee *self, PyObject *arg) { INPLACE_DIV };

static PyObject * ChenLee_setPitch(ChenLee *self, PyObject *arg) { SET_PARAM(self->pitch, self->pitch_stream, 2); }
static PyObject * ChenLee_setChaos(ChenLee *self, PyObject *arg) { SET_PARAM(self->chaos, self->chaos_stream, 3); }

MYFLT *
ChenLee_getAltBuffer(ChenLee *self)
{
    return (MYFLT *)self->altBuffer;
}

static PyMemberDef ChenLee_members[] =
{
    {"server", T_OBJECT_EX, offsetof(ChenLee, server), 0, "Pyo server."},
    {"stream", T_OBJECT_EX, offsetof(ChenLee, stream), 0, "Stream object."},
    {"pitch", T_OBJECT_EX, offsetof(ChenLee, pitch), 0, "Pitch."},
    {"chaos", T_OBJECT_EX, offsetof(ChenLee, chaos), 0, "Chaotic behavior."},
    {"mul", T_OBJECT_EX, offsetof(ChenLee, mul), 0, "Mul factor."},
    {"add", T_OBJECT_EX, offsetof(ChenLee, add), 0, "Add factor."},
    {NULL}  /* Sentinel */
};

static PyMethodDef ChenLee_methods[] =
{
    {"getServer", (PyCFunction)ChenLee_getServer, METH_NOARGS, "Returns server object."},
    {"_getStream", (PyCFunction)ChenLee_getStream, METH_NOARGS, "Returns stream object."},
    {"play", (PyCFunction)ChenLee_play, METH_VARARGS | METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
    {"out", (PyCFunction)ChenLee_out, METH_VARARGS | METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
    {"stop", (PyCFunction)ChenLee_stop, METH_VARARGS | METH_KEYWORDS, "Stops computing."},
    {"setPitch", (PyCFunction)ChenLee_setPitch, METH_O, "Sets oscillator pitch."},
    {"setChaos", (PyCFunction)ChenLee_setChaos, METH_O, "Sets oscillator chaotic behavior."},
    {"setMul", (PyCFunction)ChenLee_setMul, METH_O, "Sets ChenLee mul factor."},
    {"setAdd", (PyCFunction)ChenLee_setAdd, METH_O, "Sets ChenLee add factor."},
    {"setSub", (PyCFunction)ChenLee_setSub, METH_O, "Sets inverse add factor."},
    {"setDiv", (PyCFunction)ChenLee_setDiv, METH_O, "Sets inverse mul factor."},
    {NULL}  /* Sentinel */
};

static PyNumberMethods ChenLee_as_number =
{
    (binaryfunc)ChenLee_add,                      /*nb_add*/
    (binaryfunc)ChenLee_sub,                 /*nb_subtract*/
    (binaryfunc)ChenLee_multiply,                 /*nb_multiply*/
    0,                /*nb_remainder*/
    0,                   /*nb_divmod*/
    0,                   /*nb_power*/
    0,                  /*nb_neg*/
    0,                /*nb_pos*/
    0,                  /*(unaryfunc)array_abs*/
    0,                    /*nb_nonzero*/
    0,                    /*nb_invert*/
    0,               /*nb_lshift*/
    0,              /*nb_rshift*/
    0,              /*nb_and*/
    0,              /*nb_xor*/
    0,               /*nb_or*/
    0,                       /*nb_int*/
    0,                      /*nb_long*/
    0,                     /*nb_float*/
    (binaryfunc)ChenLee_inplace_add,              /*inplace_add*/
    (binaryfunc)ChenLee_inplace_sub,         /*inplace_subtract*/
    (binaryfunc)ChenLee_inplace_multiply,         /*inplace_multiply*/
    0,        /*inplace_remainder*/
    0,           /*inplace_power*/
    0,       /*inplace_lshift*/
    0,      /*inplace_rshift*/
    0,      /*inplace_and*/
    0,      /*inplace_xor*/
    0,       /*inplace_or*/
    0,             /*nb_floor_divide*/
    (binaryfunc)ChenLee_div,                       /*nb_true_divide*/
    0,     /*nb_inplace_floor_divide*/
    (binaryfunc)ChenLee_inplace_div,                       /*nb_inplace_true_divide*/
    0,                     /* nb_index */
};

PyTypeObject ChenLeeType =
{
    PyVarObject_HEAD_INIT(NULL, 0)
    "_pyo.ChenLee_base",         /*tp_name*/
    sizeof(ChenLee),         /*tp_basicsize*/
    0,                         /*tp_itemsize*/
    (destructor)ChenLee_dealloc, /*tp_dealloc*/
    0,                         /*tp_print*/
    0,                         /*tp_getattr*/
    0,                         /*tp_setattr*/
    0,                         /*tp_as_async (tp_compare in Python 2)*/
    0,                         /*tp_repr*/
    &ChenLee_as_number,             /*tp_as_number*/
    0,                         /*tp_as_sequence*/
    0,                         /*tp_as_mapping*/
    0,                         /*tp_hash */
    0,                         /*tp_call*/
    0,                         /*tp_str*/
    0,                         /*tp_getattro*/
    0,                         /*tp_setattro*/
    0,                         /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,  /*tp_flags*/
    "ChenLee objects. ChenLee attractor.",           /* tp_doc */
    (traverseproc)ChenLee_traverse,   /* tp_traverse */
    (inquiry)ChenLee_clear,           /* tp_clear */
    0,                     /* tp_richcompare */
    0,                     /* tp_weaklistoffset */
    0,                     /* tp_iter */
    0,                     /* tp_iternext */
    ChenLee_methods,             /* tp_methods */
    ChenLee_members,             /* tp_members */
    0,                      /* tp_getset */
    0,                         /* tp_base */
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    0,                         /* tp_dictoffset */
    0,      /* tp_init */
    0,                         /* tp_alloc */
    ChenLee_new,                 /* tp_new */
};

typedef struct
{
    pyo_audio_HEAD
    ChenLee *mainChenLee;
    int modebuffer[2];
} ChenLeeAlt;

static void ChenLeeAlt_postprocessing_ii(ChenLeeAlt *self) { POST_PROCESSING_II };
static void ChenLeeAlt_postprocessing_ai(ChenLeeAlt *self) { POST_PROCESSING_AI };
static void ChenLeeAlt_postprocessing_ia(ChenLeeAlt *self) { POST_PROCESSING_IA };
static void ChenLeeAlt_postprocessing_aa(ChenLeeAlt *self) { POST_PROCESSING_AA };
static void ChenLeeAlt_postprocessing_ireva(ChenLeeAlt *self) { POST_PROCESSING_IREVA };
static void ChenLeeAlt_postprocessing_areva(ChenLeeAlt *self) { POST_PROCESSING_AREVA };
static void ChenLeeAlt_postprocessing_revai(ChenLeeAlt *self) { POST_PROCESSING_REVAI };
static void ChenLeeAlt_postprocessing_revaa(ChenLeeAlt *self) { POST_PROCESSING_REVAA };
static void ChenLeeAlt_postprocessing_revareva(ChenLeeAlt *self) { POST_PROCESSING_REVAREVA };

static void
ChenLeeAlt_setProcMode(ChenLeeAlt *self)
{
    int muladdmode;
    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;

    switch (muladdmode)
    {
        case 0:
            self->muladd_func_ptr = ChenLeeAlt_postprocessing_ii;
            break;

        case 1:
            self->muladd_func_ptr = ChenLeeAlt_postprocessing_ai;
            break;

        case 2:
            self->muladd_func_ptr = ChenLeeAlt_postprocessing_revai;
            break;

        case 10:
            self->muladd_func_ptr = ChenLeeAlt_postprocessing_ia;
            break;

        case 11:
            self->muladd_func_ptr = ChenLeeAlt_postprocessing_aa;
            break;

        case 12:
            self->muladd_func_ptr = ChenLeeAlt_postprocessing_revaa;
            break;

        case 20:
            self->muladd_func_ptr = ChenLeeAlt_postprocessing_ireva;
            break;

        case 21:
            self->muladd_func_ptr = ChenLeeAlt_postprocessing_areva;
            break;

        case 22:
            self->muladd_func_ptr = ChenLeeAlt_postprocessing_revareva;
            break;
    }
}

static void
ChenLeeAlt_compute_next_data_frame(ChenLeeAlt *self)
{
    int i;
    MYFLT *tmp;
    tmp = ChenLee_getAltBuffer((ChenLee *)self->mainChenLee);

    for (i = 0; i < self->bufsize; i++)
    {
        self->data[i] = tmp[i];
    }

    (*self->muladd_func_ptr)(self);
}

static int
ChenLeeAlt_traverse(ChenLeeAlt *self, visitproc visit, void *arg)
{
    pyo_VISIT
    Py_VISIT(self->mainChenLee);
    return 0;
}

static int
ChenLeeAlt_clear(ChenLeeAlt *self)
{
    pyo_CLEAR
    Py_CLEAR(self->mainChenLee);
    return 0;
}

static void
ChenLeeAlt_dealloc(ChenLeeAlt* self)
{
    pyo_DEALLOC
    ChenLeeAlt_clear(self);
    Py_TYPE(self->stream)->tp_free((PyObject*)self->stream);
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject *
ChenLeeAlt_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    int i;
    PyObject *maintmp = NULL, *multmp = NULL, *addtmp = NULL;
    ChenLeeAlt *self;
    self = (ChenLeeAlt *)type->tp_alloc(type, 0);

    self->modebuffer[0] = 0;
    self->modebuffer[1] = 0;

    INIT_OBJECT_COMMON
    Stream_setFunctionPtr(self->stream, ChenLeeAlt_compute_next_data_frame);
    self->mode_func_ptr = ChenLeeAlt_setProcMode;

    static char *kwlist[] = {"mainChenLee", "mul", "alt", NULL};

    if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|OO", kwlist, &maintmp, &multmp, &addtmp))
        Py_RETURN_NONE;

    self->mainChenLee = (ChenLee *)maintmp;
    Py_INCREF(self->mainChenLee);

    if (multmp)
    {
        PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
    }

    if (addtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
    }

    PyObject_CallMethod(self->server, "addStream", "O", self->stream);

    (*self->mode_func_ptr)(self);

    return (PyObject *)self;
}

static PyObject * ChenLeeAlt_getServer(ChenLeeAlt* self) { GET_SERVER };
static PyObject * ChenLeeAlt_getStream(ChenLeeAlt* self) { GET_STREAM };
static PyObject * ChenLeeAlt_setMul(ChenLeeAlt *self, PyObject *arg) { SET_MUL };
static PyObject * ChenLeeAlt_setAdd(ChenLeeAlt *self, PyObject *arg) { SET_ADD };
static PyObject * ChenLeeAlt_setSub(ChenLeeAlt *self, PyObject *arg) { SET_SUB };
static PyObject * ChenLeeAlt_setDiv(ChenLeeAlt *self, PyObject *arg) { SET_DIV };

static PyObject * ChenLeeAlt_play(ChenLeeAlt *self, PyObject *args, PyObject *kwds) { PLAY };
static PyObject * ChenLeeAlt_out(ChenLeeAlt *self, PyObject *args, PyObject *kwds) { OUT };
static PyObject * ChenLeeAlt_stop(ChenLeeAlt *self, PyObject *args, PyObject *kwds) { STOP };

static PyObject * ChenLeeAlt_multiply(ChenLeeAlt *self, PyObject *arg) { MULTIPLY };
static PyObject * ChenLeeAlt_inplace_multiply(ChenLeeAlt *self, PyObject *arg) { INPLACE_MULTIPLY };
static PyObject * ChenLeeAlt_add(ChenLeeAlt *self, PyObject *arg) { ADD };
static PyObject * ChenLeeAlt_inplace_add(ChenLeeAlt *self, PyObject *arg) { INPLACE_ADD };
static PyObject * ChenLeeAlt_sub(ChenLeeAlt *self, PyObject *arg) { SUB };
static PyObject * ChenLeeAlt_inplace_sub(ChenLeeAlt *self, PyObject *arg) { INPLACE_SUB };
static PyObject * ChenLeeAlt_div(ChenLeeAlt *self, PyObject *arg) { DIV };
static PyObject * ChenLeeAlt_inplace_div(ChenLeeAlt *self, PyObject *arg) { INPLACE_DIV };

static PyMemberDef ChenLeeAlt_members[] =
{
    {"server", T_OBJECT_EX, offsetof(ChenLeeAlt, server), 0, "Pyo server."},
    {"stream", T_OBJECT_EX, offsetof(ChenLeeAlt, stream), 0, "Stream object."},
    {"mul", T_OBJECT_EX, offsetof(ChenLeeAlt, mul), 0, "Mul factor."},
    {"add", T_OBJECT_EX, offsetof(ChenLeeAlt, add), 0, "Add factor."},
    {NULL}  /* Sentinel */
};

static PyMethodDef ChenLeeAlt_methods[] =
{
    {"getServer", (PyCFunction)ChenLeeAlt_getServer, METH_NOARGS, "Returns server object."},
    {"_getStream", (PyCFunction)ChenLeeAlt_getStream, METH_NOARGS, "Returns stream object."},
    {"play", (PyCFunction)ChenLeeAlt_play, METH_VARARGS | METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
    {"out", (PyCFunction)ChenLeeAlt_out, METH_VARARGS | METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
    {"stop", (PyCFunction)ChenLeeAlt_stop, METH_VARARGS | METH_KEYWORDS, "Stops computing."},
    {"setMul", (PyCFunction)ChenLeeAlt_setMul, METH_O, "Sets oscillator mul factor."},
    {"setAdd", (PyCFunction)ChenLeeAlt_setAdd, METH_O, "Sets oscillator add factor."},
    {"setSub", (PyCFunction)ChenLeeAlt_setSub, METH_O, "Sets inverse add factor."},
    {"setDiv", (PyCFunction)ChenLeeAlt_setDiv, METH_O, "Sets inverse mul factor."},
    {NULL}  /* Sentinel */
};
static PyNumberMethods ChenLeeAlt_as_number =
{
    (binaryfunc)ChenLeeAlt_add,                         /*nb_add*/
    (binaryfunc)ChenLeeAlt_sub,                         /*nb_subtract*/
    (binaryfunc)ChenLeeAlt_multiply,                    /*nb_multiply*/
    0,                                              /*nb_remainder*/
    0,                                              /*nb_divmod*/
    0,                                              /*nb_power*/
    0,                                              /*nb_neg*/
    0,                                              /*nb_pos*/
    0,                                              /*(unaryfunc)array_abs,*/
    0,                                              /*nb_nonzero*/
    0,                                              /*nb_invert*/
    0,                                              /*nb_lshift*/
    0,                                              /*nb_rshift*/
    0,                                              /*nb_and*/
    0,                                              /*nb_xor*/
    0,                                              /*nb_or*/
    0,                                              /*nb_int*/
    0,                                              /*nb_long*/
    0,                                              /*nb_float*/
    (binaryfunc)ChenLeeAlt_inplace_add,                 /*inplace_add*/
    (binaryfunc)ChenLeeAlt_inplace_sub,                 /*inplace_subtract*/
    (binaryfunc)ChenLeeAlt_inplace_multiply,            /*inplace_multiply*/
    0,                                              /*inplace_remainder*/
    0,                                              /*inplace_power*/
    0,                                              /*inplace_lshift*/
    0,                                              /*inplace_rshift*/
    0,                                              /*inplace_and*/
    0,                                              /*inplace_xor*/
    0,                                              /*inplace_or*/
    0,                                              /*nb_floor_divide*/
    (binaryfunc)ChenLeeAlt_div,                       /*nb_true_divide*/
    0,                                              /*nb_inplace_floor_divide*/
    (binaryfunc)ChenLeeAlt_inplace_div,                       /*nb_inplace_true_divide*/
    0,                                              /* nb_index */
};

PyTypeObject ChenLeeAltType =
{
    PyVarObject_HEAD_INIT(NULL, 0)
    "_pyo.ChenLeeAlt_base",         /*tp_name*/
    sizeof(ChenLeeAlt),         /*tp_basicsize*/
    0,                         /*tp_itemsize*/
    (destructor)ChenLeeAlt_dealloc, /*tp_dealloc*/
    0,                         /*tp_print*/
    0,                         /*tp_getattr*/
    0,                         /*tp_setattr*/
    0,                         /*tp_as_async (tp_compare in Python 2)*/
    0,                         /*tp_repr*/
    &ChenLeeAlt_as_number,             /*tp_as_number*/
    0,                         /*tp_as_sequence*/
    0,                         /*tp_as_mapping*/
    0,                         /*tp_hash */
    0,                         /*tp_call*/
    0,                         /*tp_str*/
    0,                         /*tp_getattro*/
    0,                         /*tp_setattro*/
    0,                         /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,  /*tp_flags*/
    "ChenLeeAlt objects. Sends the alternate signal of a ChenLee attractor.",           /* tp_doc */
    (traverseproc)ChenLeeAlt_traverse,   /* tp_traverse */
    (inquiry)ChenLeeAlt_clear,           /* tp_clear */
    0,                     /* tp_richcompare */
    0,                     /* tp_weaklistoffset */
    0,                     /* tp_iter */
    0,                     /* tp_iternext */
    ChenLeeAlt_methods,             /* tp_methods */
    ChenLeeAlt_members,             /* tp_members */
    0,                      /* tp_getset */
    0,                         /* tp_base */
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    0,                         /* tp_dictoffset */
    0,      /* tp_init */
    0,                         /* tp_alloc */
    ChenLeeAlt_new,                 /* tp_new */
};

/*************/
/* SumOsc object */
/*************/
typedef struct
{
    pyo_audio_HEAD
    PyObject *freq;
    Stream *freq_stream;
    PyObject *ratio;
    Stream *ratio_stream;
    PyObject *index;
    Stream *index_stream;
    int modebuffer[5];
    MYFLT theta;
    MYFLT beta;
    MYFLT scaleFactor;
    MYFLT xn1; // dc block input delay
    MYFLT yn1; // dc block output delay
} SumOsc;

static void
SumOsc_readframes_iii(SumOsc *self)
{
    MYFLT mod_freq, mod_delta, freq_delta, x, y, ind2, theta_minus_beta, sin1, sin2, cos1;
    int i, ipart;

    MYFLT freq = PyFloat_AS_DOUBLE(self->freq);
    MYFLT rat = PyFloat_AS_DOUBLE(self->ratio);
    MYFLT ind = PyFloat_AS_DOUBLE(self->index);

    freq_delta = freq * self->scaleFactor;
    mod_freq = freq * rat;
    mod_delta = mod_freq * self->scaleFactor;

    if (ind < 0)
        ind = 0;
    else if (ind > 0.999)
        ind = 0.999;

    ind2 = ind * ind;

    for (i = 0; i < self->bufsize; i++)
    {
        ipart = (int)self->theta;
        sin1 = SINE_ARRAY[ipart] + (SINE_ARRAY[ipart + 1] - SINE_ARRAY[ipart]) * (self->theta - ipart);
        theta_minus_beta = Sine_clip(self->theta - self->beta);
        ipart = (int)theta_minus_beta;
        sin2 = SINE_ARRAY[ipart] + (SINE_ARRAY[ipart + 1] - SINE_ARRAY[ipart]) * (theta_minus_beta - ipart);
        ipart = (int)self->beta;
        cos1 = COSINE_ARRAY[ipart] + (COSINE_ARRAY[ipart + 1] - COSINE_ARRAY[ipart]) * (self->beta - ipart);
        x = (sin1 - ind * sin2) / (1 + ind2 - 2 * ind * cos1);
        self->theta += freq_delta;
        self->beta += mod_delta;
        self->theta = Sine_clip(self->theta);
        self->beta = Sine_clip(self->beta);

        /* DC filtering */
        y = x - self->xn1 + 0.995 * self->yn1;
        self->xn1 = x;
        self->yn1 = y;

        self->data[i] = y * (1 - ind2);
    }
}

static void
SumOsc_readframes_aii(SumOsc *self)
{
    MYFLT freq, mod_freq, mod_delta, freq_delta, x, y, ind2, theta_minus_beta, sin1, sin2, cos1;
    int i, ipart;

    MYFLT *fr = Stream_getData((Stream *)self->freq_stream);
    MYFLT rat = PyFloat_AS_DOUBLE(self->ratio);
    MYFLT ind = PyFloat_AS_DOUBLE(self->index);

    if (ind < 0)
        ind = 0;
    else if (ind > 0.999)
        ind = 0.999;

    ind2 = ind * ind;

    for (i = 0; i < self->bufsize; i++)
    {
        freq = fr[i];
        freq_delta = freq * self->scaleFactor;
        mod_freq = freq * rat;
        mod_delta = mod_freq * self->scaleFactor;
        ipart = (int)self->theta;
        sin1 = SINE_ARRAY[ipart] + (SINE_ARRAY[ipart + 1] - SINE_ARRAY[ipart]) * (self->theta - ipart);
        theta_minus_beta = Sine_clip(self->theta - self->beta);
        ipart = (int)theta_minus_beta;
        sin2 = SINE_ARRAY[ipart] + (SINE_ARRAY[ipart + 1] - SINE_ARRAY[ipart]) * (theta_minus_beta - ipart);
        ipart = (int)self->beta;
        cos1 = COSINE_ARRAY[ipart] + (COSINE_ARRAY[ipart + 1] - COSINE_ARRAY[ipart]) * (self->beta - ipart);
        x = (sin1 - ind * sin2) / (1 + ind2 - 2 * ind * cos1);
        self->theta += freq_delta;
        self->beta += mod_delta;
        self->theta = Sine_clip(self->theta);
        self->beta = Sine_clip(self->beta);

        y = x - self->xn1 + 0.995 * self->yn1;
        self->xn1 = x;
        self->yn1 = y;

        self->data[i] = y * (1 - ind2);
    }
}

static void
SumOsc_readframes_iai(SumOsc *self)
{
    MYFLT ratio, mod_freq, mod_delta, freq_delta, x, y, ind2, theta_minus_beta, sin1, sin2, cos1;
    int i, ipart;

    MYFLT freq = PyFloat_AS_DOUBLE(self->freq);
    MYFLT *rat = Stream_getData((Stream *)self->ratio_stream);
    MYFLT ind = PyFloat_AS_DOUBLE(self->index);

    freq_delta = freq * self->scaleFactor;

    if (ind < 0)
        ind = 0;
    else if (ind > 0.999)
        ind = 0.999;

    ind2 = ind * ind;

    for (i = 0; i < self->bufsize; i++)
    {
        ratio = rat[i];
        mod_freq = freq * ratio;
        mod_delta = mod_freq * self->scaleFactor;
        ipart = (int)self->theta;
        sin1 = SINE_ARRAY[ipart] + (SINE_ARRAY[ipart + 1] - SINE_ARRAY[ipart]) * (self->theta - ipart);
        theta_minus_beta = Sine_clip(self->theta - self->beta);
        ipart = (int)theta_minus_beta;
        sin2 = SINE_ARRAY[ipart] + (SINE_ARRAY[ipart + 1] - SINE_ARRAY[ipart]) * (theta_minus_beta - ipart);
        ipart = (int)self->beta;
        cos1 = COSINE_ARRAY[ipart] + (COSINE_ARRAY[ipart + 1] - COSINE_ARRAY[ipart]) * (self->beta - ipart);
        x = (sin1 - ind * sin2) / (1 + ind2 - 2 * ind * cos1);
        self->theta += freq_delta;
        self->beta += mod_delta;
        self->theta = Sine_clip(self->theta);
        self->beta = Sine_clip(self->beta);

        y = x - self->xn1 + 0.995 * self->yn1;
        self->xn1 = x;
        self->yn1 = y;

        self->data[i] = y * (1 - ind2);
    }
}

static void
SumOsc_readframes_aai(SumOsc *self)
{
    MYFLT freq, ratio, mod_freq, mod_delta, freq_delta, x, y, ind2, theta_minus_beta, sin1, sin2, cos1;
    int i, ipart;

    MYFLT *fr = Stream_getData((Stream *)self->freq_stream);
    MYFLT *rat = Stream_getData((Stream *)self->ratio_stream);
    MYFLT ind = PyFloat_AS_DOUBLE(self->index);

    if (ind < 0)
        ind = 0;
    else if (ind > 0.999)
        ind = 0.999;

    ind2 = ind * ind;

    for (i = 0; i < self->bufsize; i++)
    {
        freq = fr[i];
        ratio = rat[i];
        freq_delta = freq * self->scaleFactor;
        mod_freq = freq * ratio;
        mod_delta = mod_freq * self->scaleFactor;
        ipart = (int)self->theta;
        sin1 = SINE_ARRAY[ipart] + (SINE_ARRAY[ipart + 1] - SINE_ARRAY[ipart]) * (self->theta - ipart);
        theta_minus_beta = Sine_clip(self->theta - self->beta);
        ipart = (int)theta_minus_beta;
        sin2 = SINE_ARRAY[ipart] + (SINE_ARRAY[ipart + 1] - SINE_ARRAY[ipart]) * (theta_minus_beta - ipart);
        ipart = (int)self->beta;
        cos1 = COSINE_ARRAY[ipart] + (COSINE_ARRAY[ipart + 1] - COSINE_ARRAY[ipart]) * (self->beta - ipart);
        x = (sin1 - ind * sin2) / (1 + ind2 - 2 * ind * cos1);
        self->theta += freq_delta;
        self->beta += mod_delta;
        self->theta = Sine_clip(self->theta);
        self->beta = Sine_clip(self->beta);

        y = x - self->xn1 + 0.995 * self->yn1;
        self->xn1 = x;
        self->yn1 = y;

        self->data[i] = y * (1 - ind2);
    }
}

static void
SumOsc_readframes_iia(SumOsc *self)
{
    MYFLT ind, mod_freq, mod_delta, freq_delta, x, y, ind2, theta_minus_beta, sin1, sin2, cos1;
    int i, ipart;

    MYFLT freq = PyFloat_AS_DOUBLE(self->freq);
    MYFLT rat = PyFloat_AS_DOUBLE(self->ratio);
    MYFLT *index = Stream_getData((Stream *)self->index_stream);

    freq_delta = freq * self->scaleFactor;
    mod_freq = freq * rat;
    mod_delta = mod_freq * self->scaleFactor;

    for (i = 0; i < self->bufsize; i++)
    {
        ind = index[i];

        if (ind < 0)
            ind = 0;
        else if (ind > 0.999)
            ind = 0.999;

        ind2 = ind * ind;
        ipart = (int)self->theta;
        sin1 = SINE_ARRAY[ipart] + (SINE_ARRAY[ipart + 1] - SINE_ARRAY[ipart]) * (self->theta - ipart);
        theta_minus_beta = Sine_clip(self->theta - self->beta);
        ipart = (int)theta_minus_beta;
        sin2 = SINE_ARRAY[ipart] + (SINE_ARRAY[ipart + 1] - SINE_ARRAY[ipart]) * (theta_minus_beta - ipart);
        ipart = (int)self->beta;
        cos1 = COSINE_ARRAY[ipart] + (COSINE_ARRAY[ipart + 1] - COSINE_ARRAY[ipart]) * (self->beta - ipart);
        x = (sin1 - ind * sin2) / (1 + ind2 - 2 * ind * cos1);
        self->theta += freq_delta;
        self->beta += mod_delta;
        self->theta = Sine_clip(self->theta);
        self->beta = Sine_clip(self->beta);

        y = x - self->xn1 + 0.995 * self->yn1;
        self->xn1 = x;
        self->yn1 = y;

        self->data[i] = y * (1 - ind2);
    }
}

static void
SumOsc_readframes_aia(SumOsc *self)
{
    MYFLT freq, ind, mod_freq, mod_delta, freq_delta, x, y, ind2, theta_minus_beta, sin1, sin2, cos1;
    int i, ipart;

    MYFLT *fr = Stream_getData((Stream *)self->freq_stream);
    MYFLT rat = PyFloat_AS_DOUBLE(self->ratio);
    MYFLT *index = Stream_getData((Stream *)self->index_stream);

    for (i = 0; i < self->bufsize; i++)
    {
        freq = fr[i];
        ind = index[i];
        freq_delta = freq * self->scaleFactor;
        mod_freq = freq * rat;
        mod_delta = mod_freq * self->scaleFactor;

        if (ind < 0)
            ind = 0;
        else if (ind > 0.999)
            ind = 0.999;

        ind2 = ind * ind;
        ipart = (int)self->theta;
        sin1 = SINE_ARRAY[ipart] + (SINE_ARRAY[ipart + 1] - SINE_ARRAY[ipart]) * (self->theta - ipart);
        theta_minus_beta = Sine_clip(self->theta - self->beta);
        ipart = (int)theta_minus_beta;
        sin2 = SINE_ARRAY[ipart] + (SINE_ARRAY[ipart + 1] - SINE_ARRAY[ipart]) * (theta_minus_beta - ipart);
        ipart = (int)self->beta;
        cos1 = COSINE_ARRAY[ipart] + (COSINE_ARRAY[ipart + 1] - COSINE_ARRAY[ipart]) * (self->beta - ipart);
        x = (sin1 - ind * sin2) / (1 + ind2 - 2 * ind * cos1);
        self->theta += freq_delta;
        self->beta += mod_delta;
        self->theta = Sine_clip(self->theta);
        self->beta = Sine_clip(self->beta);

        y = x - self->xn1 + 0.995 * self->yn1;
        self->xn1 = x;
        self->yn1 = y;

        self->data[i] = y * (1 - ind2);
    }
}

static void
SumOsc_readframes_iaa(SumOsc *self)
{
    MYFLT ratio, ind, mod_freq, mod_delta, freq_delta, x, y, ind2, theta_minus_beta, sin1, sin2, cos1;
    int i, ipart;

    MYFLT freq = PyFloat_AS_DOUBLE(self->freq);
    MYFLT *rat = Stream_getData((Stream *)self->ratio_stream);
    MYFLT *index = Stream_getData((Stream *)self->index_stream);

    freq_delta = freq * self->scaleFactor;

    for (i = 0; i < self->bufsize; i++)
    {
        ind = index[i];
        ratio = rat[i];
        mod_freq = freq * ratio;
        mod_delta = mod_freq * self->scaleFactor;

        if (ind < 0)
            ind = 0;
        else if (ind > 0.999)
            ind = 0.999;

        ind2 = ind * ind;
        ipart = (int)self->theta;
        sin1 = SINE_ARRAY[ipart] + (SINE_ARRAY[ipart + 1] - SINE_ARRAY[ipart]) * (self->theta - ipart);
        theta_minus_beta = Sine_clip(self->theta - self->beta);
        ipart = (int)theta_minus_beta;
        sin2 = SINE_ARRAY[ipart] + (SINE_ARRAY[ipart + 1] - SINE_ARRAY[ipart]) * (theta_minus_beta - ipart);
        ipart = (int)self->beta;
        cos1 = COSINE_ARRAY[ipart] + (COSINE_ARRAY[ipart + 1] - COSINE_ARRAY[ipart]) * (self->beta - ipart);
        x = (sin1 - ind * sin2) / (1 + ind2 - 2 * ind * cos1);
        self->theta += freq_delta;
        self->beta += mod_delta;
        self->theta = Sine_clip(self->theta);
        self->beta = Sine_clip(self->beta);

        y = x - self->xn1 + 0.995 * self->yn1;
        self->xn1 = x;
        self->yn1 = y;

        self->data[i] = y * (1 - ind2);
    }
}

static void
SumOsc_readframes_aaa(SumOsc *self)
{
    MYFLT freq, ratio, ind, mod_freq, mod_delta, freq_delta, x, y, ind2, theta_minus_beta, sin1, sin2, cos1;
    int i, ipart;

    MYFLT *fr = Stream_getData((Stream *)self->freq_stream);
    MYFLT *rat = Stream_getData((Stream *)self->ratio_stream);
    MYFLT *index = Stream_getData((Stream *)self->index_stream);

    for (i = 0; i < self->bufsize; i++)
    {
        freq = fr[i];
        ind = index[i];
        ratio = rat[i];
        freq_delta = freq * self->scaleFactor;
        mod_freq = freq * ratio;
        mod_delta = mod_freq * self->scaleFactor;

        if (ind < 0)
            ind = 0;
        else if (ind > 0.999)
            ind = 0.999;

        ind2 = ind * ind;
        ipart = (int)self->theta;
        sin1 = SINE_ARRAY[ipart] + (SINE_ARRAY[ipart + 1] - SINE_ARRAY[ipart]) * (self->theta - ipart);
        theta_minus_beta = Sine_clip(self->theta - self->beta);
        ipart = (int)theta_minus_beta;
        sin2 = SINE_ARRAY[ipart] + (SINE_ARRAY[ipart + 1] - SINE_ARRAY[ipart]) * (theta_minus_beta - ipart);
        ipart = (int)self->beta;
        cos1 = COSINE_ARRAY[ipart] + (COSINE_ARRAY[ipart + 1] - COSINE_ARRAY[ipart]) * (self->beta - ipart);
        x = (sin1 - ind * sin2) / (1 + ind2 - 2 * ind * cos1);
        self->theta += freq_delta;
        self->beta += mod_delta;
        self->theta = Sine_clip(self->theta);
        self->beta = Sine_clip(self->beta);

        y = x - self->xn1 + 0.995 * self->yn1;
        self->xn1 = x;
        self->yn1 = y;

        self->data[i] = y * (1 - ind2);
    }
}

static void SumOsc_postprocessing_ii(SumOsc *self) { POST_PROCESSING_II };
static void SumOsc_postprocessing_ai(SumOsc *self) { POST_PROCESSING_AI };
static void SumOsc_postprocessing_ia(SumOsc *self) { POST_PROCESSING_IA };
static void SumOsc_postprocessing_aa(SumOsc *self) { POST_PROCESSING_AA };
static void SumOsc_postprocessing_ireva(SumOsc *self) { POST_PROCESSING_IREVA };
static void SumOsc_postprocessing_areva(SumOsc *self) { POST_PROCESSING_AREVA };
static void SumOsc_postprocessing_revai(SumOsc *self) { POST_PROCESSING_REVAI };
static void SumOsc_postprocessing_revaa(SumOsc *self) { POST_PROCESSING_REVAA };
static void SumOsc_postprocessing_revareva(SumOsc *self) { POST_PROCESSING_REVAREVA };

static void
SumOsc_setProcMode(SumOsc *self)
{
    int procmode, muladdmode;
    procmode = self->modebuffer[2] + self->modebuffer[3] * 10 + self->modebuffer[4] * 100;
    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;

    switch (procmode)
    {
        case 0:
            self->proc_func_ptr = SumOsc_readframes_iii;
            break;

        case 1:
            self->proc_func_ptr = SumOsc_readframes_aii;
            break;

        case 10:
            self->proc_func_ptr = SumOsc_readframes_iai;
            break;

        case 11:
            self->proc_func_ptr = SumOsc_readframes_aai;
            break;

        case 100:
            self->proc_func_ptr = SumOsc_readframes_iia;
            break;

        case 101:
            self->proc_func_ptr = SumOsc_readframes_aia;
            break;

        case 110:
            self->proc_func_ptr = SumOsc_readframes_iaa;
            break;

        case 111:
            self->proc_func_ptr = SumOsc_readframes_aaa;
            break;
    }

    switch (muladdmode)
    {
        case 0:
            self->muladd_func_ptr = SumOsc_postprocessing_ii;
            break;

        case 1:
            self->muladd_func_ptr = SumOsc_postprocessing_ai;
            break;

        case 2:
            self->muladd_func_ptr = SumOsc_postprocessing_revai;
            break;

        case 10:
            self->muladd_func_ptr = SumOsc_postprocessing_ia;
            break;

        case 11:
            self->muladd_func_ptr = SumOsc_postprocessing_aa;
            break;

        case 12:
            self->muladd_func_ptr = SumOsc_postprocessing_revaa;
            break;

        case 20:
            self->muladd_func_ptr = SumOsc_postprocessing_ireva;
            break;

        case 21:
            self->muladd_func_ptr = SumOsc_postprocessing_areva;
            break;

        case 22:
            self->muladd_func_ptr = SumOsc_postprocessing_revareva;
            break;
    }
}

static void
SumOsc_compute_next_data_frame(SumOsc *self)
{
    (*self->proc_func_ptr)(self);
    (*self->muladd_func_ptr)(self);
}

static int
SumOsc_traverse(SumOsc *self, visitproc visit, void *arg)
{
    pyo_VISIT
    Py_VISIT(self->freq);
    Py_VISIT(self->ratio);
    Py_VISIT(self->index);
    return 0;
}

static int
SumOsc_clear(SumOsc *self)
{
    pyo_CLEAR
    Py_CLEAR(self->freq);
    Py_CLEAR(self->ratio);
    Py_CLEAR(self->index);
    return 0;
}

static void
SumOsc_dealloc(SumOsc* self)
{
    pyo_DEALLOC
    SumOsc_clear(self);
    Py_TYPE(self->stream)->tp_free((PyObject*)self->stream);
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject *
SumOsc_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    int i;
    PyObject *freqtmp = NULL, *ratiotmp = NULL, *indextmp = NULL, *multmp = NULL, *addtmp = NULL;
    SumOsc *self;
    self = (SumOsc *)type->tp_alloc(type, 0);

    self->freq = PyFloat_FromDouble(100);
    self->ratio = PyFloat_FromDouble(0.5);
    self->index = PyFloat_FromDouble(0.5);
    self->modebuffer[0] = 0;
    self->modebuffer[1] = 0;
    self->modebuffer[2] = 0;
    self->modebuffer[3] = 0;
    self->modebuffer[4] = 0;
    self->theta = self->beta = 0.;
    self->xn1 = self->yn1 = 0.0;

    INIT_OBJECT_COMMON
    Stream_setFunctionPtr(self->stream, SumOsc_compute_next_data_frame);
    self->mode_func_ptr = SumOsc_setProcMode;

    self->scaleFactor = 512.0 / self->sr;

    static char *kwlist[] = {"freq", "ratio", "index", "mul", "add", NULL};

    if (! PyArg_ParseTupleAndKeywords(args, kwds, "|OOOOO", kwlist, &freqtmp, &ratiotmp, &indextmp, &multmp, &addtmp))
        Py_RETURN_NONE;

    if (freqtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setFreq", "O", freqtmp);
    }

    if (ratiotmp)
    {
        PyObject_CallMethod((PyObject *)self, "setRatio", "O", ratiotmp);
    }

    if (indextmp)
    {
        PyObject_CallMethod((PyObject *)self, "setIndex", "O", indextmp);
    }

    if (multmp)
    {
        PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
    }

    if (addtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
    }

    PyObject_CallMethod(self->server, "addStream", "O", self->stream);

    (*self->mode_func_ptr)(self);

    return (PyObject *)self;
}

static PyObject * SumOsc_getServer(SumOsc* self) { GET_SERVER };
static PyObject * SumOsc_getStream(SumOsc* self) { GET_STREAM };
static PyObject * SumOsc_setMul(SumOsc *self, PyObject *arg) { SET_MUL };
static PyObject * SumOsc_setAdd(SumOsc *self, PyObject *arg) { SET_ADD };
static PyObject * SumOsc_setSub(SumOsc *self, PyObject *arg) { SET_SUB };
static PyObject * SumOsc_setDiv(SumOsc *self, PyObject *arg) { SET_DIV };

static PyObject * SumOsc_play(SumOsc *self, PyObject *args, PyObject *kwds) { PLAY };
static PyObject * SumOsc_out(SumOsc *self, PyObject *args, PyObject *kwds) { OUT };
static PyObject * SumOsc_stop(SumOsc *self, PyObject *args, PyObject *kwds) { STOP };

static PyObject * SumOsc_multiply(SumOsc *self, PyObject *arg) { MULTIPLY };
static PyObject * SumOsc_inplace_multiply(SumOsc *self, PyObject *arg) { INPLACE_MULTIPLY };
static PyObject * SumOsc_add(SumOsc *self, PyObject *arg) { ADD };
static PyObject * SumOsc_inplace_add(SumOsc *self, PyObject *arg) { INPLACE_ADD };
static PyObject * SumOsc_sub(SumOsc *self, PyObject *arg) { SUB };
static PyObject * SumOsc_inplace_sub(SumOsc *self, PyObject *arg) { INPLACE_SUB };
static PyObject * SumOsc_div(SumOsc *self, PyObject *arg) { DIV };
static PyObject * SumOsc_inplace_div(SumOsc *self, PyObject *arg) { INPLACE_DIV };

static PyObject * SumOsc_setFreq(SumOsc *self, PyObject *arg) { SET_PARAM(self->freq, self->freq_stream, 2); }
static PyObject * SumOsc_setRatio(SumOsc *self, PyObject *arg) { SET_PARAM(self->ratio, self->ratio_stream, 3); }
static PyObject * SumOsc_setIndex(SumOsc *self, PyObject *arg) { SET_PARAM(self->index, self->index_stream, 4); }

static PyMemberDef SumOsc_members[] =
{
    {"server", T_OBJECT_EX, offsetof(SumOsc, server), 0, "Pyo server."},
    {"stream", T_OBJECT_EX, offsetof(SumOsc, stream), 0, "Stream object."},
    {"freq", T_OBJECT_EX, offsetof(SumOsc, freq), 0, "Frequency in cycle per second."},
    {"ratio", T_OBJECT_EX, offsetof(SumOsc, ratio), 0, "Ratio freq:modulator (mod freq = freq*ratio)."},
    {"index", T_OBJECT_EX, offsetof(SumOsc, index), 0, "Index, high frequency damping."},
    {"mul", T_OBJECT_EX, offsetof(SumOsc, mul), 0, "Mul factor."},
    {"add", T_OBJECT_EX, offsetof(SumOsc, add), 0, "Add factor."},
    {NULL}  /* Sentinel */
};

static PyMethodDef SumOsc_methods[] =
{
    {"getServer", (PyCFunction)SumOsc_getServer, METH_NOARGS, "Returns server object."},
    {"_getStream", (PyCFunction)SumOsc_getStream, METH_NOARGS, "Returns stream object."},
    {"play", (PyCFunction)SumOsc_play, METH_VARARGS | METH_KEYWORDS, "Starts computing without sending sound to soundfreqd."},
    {"out", (PyCFunction)SumOsc_out, METH_VARARGS | METH_KEYWORDS, "Starts computing and sends sound to soundfreqd channel speficied by argument."},
    {"stop", (PyCFunction)SumOsc_stop, METH_VARARGS | METH_KEYWORDS, "Stops computing."},
    {"setFreq", (PyCFunction)SumOsc_setFreq, METH_O, "Sets oscillator frequency in cycle per second."},
    {"setRatio", (PyCFunction)SumOsc_setRatio, METH_O, "Sets freq:mod ratio."},
    {"setIndex", (PyCFunction)SumOsc_setIndex, METH_O, "Sets high frequency damping."},
    {"setMul", (PyCFunction)SumOsc_setMul, METH_O, "Sets SumOsc mul factor."},
    {"setAdd", (PyCFunction)SumOsc_setAdd, METH_O, "Sets SumOsc add factor."},
    {"setSub", (PyCFunction)SumOsc_setSub, METH_O, "Sets inverse add factor."},
    {"setDiv", (PyCFunction)SumOsc_setDiv, METH_O, "Sets inverse mul factor."},
    {NULL}  /* Sentinel */
};

static PyNumberMethods SumOsc_as_number =
{
    (binaryfunc)SumOsc_add,                      /*nb_add*/
    (binaryfunc)SumOsc_sub,                 /*nb_subtract*/
    (binaryfunc)SumOsc_multiply,                 /*nb_multiply*/
    0,                /*nb_remainder*/
    0,                   /*nb_divmod*/
    0,                   /*nb_power*/
    0,                  /*nb_neg*/
    0,                /*nb_pos*/
    0,                  /*(unaryfunc)array_abs*/
    0,                    /*nb_nonzero*/
    0,                    /*nb_invert*/
    0,               /*nb_lshift*/
    0,              /*nb_rshift*/
    0,              /*nb_and*/
    0,              /*nb_xor*/
    0,               /*nb_or*/
    0,                       /*nb_int*/
    0,                      /*nb_long*/
    0,                     /*nb_float*/
    (binaryfunc)SumOsc_inplace_add,              /*inplace_add*/
    (binaryfunc)SumOsc_inplace_sub,         /*inplace_subtract*/
    (binaryfunc)SumOsc_inplace_multiply,         /*inplace_multiply*/
    0,        /*inplace_remainder*/
    0,           /*inplace_power*/
    0,       /*inplace_lshift*/
    0,      /*inplace_rshift*/
    0,      /*inplace_and*/
    0,      /*inplace_xor*/
    0,       /*inplace_or*/
    0,             /*nb_floor_divide*/
    (binaryfunc)SumOsc_div,                       /*nb_true_divide*/
    0,     /*nb_inplace_floor_divide*/
    (binaryfunc)SumOsc_inplace_div,                       /*nb_inplace_true_divide*/
    0,                     /* nb_index */
};

PyTypeObject SumOscType =
{
    PyVarObject_HEAD_INIT(NULL, 0)
    "_pyo.SumOsc_base",         /*tp_name*/
    sizeof(SumOsc),         /*tp_basicsize*/
    0,                         /*tp_itemsize*/
    (destructor)SumOsc_dealloc, /*tp_dealloc*/
    0,                         /*tp_print*/
    0,                         /*tp_getattr*/
    0,                         /*tp_setattr*/
    0,                         /*tp_as_async (tp_compare in Python 2)*/
    0,                         /*tp_repr*/
    &SumOsc_as_number,             /*tp_as_number*/
    0,                         /*tp_as_sequence*/
    0,                         /*tp_as_mapping*/
    0,                         /*tp_hash */
    0,                         /*tp_call*/
    0,                         /*tp_str*/
    0,                         /*tp_getattro*/
    0,                         /*tp_setattro*/
    0,                         /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,  /*tp_flags*/
    "SumOsc objects. Infite summation oscillator.",           /* tp_doc */
    (traverseproc)SumOsc_traverse,   /* tp_traverse */
    (inquiry)SumOsc_clear,           /* tp_clear */
    0,                     /* tp_richcompare */
    0,                     /* tp_weaklistoffset */
    0,                     /* tp_iter */
    0,                     /* tp_iternext */
    SumOsc_methods,             /* tp_methods */
    SumOsc_members,             /* tp_members */
    0,                      /* tp_getset */
    0,                         /* tp_base */
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    0,                         /* tp_dictoffset */
    0,      /* tp_init */
    0,                         /* tp_alloc */
    SumOsc_new,                 /* tp_new */
};

static MYFLT SUPERSAW_DETUNES[7][128] = {{1.0, 0.9999999999999738, 0.9999999999983218, 0.9999999999808844, 0.9999999998925958, 0.9999999995902856, 0.9999999987765995, 0.999999996915041, 0.9999999931261337, 0.9999999860647035, 0.9999999737782811, 0.9999999535466255, 0.999999921702367, 0.9999998734327713, 0.9999998025626238, 0.9999997013182335, 0.9999995600725585, 0.9999993670714514, 0.999999108141024, 0.9999987663761343, 0.999998321809992, 0.9999977510648862, 0.9999970269840314, 0.9999961182445354, 0.9999949889514873, 0.9999935982131656, 0.999991899697366, 0.9999898411688514, 0.9999873640079204, 0.999984402710097, 0.9999808843669409, 0.9999767281279772, 0.9999718446437478, 0.9999661354899821, 0.9999594925728883, 0.9999517975155655, 0.9999429210255355, 0.9999327222433956, 0.9999210480725913, 0.9999077324903094, 0.9998925958394921, 0.9998754441019703, 0.9998560681527183, 0.9998342429952286, 0.9998097269780065, 0.9997822609921857, 0.9997515676502643, 0.9997173504459607, 0.99967929289519, 0.9996370576581611, 0.9995902856425938, 0.9995385950880562, 0.999481580631423, 0.9994188123534535, 0.9993498348064905, 0.9992741660232791, 0.999191296506906, 0.9991006882018598, 0.9990017734462106, 0.9988939539049104, 0.9987765994842147, 0.9986490472272227, 0.9985106001905395, 0.9983605263020577, 0.9981980571998603, 0.9980223870522424, 0.9978326713588549, 0.9976280257329677, 0.9974075246648535, 0.9971702002662917, 0.996915040996193, 0.9966409903673441, 0.9963469456342734, 0.9960317564622357, 0.995694223577319, 0.9953330973976697, 0.9949470766458405, 0.9945348069422566, 0.994094879379803, 0.9936258290795327, 0.9931261337274945, 0.9925942120926815, 0.9920284225260998, 0.9914270614409579, 0.9907883617739762, 0.9901104914278165, 0.9893915516946329, 0.988629575660742, 0.9878225265924139, 0.9869682963027838, 0.9860647034998833, 0.985109492115793, 0.9841003296169146, 0.9830348052953636, 0.9819104285414826, 0.9807246270974751, 0.9794747452921589, 0.9781580422568408, 0.9767716901223106, 0.9753127721969568, 0.9737782811260014, 0.9721651170318559, 0.9704700856355972, 0.9686898963595642, 0.9668211604110741, 0.9648603888472602, 0.9628039906210292, 0.9606482706081385, 0.9583894276153956, 0.9560235523699754, 0.9535466254898602, 0.9509545154353983, 0.9482429764419842, 0.9454076464338582, 0.9424440449190272, 0.9393475708653054, 0.9361135005574749, 0.9327369854355683, 0.9292130499142693, 0.9255365891834358, 0.9217023669897422, 0.9177050133994422, 0.9135390225422524, 0.9091987503363557, 0.9046784121945255, 0.8999720807113701, 0.8950736833316975, 0.889977},
    {1.0, 0.999999999999985, 0.9999999999990408, 0.9999999999890743, 0.9999999999386124, 0.999999999765825, 0.999999999300757, 0.9999999982367705, 0.9999999960711946, 0.9999999920351857, 0.9999999850127967, 0.9999999734492553, 0.999999955248451, 0.9999999276596326, 0.9999998871533139, 0.9999998292863885, 0.9999997485564546, 0.9999996382453485, 0.9999994902518874, 0.9999992949138214, 0.9999990408189948, 0.9999987146057163, 0.9999983007523392, 0.9999977813560498, 0.9999971359008654, 0.9999963410148422, 0.9999953702164914, 0.9999941936504051, 0.9999927778120908, 0.9999910852620164, 0.9999890743288626, 0.9999866988019865, 0.9999839076130926, 0.9999806445071142, 0.9999768477023036, 0.9999724495395311, 0.9999673761207947, 0.9999615469369367, 0.999954874484572, 0.9999472638722232, 0.9999386124156673, 0.9999288092224893, 0.9999177347658472, 0.9999052604474442, 0.9998912481497119, 0.9998755497772012, 0.9998580067871834, 0.9998384497094605, 0.9998166976553837, 0.9997925578160827, 0.9997658249499025, 0.999736280859051, 0.9997036938554544, 0.9996678182158232, 0.9996283936259261, 0.9995851446140742, 0.9995377799738134, 0.9994859921758271, 0.9994294567690473, 0.9993678317709748, 0.9993007570472097, 0.9992278536801902, 0.9991487233271403, 0.9990629475672279, 0.9989700872379311, 0.998869681760614, 0.9987612484553119, 0.9986442818447255, 0.9985182529474248, 0.998382608560261, 0.9982367705299892, 0.998080135014099, 0.9979120717308554, 0.9977319231985478, 0.9975390039639489, 0.9973325998199832, 0.9971119670126036, 0.996876331436878, 0.9966248878222852, 0.9963567989072191, 0.9960711946027035, 0.9957671711453152, 0.9954437902393161, 0.9951000781879951, 0.9947350250142191, 0.9943475835701934, 0.9939366686364304, 0.9935011560099285, 0.9930398815815602, 0.9925516404026683, 0.9920351857408729, 0.9914892281250863, 0.9909124343797379, 0.9903034266482077, 0.9896607814054699, 0.9889830284599445, 0.9882686499445592, 0.9875160792970205, 0.9867237002292923, 0.9858898456862866, 0.9850127967937606, 0.984090781795425, 0.9831219749792602, 0.982104495593043, 0.9810364067490811, 0.9799157143181576, 0.978740365812685, 0.9775082492590679, 0.9762171920592747, 0.9748649598416194, 0.9734492553007513, 0.9719677170268558, 0.9704179183240623, 0.9687973660180627, 0.9671034992529387, 0.9653336882771985, 0.9634852332190221, 0.9615553628507172, 0.9595412333423818, 0.9574399270047795, 0.9552484510214205, 0.9529637361698543, 0.9505826355321707, 0.9481019231947095, 0.9455182929369806, 0.9428283569097924, 0.9400286443025894, 0.9371156},
    {1.0, 0.9999999999999953, 0.9999999999997022, 0.9999999999966079, 0.9999999999809411, 0.9999999999272962, 0.9999999997829073, 0.9999999994525735, 0.9999999987802313, 0.9999999975271793, 0.9999999953469515, 0.9999999917568408, 0.9999999861060718, 0.9999999775406239, 0.9999999649647041, 0.9999999469988698, 0.9999999219348009, 0.9999998876867218, 0.9999998417394735, 0.999999781093236, 0.9999997022048986, 0.9999996009260829, 0.9999994724378124, 0.9999993111818348, 0.999999110788592, 0.999998864001841, 0.9999985625999245, 0.9999981973136907, 0.9999977577410636, 0.9999972322582629, 0.9999966079276733, 0.9999958704023647, 0.9999950038272605, 0.9999939907369569, 0.9999928119501926, 0.9999914464609663, 0.9999898713263058, 0.9999880615506863, 0.9999859899670982, 0.9999836271147652, 0.9999809411135118, 0.9999778975347812, 0.999974459269302, 0.9999705863914059, 0.999966236019994, 0.9999613621761544, 0.9999559156374276, 0.9999498437887238, 0.9999430904698884, 0.9999355958199183, 0.9999272961178276, 0.9999181236201629, 0.9999080063951687, 0.9998968681536032, 0.9998846280762023, 0.9998712006377948, 0.9998564954280671, 0.9998404169689776, 0.9998228645288206, 0.9998037319329405, 0.9997829073710953, 0.9997602732014707, 0.9997357057513431, 0.999709075114393, 0.9996802449446679, 0.9996490722471952, 0.9996154071652449, 0.9995790927642417, 0.9995399648123278, 0.9994978515575741, 0.999452573501843, 0.9994039431712994, 0.9993517648835726, 0.9992958345115667, 0.9992359392439231, 0.9991718573421298, 0.9991033578942833, 0.9990302005654985, 0.998952135344969, 0.9988689022896773, 0.9987802312647548, 0.9986858416804911, 0.9985854422259942, 0.9984787305994991, 0.9983653932353271, 0.9982451050274953, 0.9981175290499744, 0.9979823162735979, 0.9978391052796202, 0.9976875219699247, 0.997527179273882, 0.9973576768518573, 0.9971786007953681, 0.9969895233238919, 0.9967900024783226, 0.9965795818110783, 0.9963577900728574, 0.9961241408960458, 0.995878132474773, 0.9956192472416178, 0.9953469515409651, 0.9950606952990115, 0.9947599116904207, 0.9944440168016286, 0.9941124092907996, 0.9937644700444305, 0.9933995618306056, 0.9930170289489021, 0.9926161968769434, 0.992196371913604, 0.9917568408188636, 0.9912968704503108, 0.9908157073962964, 0.9903125776057377, 0.9897866860145708, 0.9892372161688545, 0.9886633298445227, 0.9880641666637873, 0.9874388437081904, 0.9867864551283071, 0.9861060717500971, 0.985396740677907, 0.9846574848941214, 0.9838873028554654, 0.9830851680859551, 0.9822500287664989, 0.9813808073211485, 0.9804764},
    {1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0},
    {1.0, 1.0000000000000047, 1.0000000000003038, 1.0000000000034597, 1.0000000000194382, 1.000000000074151, 1.0000000002214138, 1.0000000005583225, 1.000000001244047, 1.0000000025220401, 1.0000000047456632, 1.000000008407232, 1.0000000141704746, 1.00000002290641, 1.0000000357326424, 1.0000000540560707, 1.0000000796190178, 1.0000001145487747, 1.0000001614105622, 1.0000002232639098, 1.0000003037224496, 1.0000004070171307, 1.0000005380628465, 1.0000007025284818, 1.000000906910375, 1.0000011586091981, 1.0000014660102534, 1.000001838567187, 1.0000022868891185, 1.00000282283119, 1.0000034595885279, 1.0000042117936259, 1.0000050956171416, 1.000006128872112, 1.000007331121585, 1.0000087237896673, 1.0000103302759908, 1.0000121760735943, 1.0000142888902226, 1.0000166987730426, 1.0000194382367766, 1.0000225423952513, 1.0000260490963657, 1.0000299990604729, 1.000034436022182, 1.0000394068755751, 1.0000449618228406, 1.0000511545263258, 1.0000580422640029, 1.0000656860883557, 1.0000741509886801, 1.0000835060568027, 1.0000938246562172, 1.0001051845946354, 1.0001176682999573, 1.000131362999657, 1.0001463609035854, 1.0001627593901905, 1.0001806611961532, 1.000200174609442, 1.0002214136657828, 1.0002444983485461, 1.000269554792052, 1.0002967154882902, 1.0003261194970592, 1.0003579126595197, 1.000392247815168, 1.0004292850222227, 1.0004691917814321, 1.0005121432632953, 1.000558322538702, 1.0006079208129879, 1.0006611376634087, 1.0007181812800294, 1.0007792687100308, 1.0008446261054336, 1.000914488974239, 1.0009891024349855, 1.0010687214747234, 1.0011536112104062, 1.0012440471536985, 1.0013403154792009, 1.0014427132960908, 1.001551548923183, 1.0016671421674035, 1.0017898246056827, 1.0019199398702647, 1.0020578439374328, 1.0022039054196534, 1.0023585058611355, 1.0025220400368071, 1.0026949162547094, 1.0028775566618078, 1.0030703975532176, 1.0032738896848503, 1.0034884985894736, 1.0037147048961896, 1.00395300465333, 1.004203909654768, 1.0044679477696459, 1.0047456632755227, 1.0050376171949345, 1.005344387635375, 1.0056665701326912, 1.006004777997897, 1.0063596426674022, 1.0067318140566603, 1.0071219609172322, 1.0075307711972652, 1.0079589524053931, 1.0084072319780484, 1.0088763576501938, 1.0093670978294713, 1.0098802419737667, 1.0104166009721909, 1.010977007529479, 1.0115623165538064, 1.0121734055480207, 1.0128111750042907, 1.013476548802174, 1.0141704746100983, 1.0148939242902633, 1.0156478943069556, 1.016433406138284, 1.0172515066913297, 1.0181032687207134, 1.01898979125058, 1.0199122},
    {1.0, 1.0000000000000149, 1.0000000000009481, 1.0000000000108007, 1.0000000000606857, 1.0000000002314975, 1.000000000691248, 1.0000000017430692, 1.0000000038838848, 1.0000000078737472, 1.0000000148158443, 1.000000026247172, 1.0000000442398742, 1.0000000715132509, 1.0000001115564334, 1.000000168761727, 1.0000002485686208, 1.0000003576184653, 1.0000005039198165, 1.00000069702445, 1.0000009482140382, 1.000001270697499, 1.0000016798190097, 1.0000021932766892, 1.0000028313519465, 1.0000036171494986, 1.0000045768480532, 1.0000057399616615, 1.000007139611736, 1.0000088128097373, 1.0000108007505284, 1.0000131491163944, 1.0000159083917324, 1.0000191341884066, 1.0000228875817727, 1.0000272354573667, 1.0000322508682655, 1.0000380134031104, 1.0000446095648012, 1.0000521331598566, 1.0000606856984415, 1.0000703768050623, 1.0000813246399298, 1.000093656330989, 1.0001075084166169, 1.0001230272989865, 1.0001403697080997, 1.0001597031764875, 1.0001812065245754, 1.0002050703567196, 1.0002314975679076, 1.0002607038611286, 1.000292918275409, 1.0003283837245178, 1.0003673575463365, 1.0004101120629, 1.000456935151101, 1.000508130824065, 1.000564019823191, 1.00062494022086, 1.000691248033811, 1.0007633178471849, 1.0008415434492337, 1.0009263384767009, 1.0010181370708653, 1.0011173945442546, 1.0012245880580264, 1.0013402173100148, 1.0014648052334467, 1.0015988987063238, 1.0017430692714728, 1.0018979138672632, 1.0020640555689915, 1.0022421443409335, 1.002432857799065, 1.0026369019844479, 1.0028550121472843, 1.00308795354164, 1.0033365222308317, 1.0036015459034857, 1.003883884700261, 1.0041844320512403, 1.0045041155239904, 1.004843897682287, 1.00520477695551, 1.0055877885187026, 1.0059940051833023, 1.0064245382985348, 1.006880538663479, 1.0073631974497963, 1.0078737471351296, 1.008413462447169, 1.008983661318385, 1.0095857058514275, 1.0102210032951957, 1.0108910070315718, 1.011597217572824, 1.0123411835696772, 1.0131245028300493, 1.0139488233484573, 1.0148158443460882, 1.0157273173215406, 1.0166850471122297, 1.017690892966463, 1.018746769626182, 1.0198546484203714, 1.0210165583691362, 1.022234587298445, 1.0235108829655426, 1.0248476541950278, 1.0262471720256006, 1.027711770867476, 1.0292438496704641, 1.0308458731027206, 1.0325203727401608, 1.0342699482665438, 1.0360972686842238, 1.0380050735355673, 1.0399961741350399, 1.042073454811958, 1.04423987416391, 1.0464984663208448, 1.0488523422198255, 1.051304690890453, 1.053858780750956, 1.0565179609149487, 1.0592856625088545, 1.0621654},
    {1.0, 1.0000000000000255, 1.000000000001639, 1.0000000000186688, 1.0000000001048943, 1.0000000004001401, 1.0000000011948122, 1.0000000030128702, 1.0000000067132389, 1.0000000136096587, 1.0000000256089738, 1.0000000453678595, 1.0000000764679864, 1.0000001236096256, 1.000000192823691, 1.0000002917022184, 1.0000004296472869, 1.0000006181383747, 1.000000871018157, 1.000001204796739, 1.0000016389743303, 1.000002196382355, 1.0000029035430034, 1.000003791047219, 1.0000048939511264, 1.000006252190896, 1.0000079110160478, 1.0000099214411948, 1.0000123407162225, 1.0000152328149083, 1.00001866894198, 1.0000227280586114, 1.0000274974263563, 1.000033073169523, 1.0000395608559847, 1.0000470760964295, 1.0000557451620493, 1.000065705620667, 1.000077106991301, 1.0000901114171699, 1.0001048943571336, 1.0001216452955755, 1.0001405684707207, 1.0001618836213946, 1.0001858267522177, 1.0002126509172415, 1.0002426270220208, 1.0002760446441257, 1.0003132128720909, 1.0003544611628048, 1.0004001402173366, 1.0004506228752006, 1.000506305027061, 1.0005676065458742, 1.0006349722364685, 1.000708872803565, 1.0007898058382332, 1.0008782968227894, 1.0009749001541295, 1.0010802001855026, 1.0011948122867234, 1.0013193839228205, 1.001454595751126, 1.001601162736803, 1.0017598352868091, 1.0019314004023019, 1.0021166828494799, 1.0023165463488648, 1.0025318947830195, 1.0027636734227063, 1.003012870171483, 1.003280516828737, 1.0035676903711592, 1.0038755142526548, 1.0042051597226938, 1.0045578471630987, 1.0049348474432722, 1.0053374832938626, 1.0057671306988667, 1.0062252203061728, 1.0067132388565414, 1.0072327306310243, 1.0077852989168221, 1.0083726074915806, 1.0089963821261256, 1.009658412105635, 1.010360551769251, 1.0111047220681308, 1.0118929121419333, 1.012727180913748, 1.0136096587034578, 1.0145425488595459, 1.0155281294093352, 1.0165687547276714, 1.0176668572240406, 1.0188249490481271, 1.0200456238138111, 1.0213315583416007, 1.0226855144195075, 1.0241103405823564, 1.0256089739095362, 1.027184441841188, 1.028839864012832, 1.0305784541084329, 1.0324035217319039, 1.0343184742970488, 1.0363268189359423, 1.0384321644257501, 1.0406382231339857, 1.0429488129822073, 1.0453678594281517, 1.0478993974663078, 1.0505475736469276, 1.053316648113477, 1.0562109966585231, 1.0592351127980624, 1.0623936098642848, 1.0656912231167786, 1.0691328118721717, 1.0727233616522132, 1.0764679863502924, 1.080371930416396, 1.0844405710605045, 1.0886794204744272, 1.0930941280720745, 1.0976904827481695, 1.102474415155399, 1.107452}
};
static MYFLT SUPERSAW_BALANCES[7][128] = {{0.044372, 0.0540113055986112, 0.0635591436542873, 0.07301551416702834, 0.08238041713683428, 0.09165385256370512, 0.10083582044764089, 0.10992632078864159, 0.11892535358670717, 0.12783291884183767, 0.1366490165540331, 0.14537364672329345, 0.1540068093496187, 0.16254850443300886, 0.17099873197346394, 0.17935749197098394, 0.18762478442556885, 0.19580060933721868, 0.2038849667059334, 0.21187785653171307, 0.2197792788145576, 0.2275892335544671, 0.2353077207514415, 0.24293474040548083, 0.25047029251658504, 0.2579143770847542, 0.2652669941099882, 0.2725281435922872, 0.27969782553165107, 0.2867760399280799, 0.2937627867815736, 0.30065806609213225, 0.3074618778597557, 0.3141742220844442, 0.32079509876619755, 0.3273245079050158, 0.333762449500899, 0.34010892355384714, 0.3463639300638601, 0.35252746903093807, 0.3585995404550809, 0.36458014433628866, 0.3704692806745614, 0.37626694946989897, 0.3819731507223015, 0.3875878844317689, 0.39311115059830126, 0.3985429492218985, 0.40388328030256065, 0.4091321438402877, 0.4142895398350797, 0.4193554682869366, 0.4243299291958584, 0.4292129225618452, 0.4340044483848969, 0.4387045066650134, 0.4433130974021948, 0.4478302205964412, 0.4522558762477525, 0.45659006435612876, 0.4608327849215699, 0.4649840379440759, 0.4690438234236469, 0.47301214136028275, 0.4768889917539835, 0.4806743746047492, 0.4843682899125799, 0.4879707376774754, 0.4914817178994358, 0.4949012305784613, 0.4982292757145515, 0.5014658533077067, 0.5046109633579267, 0.5076646058652117, 0.5106267808295617, 0.5134974882509765, 0.5162767281294562, 0.518964500465001, 0.5215608052576105, 0.524065642507285, 0.5264790122140244, 0.5288009143778287, 0.531031348998698, 0.5331703160766321, 0.5352178156116313, 0.5371738476036952, 0.5390384120528241, 0.5408115089590179, 0.5424931383222766, 0.5440833001426003, 0.5455819944199888, 0.5469892211544423, 0.5483049803459606, 0.549529271994544, 0.5506620961001921, 0.5517034526629053, 0.5526533416826834, 0.5535117631595262, 0.5542787170934341, 0.5549542034844069, 0.5555382223324447, 0.5560307736375473, 0.5564318573997148, 0.5567414736189472, 0.5569596222952445, 0.557086303428607, 0.5571215170190341, 0.5570652630665262, 0.5569175415710832, 0.5566783525327051, 0.556347695951392, 0.5559255718271436, 0.5554119801599603, 0.5548069209498419, 0.5541103941967883, 0.5533223999007997, 0.552442938061876, 0.5514720086800173, 0.5504096117552235, 0.5492557472874944, 0.5480104152768307, 0.5466736157232315, 0.5452453486266973, 0.543725613987228, 0.5421144118048237, 0.5404117420794842, 0.5386176048112096, 0.536732},
    {0.044372, 0.0540113055986112, 0.0635591436542873, 0.07301551416702834, 0.08238041713683428, 0.09165385256370512, 0.10083582044764089, 0.10992632078864159, 0.11892535358670717, 0.12783291884183767, 0.1366490165540331, 0.14537364672329345, 0.1540068093496187, 0.16254850443300886, 0.17099873197346394, 0.17935749197098394, 0.18762478442556885, 0.19580060933721868, 0.2038849667059334, 0.21187785653171307, 0.2197792788145576, 0.2275892335544671, 0.2353077207514415, 0.24293474040548083, 0.25047029251658504, 0.2579143770847542, 0.2652669941099882, 0.2725281435922872, 0.27969782553165107, 0.2867760399280799, 0.2937627867815736, 0.30065806609213225, 0.3074618778597557, 0.3141742220844442, 0.32079509876619755, 0.3273245079050158, 0.333762449500899, 0.34010892355384714, 0.3463639300638601, 0.35252746903093807, 0.3585995404550809, 0.36458014433628866, 0.3704692806745614, 0.37626694946989897, 0.3819731507223015, 0.3875878844317689, 0.39311115059830126, 0.3985429492218985, 0.40388328030256065, 0.4091321438402877, 0.4142895398350797, 0.4193554682869366, 0.4243299291958584, 0.4292129225618452, 0.4340044483848969, 0.4387045066650134, 0.4433130974021948, 0.4478302205964412, 0.4522558762477525, 0.45659006435612876, 0.4608327849215699, 0.4649840379440759, 0.4690438234236469, 0.47301214136028275, 0.4768889917539835, 0.4806743746047492, 0.4843682899125799, 0.4879707376774754, 0.4914817178994358, 0.4949012305784613, 0.4982292757145515, 0.5014658533077067, 0.5046109633579267, 0.5076646058652117, 0.5106267808295617, 0.5134974882509765, 0.5162767281294562, 0.518964500465001, 0.5215608052576105, 0.524065642507285, 0.5264790122140244, 0.5288009143778287, 0.531031348998698, 0.5331703160766321, 0.5352178156116313, 0.5371738476036952, 0.5390384120528241, 0.5408115089590179, 0.5424931383222766, 0.5440833001426003, 0.5455819944199888, 0.5469892211544423, 0.5483049803459606, 0.549529271994544, 0.5506620961001921, 0.5517034526629053, 0.5526533416826834, 0.5535117631595262, 0.5542787170934341, 0.5549542034844069, 0.5555382223324447, 0.5560307736375473, 0.5564318573997148, 0.5567414736189472, 0.5569596222952445, 0.557086303428607, 0.5571215170190341, 0.5570652630665262, 0.5569175415710832, 0.5566783525327051, 0.556347695951392, 0.5559255718271436, 0.5554119801599603, 0.5548069209498419, 0.5541103941967883, 0.5533223999007997, 0.552442938061876, 0.5514720086800173, 0.5504096117552235, 0.5492557472874944, 0.5480104152768307, 0.5466736157232315, 0.5452453486266973, 0.543725613987228, 0.5421144118048237, 0.5404117420794842, 0.5386176048112096, 0.536732},
    {0.044372, 0.0540113055986112, 0.0635591436542873, 0.07301551416702834, 0.08238041713683428, 0.09165385256370512, 0.10083582044764089, 0.10992632078864159, 0.11892535358670717, 0.12783291884183767, 0.1366490165540331, 0.14537364672329345, 0.1540068093496187, 0.16254850443300886, 0.17099873197346394, 0.17935749197098394, 0.18762478442556885, 0.19580060933721868, 0.2038849667059334, 0.21187785653171307, 0.2197792788145576, 0.2275892335544671, 0.2353077207514415, 0.24293474040548083, 0.25047029251658504, 0.2579143770847542, 0.2652669941099882, 0.2725281435922872, 0.27969782553165107, 0.2867760399280799, 0.2937627867815736, 0.30065806609213225, 0.3074618778597557, 0.3141742220844442, 0.32079509876619755, 0.3273245079050158, 0.333762449500899, 0.34010892355384714, 0.3463639300638601, 0.35252746903093807, 0.3585995404550809, 0.36458014433628866, 0.3704692806745614, 0.37626694946989897, 0.3819731507223015, 0.3875878844317689, 0.39311115059830126, 0.3985429492218985, 0.40388328030256065, 0.4091321438402877, 0.4142895398350797, 0.4193554682869366, 0.4243299291958584, 0.4292129225618452, 0.4340044483848969, 0.4387045066650134, 0.4433130974021948, 0.4478302205964412, 0.4522558762477525, 0.45659006435612876, 0.4608327849215699, 0.4649840379440759, 0.4690438234236469, 0.47301214136028275, 0.4768889917539835, 0.4806743746047492, 0.4843682899125799, 0.4879707376774754, 0.4914817178994358, 0.4949012305784613, 0.4982292757145515, 0.5014658533077067, 0.5046109633579267, 0.5076646058652117, 0.5106267808295617, 0.5134974882509765, 0.5162767281294562, 0.518964500465001, 0.5215608052576105, 0.524065642507285, 0.5264790122140244, 0.5288009143778287, 0.531031348998698, 0.5331703160766321, 0.5352178156116313, 0.5371738476036952, 0.5390384120528241, 0.5408115089590179, 0.5424931383222766, 0.5440833001426003, 0.5455819944199888, 0.5469892211544423, 0.5483049803459606, 0.549529271994544, 0.5506620961001921, 0.5517034526629053, 0.5526533416826834, 0.5535117631595262, 0.5542787170934341, 0.5549542034844069, 0.5555382223324447, 0.5560307736375473, 0.5564318573997148, 0.5567414736189472, 0.5569596222952445, 0.557086303428607, 0.5571215170190341, 0.5570652630665262, 0.5569175415710832, 0.5566783525327051, 0.556347695951392, 0.5559255718271436, 0.5554119801599603, 0.5548069209498419, 0.5541103941967883, 0.5533223999007997, 0.552442938061876, 0.5514720086800173, 0.5504096117552235, 0.5492557472874944, 0.5480104152768307, 0.5466736157232315, 0.5452453486266973, 0.543725613987228, 0.5421144118048237, 0.5404117420794842, 0.5386176048112096, 0.536732},
    {0.99785, 0.9934904251968504, 0.9891308503937009, 0.9847712755905512, 0.9804117007874016, 0.976052125984252, 0.9716925511811024, 0.9673329763779528, 0.9629734015748032, 0.9586138267716535, 0.954254251968504, 0.9498946771653544, 0.9455351023622047, 0.9411755275590551, 0.9368159527559056, 0.9324563779527559, 0.9280968031496063, 0.9237372283464567, 0.9193776535433071, 0.9150180787401575, 0.9106585039370079, 0.9062989291338582, 0.9019393543307087, 0.8975797795275591, 0.8932202047244094, 0.8888606299212598, 0.8845010551181103, 0.8801414803149606, 0.875781905511811, 0.8714223307086615, 0.8670627559055119, 0.8627031811023622, 0.8583436062992126, 0.8539840314960631, 0.8496244566929134, 0.8452648818897638, 0.8409053070866142, 0.8365457322834646, 0.832186157480315, 0.8278265826771654, 0.8234670078740158, 0.8191074330708662, 0.8147478582677166, 0.8103882834645669, 0.8060287086614173, 0.8016691338582678, 0.7973095590551181, 0.7929499842519685, 0.788590409448819, 0.7842308346456693, 0.7798712598425197, 0.7755116850393701, 0.7711521102362204, 0.7667925354330709, 0.7624329606299213, 0.7580733858267716, 0.7537138110236221, 0.7493542362204725, 0.7449946614173228, 0.7406350866141733, 0.7362755118110236, 0.731915937007874, 0.7275563622047244, 0.7231967874015748, 0.7188372125984253, 0.7144776377952756, 0.710118062992126, 0.7057584881889765, 0.7013989133858267, 0.6970393385826772, 0.6926797637795276, 0.6883201889763779, 0.6839606141732284, 0.6796010393700788, 0.6752414645669291, 0.6708818897637796, 0.6665223149606299, 0.6621627401574803, 0.6578031653543307, 0.6534435905511811, 0.6490840157480315, 0.6447244409448819, 0.6403648661417323, 0.6360052913385827, 0.631645716535433, 0.6272861417322835, 0.622926566929134, 0.6185669921259842, 0.6142074173228347, 0.609847842519685, 0.6054882677165354, 0.6011286929133859, 0.5967691181102361, 0.5924095433070866, 0.5880499685039371, 0.5836903937007873, 0.5793308188976378, 0.5749712440944883, 0.5706116692913386, 0.566252094488189, 0.5618925196850394, 0.5575329448818898, 0.5531733700787402, 0.5488137952755906, 0.544454220472441, 0.5400946456692914, 0.5357350708661417, 0.5313754960629922, 0.5270159212598425, 0.5226563464566929, 0.5182967716535434, 0.5139371968503937, 0.5095776220472441, 0.5052180472440946, 0.500858472440945, 0.4964988976377953, 0.4921393228346457, 0.48777974803149604, 0.4834201732283465, 0.4790605984251969, 0.47470102362204725, 0.4703414488188977, 0.4659818740157481, 0.46162229921259845, 0.4572627244094488, 0.4529031496062992, 0.44854357480314966, 0.444184},
    {0.044372, 0.054437289850579704, 0.06441111215822432, 0.07429346692293384, 0.08408435414470829, 0.09378377382354765, 0.10339172595945192, 0.11290821055242112, 0.12233322760245521, 0.1316667771095542, 0.14090885907371814, 0.150059473494947, 0.15911862037324073, 0.16808629970859942, 0.176962511501023, 0.1857472557505115, 0.1944405324570649, 0.20304234162068327, 0.21155268324136647, 0.21997155731911466, 0.2282989638539277, 0.23653490284580572, 0.2446793742947486, 0.25273237820075645, 0.2606939145638291, 0.26856398338396675, 0.27634258466116934, 0.2840297183954368, 0.2916253845867692, 0.2991295832351665, 0.3065423143406287, 0.31386357790315583, 0.3210933739227479, 0.3282317023994048, 0.3352785633331267, 0.3422339567239135, 0.34909788257176516, 0.3558703408766818, 0.3625513316386633, 0.3691408548577098, 0.3756389105338211, 0.3820454986669974, 0.3883606192572386, 0.3945842723045447, 0.4007164578089156, 0.4067571757703516, 0.41270642618885245, 0.4185642090644182, 0.4243305243970488, 0.4300053721867444, 0.43558875243350487, 0.44108066513733035, 0.44648111029822063, 0.4517900879161758, 0.457007597991196, 0.46213364052328115, 0.46716821551243104, 0.4721113229586459, 0.4769629628619257, 0.48172313522227056, 0.4863918400396801, 0.4909690773141547, 0.4954548470456941, 0.4998491492342985, 0.5041519838799677, 0.508363350982702, 0.5124832505425011, 0.5165116825593651, 0.5204486470332941, 0.524294143964288, 0.5280481733523468, 0.5317107351974705, 0.535281829499659, 0.5387614562589126, 0.542149615475231, 0.5454463071486143, 0.5486515312790626, 0.5517652878665756, 0.5547875769111539, 0.5577183984127968, 0.5605577523715047, 0.5633056387872776, 0.5659620576601153, 0.568527008990018, 0.5710004927769856, 0.5733825090210181, 0.5756730577221155, 0.5778721388802778, 0.5799797524955049, 0.5819958985677972, 0.5839205770971542, 0.5857537880835761, 0.587495531527063, 0.5891458074276149, 0.5907046157852317, 0.5921719565999132, 0.5935478298716598, 0.5948322356004713, 0.5960251737863476, 0.597126644429289, 0.598136647529295, 0.5990551830863663, 0.5998822511005023, 0.6006178515717031, 0.601261984499969, 0.6018146498852998, 0.6022758477276954, 0.6026455780271561, 0.6029238407836814, 0.6031106359972721, 0.6032059636679274, 0.6032098237956476, 0.6031222163804327, 0.6029431414222828, 0.6026725989211977, 0.6023105888771778, 0.6018571112902225, 0.6013121661603325, 0.6006757534875071, 0.5999478732717465, 0.5991285255130511, 0.5982177102114203, 0.5972154273668548, 0.596121676979354, 0.594936459048918, 0.5936597735755472, 0.5922916205592411, 0.590832},
    {0.044372, 0.054437289850579704, 0.06441111215822432, 0.07429346692293384, 0.08408435414470829, 0.09378377382354765, 0.10339172595945192, 0.11290821055242112, 0.12233322760245521, 0.1316667771095542, 0.14090885907371814, 0.150059473494947, 0.15911862037324073, 0.16808629970859942, 0.176962511501023, 0.1857472557505115, 0.1944405324570649, 0.20304234162068327, 0.21155268324136647, 0.21997155731911466, 0.2282989638539277, 0.23653490284580572, 0.2446793742947486, 0.25273237820075645, 0.2606939145638291, 0.26856398338396675, 0.27634258466116934, 0.2840297183954368, 0.2916253845867692, 0.2991295832351665, 0.3065423143406287, 0.31386357790315583, 0.3210933739227479, 0.3282317023994048, 0.3352785633331267, 0.3422339567239135, 0.34909788257176516, 0.3558703408766818, 0.3625513316386633, 0.3691408548577098, 0.3756389105338211, 0.3820454986669974, 0.3883606192572386, 0.3945842723045447, 0.4007164578089156, 0.4067571757703516, 0.41270642618885245, 0.4185642090644182, 0.4243305243970488, 0.4300053721867444, 0.43558875243350487, 0.44108066513733035, 0.44648111029822063, 0.4517900879161758, 0.457007597991196, 0.46213364052328115, 0.46716821551243104, 0.4721113229586459, 0.4769629628619257, 0.48172313522227056, 0.4863918400396801, 0.4909690773141547, 0.4954548470456941, 0.4998491492342985, 0.5041519838799677, 0.508363350982702, 0.5124832505425011, 0.5165116825593651, 0.5204486470332941, 0.524294143964288, 0.5280481733523468, 0.5317107351974705, 0.535281829499659, 0.5387614562589126, 0.542149615475231, 0.5454463071486143, 0.5486515312790626, 0.5517652878665756, 0.5547875769111539, 0.5577183984127968, 0.5605577523715047, 0.5633056387872776, 0.5659620576601153, 0.568527008990018, 0.5710004927769856, 0.5733825090210181, 0.5756730577221155, 0.5778721388802778, 0.5799797524955049, 0.5819958985677972, 0.5839205770971542, 0.5857537880835761, 0.587495531527063, 0.5891458074276149, 0.5907046157852317, 0.5921719565999132, 0.5935478298716598, 0.5948322356004713, 0.5960251737863476, 0.597126644429289, 0.598136647529295, 0.5990551830863663, 0.5998822511005023, 0.6006178515717031, 0.601261984499969, 0.6018146498852998, 0.6022758477276954, 0.6026455780271561, 0.6029238407836814, 0.6031106359972721, 0.6032059636679274, 0.6032098237956476, 0.6031222163804327, 0.6029431414222828, 0.6026725989211977, 0.6023105888771778, 0.6018571112902225, 0.6013121661603325, 0.6006757534875071, 0.5999478732717465, 0.5991285255130511, 0.5982177102114203, 0.5972154273668548, 0.596121676979354, 0.594936459048918, 0.5936597735755472, 0.5922916205592411, 0.590832},
    {0.044372, 0.054437289850579704, 0.06441111215822432, 0.07429346692293384, 0.08408435414470829, 0.09378377382354765, 0.10339172595945192, 0.11290821055242112, 0.12233322760245521, 0.1316667771095542, 0.14090885907371814, 0.150059473494947, 0.15911862037324073, 0.16808629970859942, 0.176962511501023, 0.1857472557505115, 0.1944405324570649, 0.20304234162068327, 0.21155268324136647, 0.21997155731911466, 0.2282989638539277, 0.23653490284580572, 0.2446793742947486, 0.25273237820075645, 0.2606939145638291, 0.26856398338396675, 0.27634258466116934, 0.2840297183954368, 0.2916253845867692, 0.2991295832351665, 0.3065423143406287, 0.31386357790315583, 0.3210933739227479, 0.3282317023994048, 0.3352785633331267, 0.3422339567239135, 0.34909788257176516, 0.3558703408766818, 0.3625513316386633, 0.3691408548577098, 0.3756389105338211, 0.3820454986669974, 0.3883606192572386, 0.3945842723045447, 0.4007164578089156, 0.4067571757703516, 0.41270642618885245, 0.4185642090644182, 0.4243305243970488, 0.4300053721867444, 0.43558875243350487, 0.44108066513733035, 0.44648111029822063, 0.4517900879161758, 0.457007597991196, 0.46213364052328115, 0.46716821551243104, 0.4721113229586459, 0.4769629628619257, 0.48172313522227056, 0.4863918400396801, 0.4909690773141547, 0.4954548470456941, 0.4998491492342985, 0.5041519838799677, 0.508363350982702, 0.5124832505425011, 0.5165116825593651, 0.5204486470332941, 0.524294143964288, 0.5280481733523468, 0.5317107351974705, 0.535281829499659, 0.5387614562589126, 0.542149615475231, 0.5454463071486143, 0.5486515312790626, 0.5517652878665756, 0.5547875769111539, 0.5577183984127968, 0.5605577523715047, 0.5633056387872776, 0.5659620576601153, 0.568527008990018, 0.5710004927769856, 0.5733825090210181, 0.5756730577221155, 0.5778721388802778, 0.5799797524955049, 0.5819958985677972, 0.5839205770971542, 0.5857537880835761, 0.587495531527063, 0.5891458074276149, 0.5907046157852317, 0.5921719565999132, 0.5935478298716598, 0.5948322356004713, 0.5960251737863476, 0.597126644429289, 0.598136647529295, 0.5990551830863663, 0.5998822511005023, 0.6006178515717031, 0.601261984499969, 0.6018146498852998, 0.6022758477276954, 0.6026455780271561, 0.6029238407836814, 0.6031106359972721, 0.6032059636679274, 0.6032098237956476, 0.6031222163804327, 0.6029431414222828, 0.6026725989211977, 0.6023105888771778, 0.6018571112902225, 0.6013121661603325, 0.6006757534875071, 0.5999478732717465, 0.5991285255130511, 0.5982177102114203, 0.5972154273668548, 0.596121676979354, 0.594936459048918, 0.5936597735755472, 0.5922916205592411, 0.590832}
};

/**************/
/* SuperSaw object */
/**************/
typedef struct
{
    pyo_audio_HEAD
    PyObject *freq;
    Stream *freq_stream;
    PyObject *detune;
    Stream *detune_stream;
    PyObject *bal;
    Stream *bal_stream;
    int modebuffer[5];
    double pointerPos[7];
    // sample memories
    MYFLT x1;
    MYFLT x2;
    MYFLT y1;
    MYFLT y2;
    // variables
    MYFLT c;
    MYFLT w0;
    MYFLT alpha;
    // coefficients
    MYFLT b0;
    MYFLT b1;
    MYFLT b2;
    MYFLT a0;
    MYFLT a1;
    MYFLT a2;
    MYFLT lastFilterFreq;
    MYFLT nyquist;
} SuperSaw;

static void
SuperSaw_readframes_iii(SuperSaw *self)
{
    MYFLT fr, det, bal, twoOnSr, val;
    int i, j, det_ind, bal_ind;
    MYFLT inc[7];
    MYFLT amp[7];

    fr = PyFloat_AS_DOUBLE(self->freq);
    det = _clip(PyFloat_AS_DOUBLE(self->detune));
    bal = _clip(PyFloat_AS_DOUBLE(self->bal));
    twoOnSr = 2.0 / self->sr;

    if (fr <= 1.0)
        fr = 1.0;
    else if (fr >= self->nyquist)
        fr = self->nyquist;

    det_ind = (int)(det * 126);
    bal_ind = (int)(bal * 126);

    if (fr != self->lastFilterFreq)
    {
        self->lastFilterFreq = fr;
        self->w0 = TWOPI * fr / self->sr;
        self->c = MYCOS(self->w0);
        self->alpha = MYSIN(self->w0) * 0.5;
        self->b0 = self->b2 = (1 + self->c) * 0.5;
        self->b1 = -(1 + self->c);
        self->a0 = 1 + self->alpha;
        self->a1 = -2 * self->c;
        self->a2 = 1 - self->alpha;
    }

    for (j = 0; j < 7; j++)
    {
        inc[j] = fr * SUPERSAW_DETUNES[j][det_ind] * twoOnSr;
        amp[j] = SUPERSAW_BALANCES[j][bal_ind];
    }

    for (i = 0; i < self->bufsize; i++)
    {
        val = 0.0;

        for (j = 0; j < 7; j++)
        {
            val += self->pointerPos[j] * amp[j];
            self->pointerPos[j] += inc[j];

            if (self->pointerPos[j] < -1.0)
                self->pointerPos[j] += 2.0;
            else if (self->pointerPos[j] >= 1.0)
                self->pointerPos[j] -= 2.0;
        }

        self->data[i] = ( (self->b0 * val) + (self->b1 * self->x1) + (self->b2 * self->x2) - (self->a1 * self->y1) - (self->a2 * self->y2) ) / self->a0;
        self->y2 = self->y1;
        self->y1 = self->data[i];
        self->x2 = self->x1;
        self->x1 = val;
        self->data[i] *= 0.2;
    }
}

static void
SuperSaw_readframes_aii(SuperSaw *self)
{
    MYFLT fr, det, bal, twoOnSr, val;
    int i, j, det_ind, bal_ind;

    MYFLT *freq = Stream_getData((Stream *)self->freq_stream);
    det = _clip(PyFloat_AS_DOUBLE(self->detune));
    bal = _clip(PyFloat_AS_DOUBLE(self->bal));
    twoOnSr = 2.0 / self->sr;

    det_ind = (int)(det * 126);
    bal_ind = (int)(bal * 126);

    for (i = 0; i < self->bufsize; i++)
    {
        fr = freq[i];

        if (fr <= 1.0)
            fr = 1.0;
        else if (fr >= self->nyquist)
            fr = self->nyquist;

        if (fr != self->lastFilterFreq)
        {
            self->lastFilterFreq = fr;
            self->w0 = TWOPI * fr / self->sr;
            self->c = MYCOS(self->w0);
            self->alpha = MYSIN(self->w0) * 0.5;
            self->b0 = self->b2 = (1 + self->c) * 0.5;
            self->b1 = -(1 + self->c);
            self->a0 = 1 + self->alpha;
            self->a1 = -2 * self->c;
            self->a2 = 1 - self->alpha;
        }

        val = 0.0;

        for (j = 0; j < 7; j++)
        {
            val += self->pointerPos[j] * SUPERSAW_BALANCES[j][bal_ind];
            self->pointerPos[j] += fr * SUPERSAW_DETUNES[j][det_ind] * twoOnSr;

            if (self->pointerPos[j] < -1.0)
                self->pointerPos[j] += 2.0;
            else if (self->pointerPos[j] >= 1.0)
                self->pointerPos[j] -= 2.0;
        }

        self->data[i] = ( (self->b0 * val) + (self->b1 * self->x1) + (self->b2 * self->x2) - (self->a1 * self->y1) - (self->a2 * self->y2) ) / self->a0;
        self->y2 = self->y1;
        self->y1 = self->data[i];
        self->x2 = self->x1;
        self->x1 = val;
        self->data[i] *= 0.2;
    }
}

static void
SuperSaw_readframes_iai(SuperSaw *self)
{
    MYFLT fr, bal, twoOnSr, val;
    int i, j, det_ind, bal_ind;

    fr = PyFloat_AS_DOUBLE(self->freq);
    MYFLT *detune = Stream_getData((Stream *)self->detune_stream);
    bal = _clip(PyFloat_AS_DOUBLE(self->bal));
    twoOnSr = 2.0 / self->sr;

    if (fr <= 1.0)
        fr = 1.0;
    else if (fr >= self->nyquist)
        fr = self->nyquist;

    bal_ind = (int)(bal * 126);

    if (fr != self->lastFilterFreq)
    {
        self->lastFilterFreq = fr;
        self->w0 = TWOPI * fr / self->sr;
        self->c = MYCOS(self->w0);
        self->alpha = MYSIN(self->w0) * 0.5;
        self->b0 = self->b2 = (1 + self->c) * 0.5;
        self->b1 = -(1 + self->c);
        self->a0 = 1 + self->alpha;
        self->a1 = -2 * self->c;
        self->a2 = 1 - self->alpha;
    }

    for (i = 0; i < self->bufsize; i++)
    {
        det_ind = (int)(_clip(detune[i]) * 126);
        val = 0.0;

        for (j = 0; j < 7; j++)
        {
            val += self->pointerPos[j] * SUPERSAW_BALANCES[j][bal_ind];
            self->pointerPos[j] += fr * SUPERSAW_DETUNES[j][det_ind] * twoOnSr;

            if (self->pointerPos[j] < -1.0)
                self->pointerPos[j] += 2.0;
            else if (self->pointerPos[j] >= 1.0)
                self->pointerPos[j] -= 2.0;
        }

        self->data[i] = ( (self->b0 * val) + (self->b1 * self->x1) + (self->b2 * self->x2) - (self->a1 * self->y1) - (self->a2 * self->y2) ) / self->a0;
        self->y2 = self->y1;
        self->y1 = self->data[i];
        self->x2 = self->x1;
        self->x1 = val;
        self->data[i] *= 0.2;
    }
}

static void
SuperSaw_readframes_aai(SuperSaw *self)
{
    MYFLT fr, bal, twoOnSr, val;
    int i, j, det_ind, bal_ind;

    MYFLT *freq = Stream_getData((Stream *)self->freq_stream);
    MYFLT *detune = Stream_getData((Stream *)self->detune_stream);
    bal = _clip(PyFloat_AS_DOUBLE(self->bal));
    twoOnSr = 2.0 / self->sr;

    bal_ind = (int)(bal * 126);

    for (i = 0; i < self->bufsize; i++)
    {
        fr = freq[i];

        if (fr <= 1.0)
            fr = 1.0;
        else if (fr >= self->nyquist)
            fr = self->nyquist;

        if (fr != self->lastFilterFreq)
        {
            self->lastFilterFreq = fr;
            self->w0 = TWOPI * fr / self->sr;
            self->c = MYCOS(self->w0);
            self->alpha = MYSIN(self->w0) * 0.5;
            self->b0 = self->b2 = (1 + self->c) * 0.5;
            self->b1 = -(1 + self->c);
            self->a0 = 1 + self->alpha;
            self->a1 = -2 * self->c;
            self->a2 = 1 - self->alpha;
        }

        det_ind = (int)(_clip(detune[i]) * 126);
        val = 0.0;

        for (j = 0; j < 7; j++)
        {
            val += self->pointerPos[j] * SUPERSAW_BALANCES[j][bal_ind];
            self->pointerPos[j] += fr * SUPERSAW_DETUNES[j][det_ind] * twoOnSr;

            if (self->pointerPos[j] < -1.0)
                self->pointerPos[j] += 2.0;
            else if (self->pointerPos[j] >= 1.0)
                self->pointerPos[j] -= 2.0;
        }

        self->data[i] = ( (self->b0 * val) + (self->b1 * self->x1) + (self->b2 * self->x2) - (self->a1 * self->y1) - (self->a2 * self->y2) ) / self->a0;
        self->y2 = self->y1;
        self->y1 = self->data[i];
        self->x2 = self->x1;
        self->x1 = val;
        self->data[i] *= 0.2;
    }
}

static void
SuperSaw_readframes_iia(SuperSaw *self)
{
    MYFLT fr, det, twoOnSr, val;
    int i, j, det_ind, bal_ind;
    MYFLT inc[7];

    fr = PyFloat_AS_DOUBLE(self->freq);
    det = _clip(PyFloat_AS_DOUBLE(self->detune));
    MYFLT *balance = Stream_getData((Stream *)self->bal_stream);
    twoOnSr = 2.0 / self->sr;

    if (fr <= 1.0)
        fr = 1.0;
    else if (fr >= self->nyquist)
        fr = self->nyquist;

    det_ind = (int)(det * 126);

    if (fr != self->lastFilterFreq)
    {
        self->lastFilterFreq = fr;
        self->w0 = TWOPI * fr / self->sr;
        self->c = MYCOS(self->w0);
        self->alpha = MYSIN(self->w0) * 0.5;
        self->b0 = self->b2 = (1 + self->c) * 0.5;
        self->b1 = -(1 + self->c);
        self->a0 = 1 + self->alpha;
        self->a1 = -2 * self->c;
        self->a2 = 1 - self->alpha;
    }

    for (j = 0; j < 7; j++)
    {
        inc[j] = fr * SUPERSAW_DETUNES[j][det_ind] * twoOnSr;
    }

    for (i = 0; i < self->bufsize; i++)
    {
        bal_ind = (int)(_clip(balance[i]) * 126);
        val = 0.0;

        for (j = 0; j < 7; j++)
        {
            val += self->pointerPos[j] * SUPERSAW_BALANCES[j][bal_ind];
            self->pointerPos[j] += inc[j];

            if (self->pointerPos[j] < -1.0)
                self->pointerPos[j] += 2.0;
            else if (self->pointerPos[j] >= 1.0)
                self->pointerPos[j] -= 2.0;
        }

        self->data[i] = ( (self->b0 * val) + (self->b1 * self->x1) + (self->b2 * self->x2) - (self->a1 * self->y1) - (self->a2 * self->y2) ) / self->a0;
        self->y2 = self->y1;
        self->y1 = self->data[i];
        self->x2 = self->x1;
        self->x1 = val;
        self->data[i] *= 0.2;
    }
}

static void
SuperSaw_readframes_aia(SuperSaw *self)
{
    MYFLT fr, det, twoOnSr, val;
    int i, j, det_ind, bal_ind;

    MYFLT *freq = Stream_getData((Stream *)self->freq_stream);
    det = _clip(PyFloat_AS_DOUBLE(self->detune));
    MYFLT *balance = Stream_getData((Stream *)self->bal_stream);
    twoOnSr = 2.0 / self->sr;

    det_ind = (int)(det * 126);

    for (i = 0; i < self->bufsize; i++)
    {
        fr = freq[i];

        if (fr <= 1.0)
            fr = 1.0;
        else if (fr >= self->nyquist)
            fr = self->nyquist;

        if (fr != self->lastFilterFreq)
        {
            self->lastFilterFreq = fr;
            self->w0 = TWOPI * fr / self->sr;
            self->c = MYCOS(self->w0);
            self->alpha = MYSIN(self->w0) * 0.5;
            self->b0 = self->b2 = (1 + self->c) * 0.5;
            self->b1 = -(1 + self->c);
            self->a0 = 1 + self->alpha;
            self->a1 = -2 * self->c;
            self->a2 = 1 - self->alpha;
        }

        bal_ind = (int)(_clip(balance[i]) * 126);
        val = 0.0;

        for (j = 0; j < 7; j++)
        {
            val += self->pointerPos[j] * SUPERSAW_BALANCES[j][bal_ind];
            self->pointerPos[j] += fr * SUPERSAW_DETUNES[j][det_ind] * twoOnSr;

            if (self->pointerPos[j] < -1.0)
                self->pointerPos[j] += 2.0;
            else if (self->pointerPos[j] >= 1.0)
                self->pointerPos[j] -= 2.0;
        }

        self->data[i] = ( (self->b0 * val) + (self->b1 * self->x1) + (self->b2 * self->x2) - (self->a1 * self->y1) - (self->a2 * self->y2) ) / self->a0;
        self->y2 = self->y1;
        self->y1 = self->data[i];
        self->x2 = self->x1;
        self->x1 = val;
        self->data[i] *= 0.2;
    }
}

static void
SuperSaw_readframes_iaa(SuperSaw *self)
{
    MYFLT fr, twoOnSr, val;
    int i, j, det_ind, bal_ind;

    fr = PyFloat_AS_DOUBLE(self->freq);
    MYFLT *detune = Stream_getData((Stream *)self->detune_stream);
    MYFLT *balance = Stream_getData((Stream *)self->bal_stream);
    twoOnSr = 2.0 / self->sr;

    if (fr <= 1.0)
        fr = 1.0;
    else if (fr >= self->nyquist)
        fr = self->nyquist;

    if (fr != self->lastFilterFreq)
    {
        self->lastFilterFreq = fr;
        self->w0 = TWOPI * fr / self->sr;
        self->c = MYCOS(self->w0);
        self->alpha = MYSIN(self->w0) * 0.5;
        self->b0 = self->b2 = (1 + self->c) * 0.5;
        self->b1 = -(1 + self->c);
        self->a0 = 1 + self->alpha;
        self->a1 = -2 * self->c;
        self->a2 = 1 - self->alpha;
    }

    for (i = 0; i < self->bufsize; i++)
    {
        det_ind = (int)(_clip(detune[i]) * 126);
        bal_ind = (int)(_clip(balance[i]) * 126);
        val = 0.0;

        for (j = 0; j < 7; j++)
        {
            val += self->pointerPos[j] * SUPERSAW_BALANCES[j][bal_ind];
            self->pointerPos[j] += fr * SUPERSAW_DETUNES[j][det_ind] * twoOnSr;

            if (self->pointerPos[j] < -1.0)
                self->pointerPos[j] += 2.0;
            else if (self->pointerPos[j] >= 1.0)
                self->pointerPos[j] -= 2.0;
        }

        self->data[i] = ( (self->b0 * val) + (self->b1 * self->x1) + (self->b2 * self->x2) - (self->a1 * self->y1) - (self->a2 * self->y2) ) / self->a0;
        self->y2 = self->y1;
        self->y1 = self->data[i];
        self->x2 = self->x1;
        self->x1 = val;
        self->data[i] *= 0.2;
    }
}

static void
SuperSaw_readframes_aaa(SuperSaw *self)
{
    MYFLT fr, twoOnSr, val;
    int i, j, det_ind, bal_ind;

    MYFLT *freq = Stream_getData((Stream *)self->freq_stream);
    MYFLT *detune = Stream_getData((Stream *)self->detune_stream);
    MYFLT *balance = Stream_getData((Stream *)self->bal_stream);
    twoOnSr = 2.0 / self->sr;

    for (i = 0; i < self->bufsize; i++)
    {
        fr = freq[i];

        if (fr <= 1.0)
            fr = 1.0;
        else if (fr >= self->nyquist)
            fr = self->nyquist;

        if (fr != self->lastFilterFreq)
        {
            self->lastFilterFreq = fr;
            self->w0 = TWOPI * fr / self->sr;
            self->c = MYCOS(self->w0);
            self->alpha = MYSIN(self->w0) * 0.5;
            self->b0 = self->b2 = (1 + self->c) * 0.5;
            self->b1 = -(1 + self->c);
            self->a0 = 1 + self->alpha;
            self->a1 = -2 * self->c;
            self->a2 = 1 - self->alpha;
        }

        det_ind = (int)(_clip(detune[i]) * 126);
        bal_ind = (int)(_clip(balance[i]) * 126);

        val = 0.0;

        for (j = 0; j < 7; j++)
        {
            val += self->pointerPos[j] * SUPERSAW_BALANCES[j][bal_ind];
            self->pointerPos[j] += fr * SUPERSAW_DETUNES[j][det_ind] * twoOnSr;

            if (self->pointerPos[j] < -1.0)
                self->pointerPos[j] += 2.0;
            else if (self->pointerPos[j] >= 1.0)
                self->pointerPos[j] -= 2.0;
        }

        self->data[i] = ( (self->b0 * val) + (self->b1 * self->x1) + (self->b2 * self->x2) - (self->a1 * self->y1) - (self->a2 * self->y2) ) / self->a0;
        self->y2 = self->y1;
        self->y1 = self->data[i];
        self->x2 = self->x1;
        self->x1 = val;
        self->data[i] *= 0.2;
    }
}

static void SuperSaw_postprocessing_ii(SuperSaw *self) { POST_PROCESSING_II };
static void SuperSaw_postprocessing_ai(SuperSaw *self) { POST_PROCESSING_AI };
static void SuperSaw_postprocessing_ia(SuperSaw *self) { POST_PROCESSING_IA };
static void SuperSaw_postprocessing_aa(SuperSaw *self) { POST_PROCESSING_AA };
static void SuperSaw_postprocessing_ireva(SuperSaw *self) { POST_PROCESSING_IREVA };
static void SuperSaw_postprocessing_areva(SuperSaw *self) { POST_PROCESSING_AREVA };
static void SuperSaw_postprocessing_revai(SuperSaw *self) { POST_PROCESSING_REVAI };
static void SuperSaw_postprocessing_revaa(SuperSaw *self) { POST_PROCESSING_REVAA };
static void SuperSaw_postprocessing_revareva(SuperSaw *self) { POST_PROCESSING_REVAREVA };

static void
SuperSaw_setProcMode(SuperSaw *self)
{
    int procmode, muladdmode;
    procmode = self->modebuffer[2] + self->modebuffer[3] * 10 + self->modebuffer[4] * 100;
    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;

    switch (procmode)
    {
        case 0:
            self->proc_func_ptr = SuperSaw_readframes_iii;
            break;

        case 1:
            self->proc_func_ptr = SuperSaw_readframes_aii;
            break;

        case 10:
            self->proc_func_ptr = SuperSaw_readframes_iai;
            break;

        case 11:
            self->proc_func_ptr = SuperSaw_readframes_aai;
            break;

        case 100:
            self->proc_func_ptr = SuperSaw_readframes_iia;
            break;

        case 101:
            self->proc_func_ptr = SuperSaw_readframes_aia;
            break;

        case 110:
            self->proc_func_ptr = SuperSaw_readframes_iaa;
            break;

        case 111:
            self->proc_func_ptr = SuperSaw_readframes_aaa;
            break;
    }

    switch (muladdmode)
    {
        case 0:
            self->muladd_func_ptr = SuperSaw_postprocessing_ii;
            break;

        case 1:
            self->muladd_func_ptr = SuperSaw_postprocessing_ai;
            break;

        case 2:
            self->muladd_func_ptr = SuperSaw_postprocessing_revai;
            break;

        case 10:
            self->muladd_func_ptr = SuperSaw_postprocessing_ia;
            break;

        case 11:
            self->muladd_func_ptr = SuperSaw_postprocessing_aa;
            break;

        case 12:
            self->muladd_func_ptr = SuperSaw_postprocessing_revaa;
            break;

        case 20:
            self->muladd_func_ptr = SuperSaw_postprocessing_ireva;
            break;

        case 21:
            self->muladd_func_ptr = SuperSaw_postprocessing_areva;
            break;

        case 22:
            self->muladd_func_ptr = SuperSaw_postprocessing_revareva;
            break;
    }
}

static void
SuperSaw_compute_next_data_frame(SuperSaw *self)
{
    (*self->proc_func_ptr)(self);
    (*self->muladd_func_ptr)(self);
}

static int
SuperSaw_traverse(SuperSaw *self, visitproc visit, void *arg)
{
    pyo_VISIT
    Py_VISIT(self->freq);
    Py_VISIT(self->detune);
    Py_VISIT(self->bal);
    return 0;
}

static int
SuperSaw_clear(SuperSaw *self)
{
    pyo_CLEAR
    Py_CLEAR(self->freq);
    Py_CLEAR(self->detune);
    Py_CLEAR(self->bal);
    return 0;
}

static void
SuperSaw_dealloc(SuperSaw* self)
{
    pyo_DEALLOC
    SuperSaw_clear(self);
    Py_TYPE(self->stream)->tp_free((PyObject*)self->stream);
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject *
SuperSaw_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    int i;
    PyObject *freqtmp = NULL, *detunetmp = NULL, *baltmp = NULL, *multmp = NULL, *addtmp = NULL;
    SuperSaw *self;
    self = (SuperSaw *)type->tp_alloc(type, 0);

    self->freq = PyFloat_FromDouble(100);
    self->detune = PyFloat_FromDouble(0.5);
    self->bal = PyFloat_FromDouble(0.7);
    self->modebuffer[0] = 0;
    self->modebuffer[1] = 0;
    self->modebuffer[2] = 0;
    self->modebuffer[3] = 0;
    self->modebuffer[4] = 0;
    self->pointerPos[0] = -0.75;
    self->pointerPos[1] = -0.5;
    self->pointerPos[2] = -0.25;
    self->pointerPos[3] = 0.0;
    self->pointerPos[4] = 0.25;
    self->pointerPos[5] = 0.5;
    self->pointerPos[6] = 0.75;
    self->lastFilterFreq = -1.0;
    self->x1 = self->x2 = self->y1 = self->y2 = 0.0;

    INIT_OBJECT_COMMON

    self->nyquist = (MYFLT)self->sr * 0.49;

    Stream_setFunctionPtr(self->stream, SuperSaw_compute_next_data_frame);
    self->mode_func_ptr = SuperSaw_setProcMode;

    static char *kwlist[] = {"freq", "detune", "bal", "mul", "add", NULL};

    if (! PyArg_ParseTupleAndKeywords(args, kwds, "|OOOOO", kwlist, &freqtmp, &detunetmp, &baltmp, &multmp, &addtmp))
        Py_RETURN_NONE;

    if (freqtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setFreq", "O", freqtmp);
    }

    if (detunetmp)
    {
        PyObject_CallMethod((PyObject *)self, "setDetune", "O", detunetmp);
    }

    if (baltmp)
    {
        PyObject_CallMethod((PyObject *)self, "setBal", "O", baltmp);
    }

    if (multmp)
    {
        PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
    }

    if (addtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
    }

    PyObject_CallMethod(self->server, "addStream", "O", self->stream);

    (*self->mode_func_ptr)(self);

    return (PyObject *)self;
}

static PyObject * SuperSaw_getServer(SuperSaw* self) { GET_SERVER };
static PyObject * SuperSaw_getStream(SuperSaw* self) { GET_STREAM };
static PyObject * SuperSaw_setMul(SuperSaw *self, PyObject *arg) { SET_MUL };
static PyObject * SuperSaw_setAdd(SuperSaw *self, PyObject *arg) { SET_ADD };
static PyObject * SuperSaw_setSub(SuperSaw *self, PyObject *arg) { SET_SUB };
static PyObject * SuperSaw_setDiv(SuperSaw *self, PyObject *arg) { SET_DIV };

static PyObject * SuperSaw_play(SuperSaw *self, PyObject *args, PyObject *kwds) { PLAY };
static PyObject * SuperSaw_out(SuperSaw *self, PyObject *args, PyObject *kwds) { OUT };
static PyObject * SuperSaw_stop(SuperSaw *self, PyObject *args, PyObject *kwds) { STOP };

static PyObject * SuperSaw_multiply(SuperSaw *self, PyObject *arg) { MULTIPLY };
static PyObject * SuperSaw_inplace_multiply(SuperSaw *self, PyObject *arg) { INPLACE_MULTIPLY };
static PyObject * SuperSaw_add(SuperSaw *self, PyObject *arg) { ADD };
static PyObject * SuperSaw_inplace_add(SuperSaw *self, PyObject *arg) { INPLACE_ADD };
static PyObject * SuperSaw_sub(SuperSaw *self, PyObject *arg) { SUB };
static PyObject * SuperSaw_inplace_sub(SuperSaw *self, PyObject *arg) { INPLACE_SUB };
static PyObject * SuperSaw_div(SuperSaw *self, PyObject *arg) { DIV };
static PyObject * SuperSaw_inplace_div(SuperSaw *self, PyObject *arg) { INPLACE_DIV };

static PyObject * SuperSaw_setFreq(SuperSaw *self, PyObject *arg) { SET_PARAM(self->freq, self->freq_stream, 2); }
static PyObject * SuperSaw_setDetune(SuperSaw *self, PyObject *arg) { SET_PARAM(self->detune, self->detune_stream, 3); }
static PyObject * SuperSaw_setBal(SuperSaw *self, PyObject *arg) { SET_PARAM(self->bal, self->bal_stream, 4); }

static PyMemberDef SuperSaw_members[] =
{
    {"server", T_OBJECT_EX, offsetof(SuperSaw, server), 0, "Pyo server."},
    {"stream", T_OBJECT_EX, offsetof(SuperSaw, stream), 0, "Stream object."},
    {"freq", T_OBJECT_EX, offsetof(SuperSaw, freq), 0, "Frequency in cycle per second."},
    {"detune", T_OBJECT_EX, offsetof(SuperSaw, detune), 0, "Detune factor."},
    {"bal", T_OBJECT_EX, offsetof(SuperSaw, bal), 0, "Mix factor."},
    {"mul", T_OBJECT_EX, offsetof(SuperSaw, mul), 0, "Mul factor."},
    {"add", T_OBJECT_EX, offsetof(SuperSaw, add), 0, "Add factor."},
    {NULL}  /* Sentinel */
};

static PyMethodDef SuperSaw_methods[] =
{
    {"getServer", (PyCFunction)SuperSaw_getServer, METH_NOARGS, "Returns server object."},
    {"_getStream", (PyCFunction)SuperSaw_getStream, METH_NOARGS, "Returns stream object."},
    {"play", (PyCFunction)SuperSaw_play, METH_VARARGS | METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
    {"out", (PyCFunction)SuperSaw_out, METH_VARARGS | METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
    {"stop", (PyCFunction)SuperSaw_stop, METH_VARARGS | METH_KEYWORDS, "Stops computing."},
    {"setFreq", (PyCFunction)SuperSaw_setFreq, METH_O, "Sets oscillator frequency in cycle per second."},
    {"setDetune", (PyCFunction)SuperSaw_setDetune, METH_O, "Sets oscillator detune factor."},
    {"setBal", (PyCFunction)SuperSaw_setBal, METH_O, "Sets oscillator mix factor."},
    {"setMul", (PyCFunction)SuperSaw_setMul, METH_O, "Sets oscillator mul factor."},
    {"setAdd", (PyCFunction)SuperSaw_setAdd, METH_O, "Sets oscillator add factor."},
    {"setSub", (PyCFunction)SuperSaw_setSub, METH_O, "Sets oscillator inverse add factor."},
    {"setDiv", (PyCFunction)SuperSaw_setDiv, METH_O, "Sets inverse mul factor."},
    {NULL}  /* Sentinel */
};

static PyNumberMethods SuperSaw_as_number =
{
    (binaryfunc)SuperSaw_add,                      /*nb_add*/
    (binaryfunc)SuperSaw_sub,                 /*nb_subtract*/
    (binaryfunc)SuperSaw_multiply,                 /*nb_multiply*/
    0,                /*nb_remainder*/
    0,                   /*nb_divmod*/
    0,                   /*nb_power*/
    0,                  /*nb_neg*/
    0,                /*nb_pos*/
    0,                  /*(unaryfunc)array_abs,*/
    0,                    /*nb_nonzero*/
    0,                    /*nb_invert*/
    0,               /*nb_lshift*/
    0,              /*nb_rshift*/
    0,              /*nb_and*/
    0,              /*nb_xor*/
    0,               /*nb_or*/
    0,                       /*nb_int*/
    0,                      /*nb_long*/
    0,                     /*nb_float*/
    (binaryfunc)SuperSaw_inplace_add,              /*inplace_add*/
    (binaryfunc)SuperSaw_inplace_sub,         /*inplace_subtract*/
    (binaryfunc)SuperSaw_inplace_multiply,         /*inplace_multiply*/
    0,        /*inplace_remainder*/
    0,           /*inplace_power*/
    0,       /*inplace_lshift*/
    0,      /*inplace_rshift*/
    0,      /*inplace_and*/
    0,      /*inplace_xor*/
    0,       /*inplace_or*/
    0,             /*nb_floor_divide*/
    (binaryfunc)SuperSaw_div,                       /*nb_true_divide*/
    0,     /*nb_inplace_floor_divide*/
    (binaryfunc)SuperSaw_inplace_div,                       /*nb_inplace_true_divide*/
    0,                     /* nb_index */
};

PyTypeObject SuperSawType =
{
    PyVarObject_HEAD_INIT(NULL, 0)
    "_pyo.SuperSaw_base",         /*tp_name*/
    sizeof(SuperSaw),         /*tp_basicsize*/
    0,                         /*tp_itemsize*/
    (destructor)SuperSaw_dealloc, /*tp_dealloc*/
    0,                         /*tp_print*/
    0,                         /*tp_getattr*/
    0,                         /*tp_setattr*/
    0,                         /*tp_as_async (tp_compare in Python 2)*/
    0,                         /*tp_repr*/
    &SuperSaw_as_number,             /*tp_as_number*/
    0,                         /*tp_as_sequence*/
    0,                         /*tp_as_mapping*/
    0,                         /*tp_hash */
    0,                         /*tp_call*/
    0,                         /*tp_str*/
    0,                         /*tp_getattro*/
    0,                         /*tp_setattro*/
    0,                         /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
    "SuperSaw objects. detune incrementor from 0 to 1.",           /* tp_doc */
    (traverseproc)SuperSaw_traverse,   /* tp_traverse */
    (inquiry)SuperSaw_clear,           /* tp_clear */
    0,                     /* tp_richcompare */
    0,                     /* tp_weaklistoffset */
    0,                     /* tp_iter */
    0,                     /* tp_iternext */
    SuperSaw_methods,             /* tp_methods */
    SuperSaw_members,             /* tp_members */
    0,                      /* tp_getset */
    0,                         /* tp_base */
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    0,                         /* tp_dictoffset */
    0,      /* tp_init */
    0,                         /* tp_alloc */
    SuperSaw_new,                 /* tp_new */
};

/**************/
/* RCOsc object */
/**************/
typedef struct
{
    pyo_audio_HEAD
    PyObject *freq;
    Stream *freq_stream;
    PyObject *sharp;
    Stream *sharp_stream;
    int modebuffer[4];
    MYFLT pointerPos;
} RCOsc;

static void
RCOsc_readframes_ii(RCOsc *self)
{
    MYFLT fr, sh, inc, down_phase, up_phase;
    int i;

    fr = PyFloat_AS_DOUBLE(self->freq);
    sh = _clip(PyFloat_AS_DOUBLE(self->sharp));
    sh = sh * sh * 99.0 + 1.0;
    inc = fr * 2 / self->sr;

    for (i = 0; i < self->bufsize; i++)
    {
        if (self->pointerPos < 1)
        {
            down_phase = 1.0 - self->pointerPos;
            up_phase = 1.0;
        }
        else
        {
            down_phase = 0.0;
            up_phase = 2.0 - self->pointerPos;
        }

        self->data[i] = ( (1.0 - MYPOW(down_phase, sh)) + (MYPOW(up_phase, sh)) ) * 2.0 - 3.0;
        self->pointerPos += inc;

        if (self->pointerPos < 0)
            self->pointerPos += 2.0;
        else if (self->pointerPos >= 2)
            self->pointerPos -= 2.0;
    }
}

static void
RCOsc_readframes_ai(RCOsc *self)
{
    MYFLT sh, down_phase, up_phase, twoOverSr;
    int i;

    MYFLT *fr = Stream_getData((Stream *)self->freq_stream);
    sh = _clip(PyFloat_AS_DOUBLE(self->sharp));
    sh = sh * sh * 99.0 + 1.0;

    twoOverSr = 2.0 / self->sr;

    for (i = 0; i < self->bufsize; i++)
    {
        if (self->pointerPos < 1)
        {
            down_phase = 1.0 - self->pointerPos;
            up_phase = 1.0;
        }
        else
        {
            down_phase = 0.0;
            up_phase = 2.0 - self->pointerPos;
        }

        self->data[i] = ( (1.0 - MYPOW(down_phase, sh)) + (MYPOW(up_phase, sh)) ) * 2.0 - 3.0;
        self->pointerPos += fr[i] * twoOverSr;

        if (self->pointerPos < 0)
            self->pointerPos += 2.0;
        else if (self->pointerPos >= 2)
            self->pointerPos -= 2.0;
    }
}

static void
RCOsc_readframes_ia(RCOsc *self)
{
    MYFLT fr, sh, inc, down_phase, up_phase;
    int i;

    fr = PyFloat_AS_DOUBLE(self->freq);
    MYFLT *sharp = Stream_getData((Stream *)self->sharp_stream);
    inc = fr * 2 / self->sr;

    for (i = 0; i < self->bufsize; i++)
    {
        sh = _clip(sharp[i]);
        sh = sh * sh * 99.0 + 1.0;

        if (self->pointerPos < 1)
        {
            down_phase = 1.0 - self->pointerPos;
            up_phase = 1.0;
        }
        else
        {
            down_phase = 0.0;
            up_phase = 2.0 - self->pointerPos;
        }

        self->data[i] = ( (1.0 - MYPOW(down_phase, sh)) + (MYPOW(up_phase, sh)) ) * 2.0 - 3.0;
        self->pointerPos += inc;

        if (self->pointerPos < 0)
            self->pointerPos += 2.0;
        else if (self->pointerPos >= 2)
            self->pointerPos -= 2.0;
    }
}

static void
RCOsc_readframes_aa(RCOsc *self)
{
    MYFLT sh, down_phase, up_phase, twoOverSr;
    int i;

    MYFLT *fr = Stream_getData((Stream *)self->freq_stream);
    MYFLT *sharp = Stream_getData((Stream *)self->sharp_stream);

    twoOverSr = 2.0 / self->sr;

    for (i = 0; i < self->bufsize; i++)
    {
        sh = _clip(sharp[i]);
        sh = sh * sh * 99.0 + 1.0;

        if (self->pointerPos < 1)
        {
            down_phase = 1.0 - self->pointerPos;
            up_phase = 1.0;
        }
        else
        {
            down_phase = 0.0;
            up_phase = 2.0 - self->pointerPos;
        }

        self->data[i] = ( (1.0 - MYPOW(down_phase, sh)) + (MYPOW(up_phase, sh)) ) * 2.0 - 3.0;
        self->pointerPos += fr[i] * twoOverSr;

        if (self->pointerPos < 0)
            self->pointerPos += 2.0;
        else if (self->pointerPos >= 2)
            self->pointerPos -= 2.0;
    }
}

static void RCOsc_postprocessing_ii(RCOsc *self) { POST_PROCESSING_II };
static void RCOsc_postprocessing_ai(RCOsc *self) { POST_PROCESSING_AI };
static void RCOsc_postprocessing_ia(RCOsc *self) { POST_PROCESSING_IA };
static void RCOsc_postprocessing_aa(RCOsc *self) { POST_PROCESSING_AA };
static void RCOsc_postprocessing_ireva(RCOsc *self) { POST_PROCESSING_IREVA };
static void RCOsc_postprocessing_areva(RCOsc *self) { POST_PROCESSING_AREVA };
static void RCOsc_postprocessing_revai(RCOsc *self) { POST_PROCESSING_REVAI };
static void RCOsc_postprocessing_revaa(RCOsc *self) { POST_PROCESSING_REVAA };
static void RCOsc_postprocessing_revareva(RCOsc *self) { POST_PROCESSING_REVAREVA };

static void
RCOsc_setProcMode(RCOsc *self)
{
    int procmode, muladdmode;
    procmode = self->modebuffer[2] + self->modebuffer[3] * 10;
    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;

    switch (procmode)
    {
        case 0:
            self->proc_func_ptr = RCOsc_readframes_ii;
            break;

        case 1:
            self->proc_func_ptr = RCOsc_readframes_ai;
            break;

        case 10:
            self->proc_func_ptr = RCOsc_readframes_ia;
            break;

        case 11:
            self->proc_func_ptr = RCOsc_readframes_aa;
            break;
    }

    switch (muladdmode)
    {
        case 0:
            self->muladd_func_ptr = RCOsc_postprocessing_ii;
            break;

        case 1:
            self->muladd_func_ptr = RCOsc_postprocessing_ai;
            break;

        case 2:
            self->muladd_func_ptr = RCOsc_postprocessing_revai;
            break;

        case 10:
            self->muladd_func_ptr = RCOsc_postprocessing_ia;
            break;

        case 11:
            self->muladd_func_ptr = RCOsc_postprocessing_aa;
            break;

        case 12:
            self->muladd_func_ptr = RCOsc_postprocessing_revaa;
            break;

        case 20:
            self->muladd_func_ptr = RCOsc_postprocessing_ireva;
            break;

        case 21:
            self->muladd_func_ptr = RCOsc_postprocessing_areva;
            break;

        case 22:
            self->muladd_func_ptr = RCOsc_postprocessing_revareva;
            break;
    }
}

static void
RCOsc_compute_next_data_frame(RCOsc *self)
{
    (*self->proc_func_ptr)(self);
    (*self->muladd_func_ptr)(self);
}

static int
RCOsc_traverse(RCOsc *self, visitproc visit, void *arg)
{
    pyo_VISIT
    Py_VISIT(self->sharp);
    Py_VISIT(self->freq);
    return 0;
}

static int
RCOsc_clear(RCOsc *self)
{
    pyo_CLEAR
    Py_CLEAR(self->sharp);
    Py_CLEAR(self->freq);
    return 0;
}

static void
RCOsc_dealloc(RCOsc* self)
{
    pyo_DEALLOC
    RCOsc_clear(self);
    Py_TYPE(self->stream)->tp_free((PyObject*)self->stream);
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject *
RCOsc_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    int i;
    PyObject *freqtmp = NULL, *sharptmp = NULL, *multmp = NULL, *addtmp = NULL;
    RCOsc *self;
    self = (RCOsc *)type->tp_alloc(type, 0);

    self->freq = PyFloat_FromDouble(100);
    self->sharp = PyFloat_FromDouble(0.25);
    self->modebuffer[0] = 0;
    self->modebuffer[1] = 0;
    self->modebuffer[2] = 0;
    self->modebuffer[3] = 0;
    self->pointerPos = 0.;

    INIT_OBJECT_COMMON
    Stream_setFunctionPtr(self->stream, RCOsc_compute_next_data_frame);
    self->mode_func_ptr = RCOsc_setProcMode;

    static char *kwlist[] = {"freq", "sharp", "mul", "add", NULL};

    if (! PyArg_ParseTupleAndKeywords(args, kwds, "|OOOO", kwlist, &freqtmp, &sharptmp, &multmp, &addtmp))
        Py_RETURN_NONE;

    if (freqtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setFreq", "O", freqtmp);
    }

    if (sharptmp)
    {
        PyObject_CallMethod((PyObject *)self, "setSharp", "O", sharptmp);
    }

    if (multmp)
    {
        PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
    }

    if (addtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
    }

    PyObject_CallMethod(self->server, "addStream", "O", self->stream);

    (*self->mode_func_ptr)(self);

    return (PyObject *)self;
}

static PyObject * RCOsc_getServer(RCOsc* self) { GET_SERVER };
static PyObject * RCOsc_getStream(RCOsc* self) { GET_STREAM };
static PyObject * RCOsc_setMul(RCOsc *self, PyObject *arg) { SET_MUL };
static PyObject * RCOsc_setAdd(RCOsc *self, PyObject *arg) { SET_ADD };
static PyObject * RCOsc_setSub(RCOsc *self, PyObject *arg) { SET_SUB };
static PyObject * RCOsc_setDiv(RCOsc *self, PyObject *arg) { SET_DIV };

static PyObject * RCOsc_play(RCOsc *self, PyObject *args, PyObject *kwds) { PLAY };
static PyObject * RCOsc_out(RCOsc *self, PyObject *args, PyObject *kwds) { OUT };
static PyObject * RCOsc_stop(RCOsc *self, PyObject *args, PyObject *kwds) { STOP };

static PyObject * RCOsc_multiply(RCOsc *self, PyObject *arg) { MULTIPLY };
static PyObject * RCOsc_inplace_multiply(RCOsc *self, PyObject *arg) { INPLACE_MULTIPLY };
static PyObject * RCOsc_add(RCOsc *self, PyObject *arg) { ADD };
static PyObject * RCOsc_inplace_add(RCOsc *self, PyObject *arg) { INPLACE_ADD };
static PyObject * RCOsc_sub(RCOsc *self, PyObject *arg) { SUB };
static PyObject * RCOsc_inplace_sub(RCOsc *self, PyObject *arg) { INPLACE_SUB };
static PyObject * RCOsc_div(RCOsc *self, PyObject *arg) { DIV };
static PyObject * RCOsc_inplace_div(RCOsc *self, PyObject *arg) { INPLACE_DIV };

static PyObject * RCOsc_setFreq(RCOsc *self, PyObject *arg) { SET_PARAM(self->freq, self->freq_stream, 2); }
static PyObject * RCOsc_setSharp(RCOsc *self, PyObject *arg) { SET_PARAM(self->sharp, self->sharp_stream, 3); }

static PyObject *
RCOsc_reset(RCOsc *self)
{
    self->pointerPos = 0.0;
    Py_RETURN_NONE;
}

static PyMemberDef RCOsc_members[] =
{
    {"server", T_OBJECT_EX, offsetof(RCOsc, server), 0, "Pyo server."},
    {"stream", T_OBJECT_EX, offsetof(RCOsc, stream), 0, "Stream object."},
    {"freq", T_OBJECT_EX, offsetof(RCOsc, freq), 0, "Frequency in cycle per second."},
    {"sharp", T_OBJECT_EX, offsetof(RCOsc, sharp), 0, "RCOscillator sharp."},
    {"mul", T_OBJECT_EX, offsetof(RCOsc, mul), 0, "Mul factor."},
    {"add", T_OBJECT_EX, offsetof(RCOsc, add), 0, "Add factor."},
    {NULL}  /* Sentinel */
};

static PyMethodDef RCOsc_methods[] =
{
    {"getServer", (PyCFunction)RCOsc_getServer, METH_NOARGS, "Returns server object."},
    {"_getStream", (PyCFunction)RCOsc_getStream, METH_NOARGS, "Returns stream object."},
    {"play", (PyCFunction)RCOsc_play, METH_VARARGS | METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
    {"out", (PyCFunction)RCOsc_out, METH_VARARGS | METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
    {"stop", (PyCFunction)RCOsc_stop, METH_VARARGS | METH_KEYWORDS, "Stops computing."},
    {"setFreq", (PyCFunction)RCOsc_setFreq, METH_O, "Sets oscillator frequency in cycle per second."},
    {"setSharp", (PyCFunction)RCOsc_setSharp, METH_O, "Sets oscillator sharp."},
    {"reset", (PyCFunction)RCOsc_reset, METH_NOARGS, "Resets pointer position to 0."},
    {"setMul", (PyCFunction)RCOsc_setMul, METH_O, "Sets oscillator mul factor."},
    {"setAdd", (PyCFunction)RCOsc_setAdd, METH_O, "Sets oscillator add factor."},
    {"setSub", (PyCFunction)RCOsc_setSub, METH_O, "Sets oscillator inverse add factor."},
    {"setDiv", (PyCFunction)RCOsc_setDiv, METH_O, "Sets inverse mul factor."},
    {NULL}  /* Sentinel */
};

static PyNumberMethods RCOsc_as_number =
{
    (binaryfunc)RCOsc_add,                      /*nb_add*/
    (binaryfunc)RCOsc_sub,                 /*nb_subtract*/
    (binaryfunc)RCOsc_multiply,                 /*nb_multiply*/
    0,                /*nb_remainder*/
    0,                   /*nb_divmod*/
    0,                   /*nb_power*/
    0,                  /*nb_neg*/
    0,                /*nb_pos*/
    0,                  /*(unaryfunc)array_abs,*/
    0,                    /*nb_nonzero*/
    0,                    /*nb_invert*/
    0,               /*nb_lshift*/
    0,              /*nb_rshift*/
    0,              /*nb_and*/
    0,              /*nb_xor*/
    0,               /*nb_or*/
    0,                       /*nb_int*/
    0,                      /*nb_long*/
    0,                     /*nb_float*/
    (binaryfunc)RCOsc_inplace_add,              /*inplace_add*/
    (binaryfunc)RCOsc_inplace_sub,         /*inplace_subtract*/
    (binaryfunc)RCOsc_inplace_multiply,         /*inplace_multiply*/
    0,        /*inplace_remainder*/
    0,           /*inplace_power*/
    0,       /*inplace_lshift*/
    0,      /*inplace_rshift*/
    0,      /*inplace_and*/
    0,      /*inplace_xor*/
    0,       /*inplace_or*/
    0,             /*nb_floor_divide*/
    (binaryfunc)RCOsc_div,                       /*nb_true_divide*/
    0,     /*nb_inplace_floor_divide*/
    (binaryfunc)RCOsc_inplace_div,                       /*nb_inplace_true_divide*/
    0,                     /* nb_index */
};

PyTypeObject RCOscType =
{
    PyVarObject_HEAD_INIT(NULL, 0)
    "_pyo.RCOsc_base",         /*tp_name*/
    sizeof(RCOsc),         /*tp_basicsize*/
    0,                         /*tp_itemsize*/
    (destructor)RCOsc_dealloc, /*tp_dealloc*/
    0,                         /*tp_print*/
    0,                         /*tp_getattr*/
    0,                         /*tp_setattr*/
    0,                         /*tp_as_async (tp_compare in Python 2)*/
    0,                         /*tp_repr*/
    &RCOsc_as_number,             /*tp_as_number*/
    0,                         /*tp_as_sequence*/
    0,                         /*tp_as_mapping*/
    0,                         /*tp_hash */
    0,                         /*tp_call*/
    0,                         /*tp_str*/
    0,                         /*tp_getattro*/
    0,                         /*tp_setattro*/
    0,                         /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
    "RCOsc objects. Waveform simulation of of a RC circuit.",           /* tp_doc */
    (traverseproc)RCOsc_traverse,   /* tp_traverse */
    (inquiry)RCOsc_clear,           /* tp_clear */
    0,                     /* tp_richcompare */
    0,                     /* tp_weaklistoffset */
    0,                     /* tp_iter */
    0,                     /* tp_iternext */
    RCOsc_methods,             /* tp_methods */
    RCOsc_members,             /* tp_members */
    0,                      /* tp_getset */
    0,                         /* tp_base */
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    0,                         /* tp_dictoffset */
    0,      /* tp_init */
    0,                         /* tp_alloc */
    RCOsc_new,                 /* tp_new */
};

/**************/
/* TableScale object */
/**************/
typedef struct
{
    pyo_audio_HEAD
    PyObject *table;
    PyObject *outtable;
    int modebuffer[2];
} TableScale;

static void
TableScale_readframes_ii(TableScale *self)
{
    T_SIZE_T i, num;
    MYFLT mul, add;
    MYFLT *tablelist = TableStream_getData((TableStream *)self->table);
    T_SIZE_T size = TableStream_getSize((TableStream *)self->table);
    MYFLT *outlist = TableStream_getData((TableStream *)self->outtable);
    T_SIZE_T osize = TableStream_getSize((TableStream *)self->outtable);

    mul = PyFloat_AS_DOUBLE(self->mul);
    add = PyFloat_AS_DOUBLE(self->add);

    num = size < osize ? size : osize;

    for (i = 0; i < num; i++)
    {
        outlist[i] = tablelist[i] * mul + add;
    }
}

static void
TableScale_readframes_ai(TableScale *self)
{
    T_SIZE_T i, num;
    MYFLT add;
    MYFLT *tablelist = TableStream_getData((TableStream *)self->table);
    T_SIZE_T size = TableStream_getSize((TableStream *)self->table);
    MYFLT *outlist = TableStream_getData((TableStream *)self->outtable);
    T_SIZE_T osize = TableStream_getSize((TableStream *)self->outtable);

    MYFLT *mul = Stream_getData((Stream *)self->mul_stream);
    add = PyFloat_AS_DOUBLE(self->add);

    num = size < osize ? size : osize;

    for (i = 0; i < num; i++)
    {
        outlist[i] = tablelist[i] * mul[i] + add;
    }
}

static void
TableScale_readframes_ia(TableScale *self)
{
    T_SIZE_T i, num;
    MYFLT mul;
    MYFLT *tablelist = TableStream_getData((TableStream *)self->table);
    T_SIZE_T size = TableStream_getSize((TableStream *)self->table);
    MYFLT *outlist = TableStream_getData((TableStream *)self->outtable);
    T_SIZE_T osize = TableStream_getSize((TableStream *)self->outtable);

    mul = PyFloat_AS_DOUBLE(self->mul);
    MYFLT *add = Stream_getData((Stream *)self->add_stream);

    num = size < osize ? size : osize;

    for (i = 0; i < num; i++)
    {
        outlist[i] = tablelist[i] * mul + add[i];
    }
}

static void
TableScale_readframes_aa(TableScale *self)
{
    T_SIZE_T i, num;
    MYFLT *tablelist = TableStream_getData((TableStream *)self->table);
    T_SIZE_T size = TableStream_getSize((TableStream *)self->table);
    MYFLT *outlist = TableStream_getData((TableStream *)self->outtable);
    T_SIZE_T osize = TableStream_getSize((TableStream *)self->outtable);

    MYFLT *mul = Stream_getData((Stream *)self->mul_stream);
    MYFLT *add = Stream_getData((Stream *)self->add_stream);

    num = size < osize ? size : osize;

    for (i = 0; i < num; i++)
    {
        outlist[i] = tablelist[i] * mul[i] + add[i];
    }
}

static void
TableScale_setProcMode(TableScale *self)
{
    int muladdmode;
    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;

    switch (muladdmode)
    {
        case 0:
            self->proc_func_ptr = TableScale_readframes_ii;
            break;

        case 1:
            self->proc_func_ptr = TableScale_readframes_ai;
            break;

        case 10:
            self->proc_func_ptr = TableScale_readframes_ia;
            break;

        case 11:
            self->proc_func_ptr = TableScale_readframes_aa;
            break;
    }
}

static void
TableScale_compute_next_data_frame(TableScale *self)
{
    (*self->proc_func_ptr)(self);
}

static int
TableScale_traverse(TableScale *self, visitproc visit, void *arg)
{
    pyo_VISIT
    return 0;
}

static int
TableScale_clear(TableScale *self)
{
    pyo_CLEAR
    return 0;
}

static void
TableScale_dealloc(TableScale* self)
{
    pyo_DEALLOC
    TableScale_clear(self);
    Py_TYPE(self->stream)->tp_free((PyObject*)self->stream);
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject *
TableScale_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    int i;
    PyObject *tabletmp, *outtabletmp, *multmp = NULL, *addtmp = NULL;
    TableScale *self;
    self = (TableScale *)type->tp_alloc(type, 0);

    self->modebuffer[0] = 0;
    self->modebuffer[1] = 0;

    INIT_OBJECT_COMMON
    Stream_setFunctionPtr(self->stream, TableScale_compute_next_data_frame);
    self->mode_func_ptr = TableScale_setProcMode;

    static char *kwlist[] = {"table", "outtable", "mul", "add", NULL};

    if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO", kwlist, &tabletmp, &outtabletmp, &multmp, &addtmp))
        Py_RETURN_NONE;

    if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 )
    {
        PyErr_SetString(PyExc_TypeError, "\"table\" argument of TableScale must be a PyoTableObject.\n");
        Py_RETURN_NONE;
    }

    self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");

    if ( PyObject_HasAttrString((PyObject *)outtabletmp, "getTableStream") == 0 )
    {
        PyErr_SetString(PyExc_TypeError, "\"outtable\" argument of TableScale must be a PyoTableObject.\n");
        Py_RETURN_NONE;
    }

    self->outtable = PyObject_CallMethod((PyObject *)outtabletmp, "getTableStream", "");

    if (multmp)
    {
        PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
    }

    if (addtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
    }

    PyObject_CallMethod(self->server, "addStream", "O", self->stream);

    (*self->mode_func_ptr)(self);

    return (PyObject *)self;
}

static PyObject * TableScale_getServer(TableScale* self) { GET_SERVER };
static PyObject * TableScale_getStream(TableScale* self) { GET_STREAM };
static PyObject * TableScale_setMul(TableScale *self, PyObject *arg) { SET_MUL };
static PyObject * TableScale_setAdd(TableScale *self, PyObject *arg) { SET_ADD };
static PyObject * TableScale_setSub(TableScale *self, PyObject *arg) { SET_SUB };
static PyObject * TableScale_setDiv(TableScale *self, PyObject *arg) { SET_DIV };

static PyObject * TableScale_play(TableScale *self, PyObject *args, PyObject *kwds) { PLAY };
static PyObject * TableScale_out(TableScale *self, PyObject *args, PyObject *kwds) { OUT };
static PyObject * TableScale_stop(TableScale *self, PyObject *args, PyObject *kwds) { STOP };

static PyObject * TableScale_multiply(TableScale *self, PyObject *arg) { MULTIPLY };
static PyObject * TableScale_inplace_multiply(TableScale *self, PyObject *arg) { INPLACE_MULTIPLY };
static PyObject * TableScale_add(TableScale *self, PyObject *arg) { ADD };
static PyObject * TableScale_inplace_add(TableScale *self, PyObject *arg) { INPLACE_ADD };
static PyObject * TableScale_sub(TableScale *self, PyObject *arg) { SUB };
static PyObject * TableScale_inplace_sub(TableScale *self, PyObject *arg) { INPLACE_SUB };
static PyObject * TableScale_div(TableScale *self, PyObject *arg) { DIV };
static PyObject * TableScale_inplace_div(TableScale *self, PyObject *arg) { INPLACE_DIV };

static PyObject *
TableScale_getTable(TableScale* self)
{
    Py_INCREF(self->table);
    return self->table;
};

static PyObject *
TableScale_setTable(TableScale *self, PyObject *arg)
{
    ASSERT_ARG_NOT_NULL

    Py_DECREF(self->table);
    self->table = PyObject_CallMethod((PyObject *)arg, "getTableStream", "");

    Py_RETURN_NONE;
}

static PyObject *
TableScale_getOuttable(TableScale* self)
{
    Py_INCREF(self->outtable);
    return self->outtable;
};

static PyObject *
TableScale_setOuttable(TableScale *self, PyObject *arg)
{
    ASSERT_ARG_NOT_NULL

    Py_DECREF(self->outtable);
    self->outtable = PyObject_CallMethod((PyObject *)arg, "getTableStream", "");

    Py_RETURN_NONE;
}

static PyMemberDef TableScale_members[] =
{
    {"server", T_OBJECT_EX, offsetof(TableScale, server), 0, "Pyo server."},
    {"stream", T_OBJECT_EX, offsetof(TableScale, stream), 0, "Stream object."},
    {"table", T_OBJECT_EX, offsetof(TableScale, table), 0, "Waveform table."},
    {"outtable", T_OBJECT_EX, offsetof(TableScale, outtable), 0, "Output table."},
    {"mul", T_OBJECT_EX, offsetof(TableScale, mul), 0, "Mul factor."},
    {"add", T_OBJECT_EX, offsetof(TableScale, add), 0, "Add factor."},
    {NULL}  /* Sentinel */
};

static PyMethodDef TableScale_methods[] =
{
    {"getTable", (PyCFunction)TableScale_getTable, METH_NOARGS, "Returns waveform table object."},
    {"getOuttable", (PyCFunction)TableScale_getOuttable, METH_NOARGS, "Returns output table object."},
    {"getServer", (PyCFunction)TableScale_getServer, METH_NOARGS, "Returns server object."},
    {"_getStream", (PyCFunction)TableScale_getStream, METH_NOARGS, "Returns stream object."},
    {"play", (PyCFunction)TableScale_play, METH_VARARGS | METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
    {"out", (PyCFunction)TableScale_out, METH_VARARGS | METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
    {"stop", (PyCFunction)TableScale_stop, METH_VARARGS | METH_KEYWORDS, "Stops computing."},
    {"setTable", (PyCFunction)TableScale_setTable, METH_O, "Sets oscillator table."},
    {"setOuttable", (PyCFunction)TableScale_setOuttable, METH_O, "Sets output table."},
    {"setMul", (PyCFunction)TableScale_setMul, METH_O, "Sets oscillator mul factor."},
    {"setAdd", (PyCFunction)TableScale_setAdd, METH_O, "Sets oscillator add factor."},
    {"setSub", (PyCFunction)TableScale_setSub, METH_O, "Sets oscillator inverse add factor."},
    {"setDiv", (PyCFunction)TableScale_setDiv, METH_O, "Sets inverse mul factor."},
    {NULL}  /* Sentinel */
};

static PyNumberMethods TableScale_as_number =
{
    (binaryfunc)TableScale_add,                      /*nb_add*/
    (binaryfunc)TableScale_sub,                 /*nb_subtract*/
    (binaryfunc)TableScale_multiply,                 /*nb_multiply*/
    0,                /*nb_remainder*/
    0,                   /*nb_divmod*/
    0,                   /*nb_power*/
    0,                  /*nb_neg*/
    0,                /*nb_pos*/
    0,                  /*(unaryfunc)array_abs,*/
    0,                    /*nb_nonzero*/
    0,                    /*nb_invert*/
    0,               /*nb_lshift*/
    0,              /*nb_rshift*/
    0,              /*nb_and*/
    0,              /*nb_xor*/
    0,               /*nb_or*/
    0,                       /*nb_int*/
    0,                      /*nb_long*/
    0,                     /*nb_float*/
    (binaryfunc)TableScale_inplace_add,              /*inplace_add*/
    (binaryfunc)TableScale_inplace_sub,         /*inplace_subtract*/
    (binaryfunc)TableScale_inplace_multiply,         /*inplace_multiply*/
    0,        /*inplace_remainder*/
    0,           /*inplace_power*/
    0,       /*inplace_lshift*/
    0,      /*inplace_rshift*/
    0,      /*inplace_and*/
    0,      /*inplace_xor*/
    0,       /*inplace_or*/
    0,             /*nb_floor_divide*/
    (binaryfunc)TableScale_div,                       /*nb_true_divide*/
    0,     /*nb_inplace_floor_divide*/
    (binaryfunc)TableScale_inplace_div,                       /*nb_inplace_true_divide*/
    0,                     /* nb_index */
};

PyTypeObject TableScaleType =
{
    PyVarObject_HEAD_INIT(NULL, 0)
    "_pyo.TableScale_base",         /*tp_name*/
    sizeof(TableScale),         /*tp_basicsize*/
    0,                         /*tp_itemsize*/
    (destructor)TableScale_dealloc, /*tp_dealloc*/
    0,                         /*tp_print*/
    0,                         /*tp_getattr*/
    0,                         /*tp_setattr*/
    0,                         /*tp_as_async (tp_compare in Python 2)*/
    0,                         /*tp_repr*/
    &TableScale_as_number,             /*tp_as_number*/
    0,                         /*tp_as_sequence*/
    0,                         /*tp_as_mapping*/
    0,                         /*tp_hash */
    0,                         /*tp_call*/
    0,                         /*tp_str*/
    0,                         /*tp_getattro*/
    0,                         /*tp_setattro*/
    0,                         /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
    "TableScale objects. Scale a PyoTable and save the result in another table.",           /* tp_doc */
    (traverseproc)TableScale_traverse,   /* tp_traverse */
    (inquiry)TableScale_clear,           /* tp_clear */
    0,                     /* tp_richcompare */
    0,                     /* tp_weaklistoffset */
    0,                     /* tp_iter */
    0,                     /* tp_iternext */
    TableScale_methods,             /* tp_methods */
    TableScale_members,             /* tp_members */
    0,                      /* tp_getset */
    0,                         /* tp_base */
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    0,                         /* tp_dictoffset */
    0,      /* tp_init */
    0,                         /* tp_alloc */
    TableScale_new,                 /* tp_new */
};

/******************************/
/* TableFill object definition */
/******************************/
typedef struct
{
    pyo_audio_HEAD
    PyObject *input;
    Stream *input_stream;
    PyObject *table;
    T_SIZE_T pointer;
} TableFill;

static void
TableFill_compute_next_data_frame(TableFill *self)
{
    int i;
    T_SIZE_T size = TableStream_getSize((TableStream *)self->table);
    MYFLT *tablelist = TableStream_getData((TableStream *)self->table);
    MYFLT *in = Stream_getData((Stream *)self->input_stream);

    for (i = 0; i < self->bufsize; i++)
    {
        tablelist[self->pointer++] = in[i];

        if (self->pointer >= size)
            self->pointer = 0;
    }
}

static int
TableFill_traverse(TableFill *self, visitproc visit, void *arg)
{
    pyo_VISIT
    Py_VISIT(self->input);
    return 0;
}

static int
TableFill_clear(TableFill *self)
{
    pyo_CLEAR
    Py_CLEAR(self->input);
    return 0;
}

static void
TableFill_dealloc(TableFill* self)
{
    pyo_DEALLOC
    TableFill_clear(self);
    Py_TYPE(self->stream)->tp_free((PyObject*)self->stream);
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject *
TableFill_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    int i;
    PyObject *inputtmp, *input_streamtmp, *tabletmp;
    TableFill *self;
    self = (TableFill *)type->tp_alloc(type, 0);

    self->pointer = 0;

    INIT_OBJECT_COMMON

    Stream_setFunctionPtr(self->stream, TableFill_compute_next_data_frame);

    static char *kwlist[] = {"input", "table", NULL};

    if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &inputtmp, &tabletmp))
        Py_RETURN_NONE;

    INIT_INPUT_STREAM

    if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 )
    {
        PyErr_SetString(PyExc_TypeError, "\"table\" argument of TableFill must be a PyoTableObject.\n");
        Py_RETURN_NONE;
    }

    self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");

    PyObject_CallMethod(self->server, "addStream", "O", self->stream);

    return (PyObject *)self;
}

static PyObject * TableFill_getServer(TableFill* self) { GET_SERVER };
static PyObject * TableFill_getStream(TableFill* self) { GET_STREAM };

static PyObject * TableFill_play(TableFill *self, PyObject *args, PyObject *kwds)
{
    self->pointer = 0;
    PLAY
};

static PyObject * TableFill_stop(TableFill *self, PyObject *args, PyObject *kwds) { STOP };

static PyObject *
TableFill_setTable(TableFill *self, PyObject *arg)
{
    ASSERT_ARG_NOT_NULL

    Py_DECREF(self->table);
    self->table = PyObject_CallMethod((PyObject *)arg, "getTableStream", "");
    Py_INCREF(self->table);

    Py_RETURN_NONE;
}

static PyObject * TableFill_getCurrentPos(TableFill *self)
{
    return PyLong_FromLong(self->pointer);
};

static PyMemberDef TableFill_members[] =
{
    {"server", T_OBJECT_EX, offsetof(TableFill, server), 0, "Pyo server."},
    {"stream", T_OBJECT_EX, offsetof(TableFill, stream), 0, "Stream object."},
    {"input", T_OBJECT_EX, offsetof(TableFill, input), 0, "Input sound object."},
    {"table", T_OBJECT_EX, offsetof(TableFill, table), 0, "Table to record in."},
    {NULL}  /* Sentinel */
};

static PyMethodDef TableFill_methods[] =
{
    {"getServer", (PyCFunction)TableFill_getServer, METH_NOARGS, "Returns server object."},
    {"_getStream", (PyCFunction)TableFill_getStream, METH_NOARGS, "Returns stream object."},
    {"setTable", (PyCFunction)TableFill_setTable, METH_O, "Sets a new table to fill."},
    {"play", (PyCFunction)TableFill_play, METH_VARARGS | METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
    {"stop", (PyCFunction)TableFill_stop, METH_VARARGS | METH_KEYWORDS, "Stops computing."},
    {"getCurrentPos", (PyCFunction)TableFill_getCurrentPos, METH_NOARGS, "Returns the current position."},
    {NULL}  /* Sentinel */
};

PyTypeObject TableFillType =
{
    PyVarObject_HEAD_INIT(NULL, 0)
    "_pyo.TableFill_base",         /*tp_name*/
    sizeof(TableFill),         /*tp_basicsize*/
    0,                         /*tp_itemsize*/
    (destructor)TableFill_dealloc, /*tp_dealloc*/
    0,                         /*tp_print*/
    0,                         /*tp_getattr*/
    0,                         /*tp_setattr*/
    0,                         /*tp_as_async (tp_compare in Python 2)*/
    0,                         /*tp_repr*/
    0,             /*tp_as_number*/
    0,                         /*tp_as_sequence*/
    0,                         /*tp_as_mapping*/
    0,                         /*tp_hash */
    0,                         /*tp_call*/
    0,                         /*tp_str*/
    0,                         /*tp_getattro*/
    0,                         /*tp_setattro*/
    0,                         /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
    "TableFill objects. Fill a table object with values in input.",           /* tp_doc */
    (traverseproc)TableFill_traverse,   /* tp_traverse */
    (inquiry)TableFill_clear,           /* tp_clear */
    0,                     /* tp_richcompare */
    0,                     /* tp_weaklistoffset */
    0,                     /* tp_iter */
    0,                     /* tp_iternext */
    TableFill_methods,             /* tp_methods */
    TableFill_members,             /* tp_members */
    0,                      /* tp_getset */
    0,                         /* tp_base */
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    0,                         /* tp_dictoffset */
    0,      /* tp_init */
    0,                         /* tp_alloc */
    TableFill_new,                 /* tp_new */
};

/**************/
/* TableScan object */
/**************/
typedef struct
{
    pyo_audio_HEAD
    PyObject *table;
    int modebuffer[2];
    T_SIZE_T pointerPos;
} TableScan;

static void
TableScan_readframes(TableScan *self)
{
    int i;
    MYFLT *tablelist = TableStream_getData((TableStream *)self->table);
    T_SIZE_T size = TableStream_getSize((TableStream *)self->table);

    for (i = 0; i < self->bufsize; i++)
    {
        self->data[i] = tablelist[self->pointerPos++];

        if (self->pointerPos >= size)
            self->pointerPos = 0;
    }
}

static void TableScan_postprocessing_ii(TableScan *self) { POST_PROCESSING_II };
static void TableScan_postprocessing_ai(TableScan *self) { POST_PROCESSING_AI };
static void TableScan_postprocessing_ia(TableScan *self) { POST_PROCESSING_IA };
static void TableScan_postprocessing_aa(TableScan *self) { POST_PROCESSING_AA };
static void TableScan_postprocessing_ireva(TableScan *self) { POST_PROCESSING_IREVA };
static void TableScan_postprocessing_areva(TableScan *self) { POST_PROCESSING_AREVA };
static void TableScan_postprocessing_revai(TableScan *self) { POST_PROCESSING_REVAI };
static void TableScan_postprocessing_revaa(TableScan *self) { POST_PROCESSING_REVAA };
static void TableScan_postprocessing_revareva(TableScan *self) { POST_PROCESSING_REVAREVA };

static void
TableScan_setProcMode(TableScan *self)
{
    int muladdmode;
    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;

    self->proc_func_ptr = TableScan_readframes;

    switch (muladdmode)
    {
        case 0:
            self->muladd_func_ptr = TableScan_postprocessing_ii;
            break;

        case 1:
            self->muladd_func_ptr = TableScan_postprocessing_ai;
            break;

        case 2:
            self->muladd_func_ptr = TableScan_postprocessing_revai;
            break;

        case 10:
            self->muladd_func_ptr = TableScan_postprocessing_ia;
            break;

        case 11:
            self->muladd_func_ptr = TableScan_postprocessing_aa;
            break;

        case 12:
            self->muladd_func_ptr = TableScan_postprocessing_revaa;
            break;

        case 20:
            self->muladd_func_ptr = TableScan_postprocessing_ireva;
            break;

        case 21:
            self->muladd_func_ptr = TableScan_postprocessing_areva;
            break;

        case 22:
            self->muladd_func_ptr = TableScan_postprocessing_revareva;
            break;
    }
}

static void
TableScan_compute_next_data_frame(TableScan *self)
{
    (*self->proc_func_ptr)(self);
    (*self->muladd_func_ptr)(self);
}

static int
TableScan_traverse(TableScan *self, visitproc visit, void *arg)
{
    pyo_VISIT
    return 0;
}

static int
TableScan_clear(TableScan *self)
{
    pyo_CLEAR
    return 0;
}

static void
TableScan_dealloc(TableScan* self)
{
    pyo_DEALLOC
    TableScan_clear(self);
    Py_TYPE(self->stream)->tp_free((PyObject*)self->stream);
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject *
TableScan_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    int i;
    PyObject *tabletmp, *multmp = NULL, *addtmp = NULL;
    TableScan *self;
    self = (TableScan *)type->tp_alloc(type, 0);

    self->modebuffer[0] = 0;
    self->modebuffer[1] = 0;
    self->pointerPos = 0;

    INIT_OBJECT_COMMON
    Stream_setFunctionPtr(self->stream, TableScan_compute_next_data_frame);
    self->mode_func_ptr = TableScan_setProcMode;

    static char *kwlist[] = {"table", "mul", "add", NULL};

    if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|OO", kwlist, &tabletmp, &multmp, &addtmp))
        Py_RETURN_NONE;

    if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 )
    {
        PyErr_SetString(PyExc_TypeError, "\"table\" argument of TableScan must be a PyoTableObject.\n");
        Py_RETURN_NONE;
    }

    self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");

    if (multmp)
    {
        PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
    }

    if (addtmp)
    {
        PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
    }

    PyObject_CallMethod(self->server, "addStream", "O", self->stream);

    (*self->mode_func_ptr)(self);

    return (PyObject *)self;
}

static PyObject * TableScan_getServer(TableScan* self) { GET_SERVER };
static PyObject * TableScan_getStream(TableScan* self) { GET_STREAM };
static PyObject * TableScan_setMul(TableScan *self, PyObject *arg) { SET_MUL };
static PyObject * TableScan_setAdd(TableScan *self, PyObject *arg) { SET_ADD };
static PyObject * TableScan_setSub(TableScan *self, PyObject *arg) { SET_SUB };
static PyObject * TableScan_setDiv(TableScan *self, PyObject *arg) { SET_DIV };

static PyObject * TableScan_play(TableScan *self, PyObject *args, PyObject *kwds)
{
    self->pointerPos = 0;
    PLAY
};

static PyObject * TableScan_out(TableScan *self, PyObject *args, PyObject *kwds)
{
    self->pointerPos = 0;
    OUT
};
static PyObject * TableScan_stop(TableScan *self, PyObject *args, PyObject *kwds) { STOP };

static PyObject * TableScan_multiply(TableScan *self, PyObject *arg) { MULTIPLY };
static PyObject * TableScan_inplace_multiply(TableScan *self, PyObject *arg) { INPLACE_MULTIPLY };
static PyObject * TableScan_add(TableScan *self, PyObject *arg) { ADD };
static PyObject * TableScan_inplace_add(TableScan *self, PyObject *arg) { INPLACE_ADD };
static PyObject * TableScan_sub(TableScan *self, PyObject *arg) { SUB };
static PyObject * TableScan_inplace_sub(TableScan *self, PyObject *arg) { INPLACE_SUB };
static PyObject * TableScan_div(TableScan *self, PyObject *arg) { DIV };
static PyObject * TableScan_inplace_div(TableScan *self, PyObject *arg) { INPLACE_DIV };

static PyObject *
TableScan_getTable(TableScan* self)
{
    Py_INCREF(self->table);
    return self->table;
};

static PyObject *
TableScan_setTable(TableScan *self, PyObject *arg)
{
    ASSERT_ARG_NOT_NULL

    Py_DECREF(self->table);
    self->table = PyObject_CallMethod((PyObject *)arg, "getTableStream", "");

    Py_RETURN_NONE;
}

static PyObject *
TableScan_reset(TableScan *self)
{
    self->pointerPos = 0;
    Py_RETURN_NONE;
}

static PyMemberDef TableScan_members[] =
{
    {"server", T_OBJECT_EX, offsetof(TableScan, server), 0, "Pyo server."},
    {"stream", T_OBJECT_EX, offsetof(TableScan, stream), 0, "Stream object."},
    {"table", T_OBJECT_EX, offsetof(TableScan, table), 0, "Waveform table."},
    {"mul", T_OBJECT_EX, offsetof(TableScan, mul), 0, "Mul factor."},
    {"add", T_OBJECT_EX, offsetof(TableScan, add), 0, "Add factor."},
    {NULL}  /* Sentinel */
};

static PyMethodDef TableScan_methods[] =
{
    {"getTable", (PyCFunction)TableScan_getTable, METH_NOARGS, "Returns waveform table object."},
    {"getServer", (PyCFunction)TableScan_getServer, METH_NOARGS, "Returns server object."},
    {"_getStream", (PyCFunction)TableScan_getStream, METH_NOARGS, "Returns stream object."},
    {"play", (PyCFunction)TableScan_play, METH_VARARGS | METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
    {"out", (PyCFunction)TableScan_out, METH_VARARGS | METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
    {"stop", (PyCFunction)TableScan_stop, METH_VARARGS | METH_KEYWORDS, "Stops computing."},
    {"setTable", (PyCFunction)TableScan_setTable, METH_O, "Sets oscillator table."},
    {"reset", (PyCFunction)TableScan_reset, METH_NOARGS, "Resets pointer position to 0."},
    {"setMul", (PyCFunction)TableScan_setMul, METH_O, "Sets oscillator mul factor."},
    {"setAdd", (PyCFunction)TableScan_setAdd, METH_O, "Sets oscillator add factor."},
    {"setSub", (PyCFunction)TableScan_setSub, METH_O, "Sets oscillator inverse add factor."},
    {"setDiv", (PyCFunction)TableScan_setDiv, METH_O, "Sets inverse mul factor."},
    {NULL}  /* Sentinel */
};

static PyNumberMethods TableScan_as_number =
{
    (binaryfunc)TableScan_add,                      /*nb_add*/
    (binaryfunc)TableScan_sub,                 /*nb_subtract*/
    (binaryfunc)TableScan_multiply,                 /*nb_multiply*/
    0,                /*nb_remainder*/
    0,                   /*nb_divmod*/
    0,                   /*nb_power*/
    0,                  /*nb_neg*/
    0,                /*nb_pos*/
    0,                  /*(unaryfunc)array_abs,*/
    0,                    /*nb_nonzero*/
    0,                    /*nb_invert*/
    0,               /*nb_lshift*/
    0,              /*nb_rshift*/
    0,              /*nb_and*/
    0,              /*nb_xor*/
    0,               /*nb_or*/
    0,                       /*nb_int*/
    0,                      /*nb_long*/
    0,                     /*nb_float*/
    (binaryfunc)TableScan_inplace_add,              /*inplace_add*/
    (binaryfunc)TableScan_inplace_sub,         /*inplace_subtract*/
    (binaryfunc)TableScan_inplace_multiply,         /*inplace_multiply*/
    0,        /*inplace_remainder*/
    0,           /*inplace_power*/
    0,       /*inplace_lshift*/
    0,      /*inplace_rshift*/
    0,      /*inplace_and*/
    0,      /*inplace_xor*/
    0,       /*inplace_or*/
    0,             /*nb_floor_divide*/
    (binaryfunc)TableScan_div,                       /*nb_true_divide*/
    0,     /*nb_inplace_floor_divide*/
    (binaryfunc)TableScan_inplace_div,                       /*nb_inplace_true_divide*/
    0,                     /* nb_index */
};

PyTypeObject TableScanType =
{
    PyVarObject_HEAD_INIT(NULL, 0)
    "_pyo.TableScan_base",         /*tp_name*/
    sizeof(TableScan),         /*tp_basicsize*/
    0,                         /*tp_itemsize*/
    (destructor)TableScan_dealloc, /*tp_dealloc*/
    0,                         /*tp_print*/
    0,                         /*tp_getattr*/
    0,                         /*tp_setattr*/
    0,                         /*tp_as_async (tp_compare in Python 2)*/
    0,                         /*tp_repr*/
    &TableScan_as_number,             /*tp_as_number*/
    0,                         /*tp_as_sequence*/
    0,                         /*tp_as_mapping*/
    0,                         /*tp_hash */
    0,                         /*tp_call*/
    0,                         /*tp_str*/
    0,                         /*tp_getattro*/
    0,                         /*tp_setattro*/
    0,                         /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
    "TableScan objects. Scan the content of a table in loop.",           /* tp_doc */
    (traverseproc)TableScan_traverse,   /* tp_traverse */
    (inquiry)TableScan_clear,           /* tp_clear */
    0,                     /* tp_richcompare */
    0,                     /* tp_weaklistoffset */
    0,                     /* tp_iter */
    0,                     /* tp_iternext */
    TableScan_methods,             /* tp_methods */
    TableScan_members,             /* tp_members */
    0,                      /* tp_getset */
    0,                         /* tp_base */
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    0,                         /* tp_dictoffset */
    0,      /* tp_init */
    0,                         /* tp_alloc */
    TableScan_new,                 /* tp_new */
};
