--- /dev/null
+
+/*
+ * maximilian.cpp
+ * platform independent synthesis library using portaudio or rtaudio
+ *
+ * Created by Mick Grierson on 29/12/2009.
+ * Copyright 2009 Mick Grierson & Strangeloop Limited. All rights reserved.
+ * Thanks to the Goldsmiths Creative Computing Team.
+ * Special thanks to Arturo Castro for the PortAudio implementation.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "maximilian.h"
+#include "math.h"
+
+/* Maximilian can be configured to load ogg vorbis format files using the
+* loadOgg() method.
+* Uncomment the following to include Sean Barrett's Ogg Vorbis decoder.
+* If you're on windows, make sure to add the files std_vorbis.c and std_vorbis.h to your project*/
+
+//#define VORBIS
+
+#ifdef VORBIS
+extern "C" {
+ #include "stb_vorbis.h"
+}
+#endif
+
+//This used to be important for dealing with multichannel playback
+float chandiv= 1;
+
+int maxiSettings::sampleRate = 44100;
+int maxiSettings::channels = 2;
+int maxiSettings::bufferSize = 1024;
+
+
+//this is a 514-point sinewave table that has many uses.
+double sineBuffer[514]={0,0.012268,0.024536,0.036804,0.049042,0.06131,0.073547,0.085785,0.097992,0.1102,0.12241,0.13455,0.1467,0.15884,0.17093,0.18301,0.19507,0.20709,0.21909,0.23105,0.24295,0.25485,0.26669,0.2785,0.29025,0.30197,0.31366,0.32529,0.33685,0.34839,0.35986,0.37128,0.38266,0.39395,0.40521,0.41641,0.42752,0.4386,0.44958,0.46051,0.47137,0.48215,0.49286,0.50351,0.51407,0.52457,0.53497,0.54529,0.55554,0.5657,0.57578,0.58575,0.59567,0.60547,0.6152,0.62482,0.63437,0.6438,0.65314,0.66238,0.67151,0.68057,0.68951,0.69833,0.70706,0.7157,0.72421,0.7326,0.74091,0.74908,0.75717,0.76514,0.77298,0.7807,0.7883,0.79581,0.80316,0.81042,0.81754,0.82455,0.83142,0.8382,0.84482,0.85132,0.8577,0.86392,0.87006,0.87604,0.88187,0.8876,0.89319,0.89862,0.90396,0.90912,0.91415,0.91907,0.92383,0.92847,0.93295,0.93729,0.9415,0.94556,0.94949,0.95325,0.95691,0.96039,0.96375,0.96692,0.97,0.9729,0.97565,0.97827,0.98074,0.98306,0.98523,0.98724,0.98914,0.99084,0.99243,0.99387,0.99515,0.99628,0.99725,0.99808,0.99875,0.99927,0.99966,0.99988,0.99997,0.99988,0.99966,0.99927,0.99875,0.99808,0.99725,0.99628,0.99515,0.99387,0.99243,0.99084,0.98914,0.98724,0.98523,0.98306,0.98074,0.97827,0.97565,0.9729,0.97,0.96692,0.96375,0.96039,0.95691,0.95325,0.94949,0.94556,0.9415,0.93729,0.93295,0.92847,0.92383,0.91907,0.91415,0.90912,0.90396,0.89862,0.89319,0.8876,0.88187,0.87604,0.87006,0.86392,0.8577,0.85132,0.84482,0.8382,0.83142,0.82455,0.81754,0.81042,0.80316,0.79581,0.7883,0.7807,0.77298,0.76514,0.75717,0.74908,0.74091,0.7326,0.72421,0.7157,0.70706,0.69833,0.68951,0.68057,0.67151,0.66238,0.65314,0.6438,0.63437,0.62482,0.6152,0.60547,0.59567,0.58575,0.57578,0.5657,0.55554,0.54529,0.53497,0.52457,0.51407,0.50351,0.49286,0.48215,0.47137,0.46051,0.44958,0.4386,0.42752,0.41641,0.40521,0.39395,0.38266,0.37128,0.35986,0.34839,0.33685,0.32529,0.31366,0.30197,0.29025,0.2785,0.26669,0.25485,0.24295,0.23105,0.21909,0.20709,0.19507,0.18301,0.17093,0.15884,0.1467,0.13455,0.12241,0.1102,0.097992,0.085785,0.073547,0.06131,0.049042,0.036804,0.024536,0.012268,0,-0.012268,-0.024536,-0.036804,-0.049042,-0.06131,-0.073547,-0.085785,-0.097992,-0.1102,-0.12241,-0.13455,-0.1467,-0.15884,-0.17093,-0.18301,-0.19507,-0.20709,-0.21909,-0.23105,-0.24295,-0.25485,-0.26669,-0.2785,-0.29025,-0.30197,-0.31366,-0.32529,-0.33685,-0.34839,-0.35986,-0.37128,-0.38266,-0.39395,-0.40521,-0.41641,-0.42752,-0.4386,-0.44958,-0.46051,-0.47137,-0.48215,-0.49286,-0.50351,-0.51407,-0.52457,-0.53497,-0.54529,-0.55554,-0.5657,-0.57578,-0.58575,-0.59567,-0.60547,-0.6152,-0.62482,-0.63437,-0.6438,-0.65314,-0.66238,-0.67151,-0.68057,-0.68951,-0.69833,-0.70706,-0.7157,-0.72421,-0.7326,-0.74091,-0.74908,-0.75717,-0.76514,-0.77298,-0.7807,-0.7883,-0.79581,-0.80316,-0.81042,-0.81754,-0.82455,-0.83142,-0.8382,-0.84482,-0.85132,-0.8577,-0.86392,-0.87006,-0.87604,-0.88187,-0.8876,-0.89319,-0.89862,-0.90396,-0.90912,-0.91415,-0.91907,-0.92383,-0.92847,-0.93295,-0.93729,-0.9415,-0.94556,-0.94949,-0.95325,-0.95691,-0.96039,-0.96375,-0.96692,-0.97,-0.9729,-0.97565,-0.97827,-0.98074,-0.98306,-0.98523,-0.98724,-0.98914,-0.99084,-0.99243,-0.99387,-0.99515,-0.99628,-0.99725,-0.99808,-0.99875,-0.99927,-0.99966,-0.99988,-0.99997,-0.99988,-0.99966,-0.99927,-0.99875,-0.99808,-0.99725,-0.99628,-0.99515,-0.99387,-0.99243,-0.99084,-0.98914,-0.98724,-0.98523,-0.98306,-0.98074,-0.97827,-0.97565,-0.9729,-0.97,-0.96692,-0.96375,-0.96039,-0.95691,-0.95325,-0.94949,-0.94556,-0.9415,-0.93729,-0.93295,-0.92847,-0.92383,-0.91907,-0.91415,-0.90912,-0.90396,-0.89862,-0.89319,-0.8876,-0.88187,-0.87604,-0.87006,-0.86392,-0.8577,-0.85132,-0.84482,-0.8382,-0.83142,-0.82455,-0.81754,-0.81042,-0.80316,-0.79581,-0.7883,-0.7807,-0.77298,-0.76514,-0.75717,-0.74908,-0.74091,-0.7326,-0.72421,-0.7157,-0.70706,-0.69833,-0.68951,-0.68057,-0.67151,-0.66238,-0.65314,-0.6438,-0.63437,-0.62482,-0.6152,-0.60547,-0.59567,-0.58575,-0.57578,-0.5657,-0.55554,-0.54529,-0.53497,-0.52457,-0.51407,-0.50351,-0.49286,-0.48215,-0.47137,-0.46051,-0.44958,-0.4386,-0.42752,-0.41641,-0.40521,-0.39395,-0.38266,-0.37128,-0.35986,-0.34839,-0.33685,-0.32529,-0.31366,-0.30197,-0.29025,-0.2785,-0.26669,-0.25485,-0.24295,-0.23105,-0.21909,-0.20709,-0.19507,-0.18301,-0.17093,-0.15884,-0.1467,-0.13455,-0.12241,-0.1102,-0.097992,-0.085785,-0.073547,-0.06131,-0.049042,-0.036804,-0.024536,-0.012268,0,0.012268
+};
+
+// This is a transition table that helps with bandlimited oscs.
+double transition[1001]={-0.500003,-0.500003,-0.500023,-0.500063,-0.500121,-0.500179,-0.500259,
+ -0.50036,-0.500476,-0.500591,-0.500732,-0.500893,-0.501066,-0.501239,
+ -0.50144,-0.501661,-0.501891,-0.502123,-0.502382,-0.502662,-0.502949,
+ -0.50324,-0.503555,-0.503895,-0.504238,-0.504587,-0.504958,-0.505356,
+ -0.505754,-0.506162,-0.506589,-0.507042,-0.507495,-0.50796,-0.508444,
+ -0.508951,-0.509458,-0.509979,-0.510518,-0.511079,-0.511638,-0.512213,
+ -0.512808,-0.51342,-0.51403,-0.514659,-0.515307,-0.51597,-0.51663,-0.517312,
+ -0.518012,-0.518724,-0.519433,-0.520166,-0.520916,-0.521675,-0.522432,
+ -0.523214,-0.524013,-0.524819,-0.525624,-0.526451,-0.527298,-0.528147,
+ -0.528999,-0.52987,-0.530762,-0.531654,-0.532551,-0.533464,-0.534399,
+ -0.535332,-0.536271,-0.537226,-0.538202,-0.539172,-0.540152,-0.541148,
+ -0.542161,-0.543168,-0.544187,-0.54522,-0.546269,-0.54731,-0.548365,
+ -0.549434,-0.550516,-0.55159, -0.552679,-0.553781,-0.554893,-0.555997,
+ -0.557118,-0.558252,-0.559391,-0.560524,-0.561674,-0.562836,-0.564001,
+ -0.565161,-0.566336,-0.567524,-0.568712,-0.569896,-0.571095,-0.572306,
+ -0.573514,-0.574721,-0.575939,-0.577171,-0.578396,-0.579622,-0.580858,
+ -0.582108,-0.583348,-0.58459, -0.585842,-0.587106,-0.588358,-0.589614,
+ -0.590879,-0.592154,-0.593415,-0.594682,-0.595957,-0.59724,-0.598507,
+ -0.599782,-0.601064,-0.602351,-0.603623,-0.604902,-0.606189,-0.607476,
+ -0.60875,-0.610032,-0.611319, -0.612605,-0.613877,-0.615157,-0.616443,
+ -0.617723,-0.618992,-0.620268,-0.621548,-0.62282,-0.624083,-0.62535,
+ -0.626622,-0.627882,-0.629135,-0.630391,-0.631652,-0.632898,-0.634138,
+ -0.63538,-0.636626,-0.637854, -0.639078,-0.640304,-0.641531,-0.642739,
+ -0.643943,-0.645149,-0.646355,-0.647538,-0.64872,-0.649903,-0.651084,
+ -0.652241,-0.653397,-0.654553,-0.655705,-0.656834,-0.657961,-0.659087,
+ -0.660206,-0.661304,-0.662399,-0.663492,-0.664575,-0.665639,-0.666699,
+ -0.667756,-0.6688,-0.669827, -0.670849,-0.671866,-0.672868,-0.673854,
+ -0.674835,-0.675811,-0.676767,-0.677709,-0.678646,-0.679576,-0.680484,
+ -0.68138,-0.682269,-0.683151, -0.684008,-0.684854,-0.685693,-0.686524,
+ -0.687327,-0.688119,-0.688905,-0.689682,-0.690428,-0.691164,-0.691893,
+ -0.692613,-0.6933,-0.693978, -0.694647,-0.695305,-0.695932,-0.696549,
+ -0.697156,-0.697748,-0.698313,-0.698865,-0.699407,-0.699932,-0.700431,
+ -0.700917,-0.701391,-0.701845,-0.702276,-0.702693,-0.703097,-0.703478,
+ -0.703837,-0.704183,-0.704514,-0.704819,-0.705105,-0.705378,-0.705633,
+ -0.70586,-0.706069,-0.706265, -0.706444,-0.706591,-0.706721,-0.706837,
+ -0.706938,-0.707003,-0.707051,-0.707086,-0.707106,-0.707086,-0.707051,
+ -0.707001,-0.706935,-0.706832,-0.706711,-0.706576,-0.706421,-0.706233,
+ -0.706025,-0.705802,-0.705557,-0.705282,-0.704984,-0.704671,-0.704334,
+ -0.703969,-0.703582,-0.703176,-0.702746,-0.702288,-0.70181,-0.701312,
+ -0.700785,-0.700234,-0.699664,-0.69907,-0.698447,-0.6978,-0.697135,
+ -0.696446,-0.695725,-0.694981,-0.694219,-0.693435,-0.692613,-0.691771,
+ -0.690911,-0.69003,-0.689108, -0.688166,-0.687206,-0.686227,-0.685204,
+ -0.684162,-0.683101,-0.682019,-0.680898,-0.679755,-0.678592,-0.677407,
+ -0.676187,-0.674941,-0.673676,-0.672386,-0.671066,-0.669718,-0.66835,
+ -0.666955,-0.665532,-0.664083,-0.662611,-0.661112,-0.659585,-0.658035,
+ -0.656459,-0.654854,-0.653223,-0.651572,-0.649892,-0.648181,-0.646446,
+ -0.644691,-0.642909,-0.641093,-0.639253,-0.637393,-0.63551,-0.633588,
+ -0.631644,-0.62968,-0.627695,-0.625668,-0.623621,-0.621553,-0.619464,
+ -0.617334,-0.615183,-0.613011,-0.610817,-0.608587,-0.606333,-0.604058,
+ -0.60176,-0.599429,-0.597072,-0.594695,-0.592293,-0.589862,-0.587404,
+ -0.584925,-0.58242,-0.579888,-0.577331,-0.574751,-0.572145,-0.569512,
+ -0.566858,-0.564178,-0.561471,-0.558739,-0.555988,-0.553209,-0.550402,
+ -0.547572,-0.544723,-0.54185,-0.538944,-0.536018,-0.533072,-0.530105,
+ -0.527103,-0.524081,-0.52104,-0.51798,-0.514883,-0.511767,-0.508633,
+ -0.505479,-0.502291,-0.499083,-0.495857,-0.492611,-0.489335,-0.486037,
+ -0.48272,-0.479384,-0.476021,-0.472634,-0.46923,-0.465805,-0.462356,
+ -0.458884,-0.455394,-0.451882,-0.448348,-0.444795,-0.44122,-0.437624,
+ -0.434008,-0.430374,-0.426718,-0.423041,-0.419344,-0.415631,-0.411897,
+ -0.40814,-0.404365,-0.400575,-0.396766,-0.392933,-0.389082,-0.385217,
+ -0.381336,-0.377428,-0.373505,-0.369568,-0.365616,-0.361638,-0.357645,
+ -0.353638,-0.349617,-0.345572,-0.341512,-0.337438,-0.33335,-0.329242,
+ -0.325118,-0.32098,-0.316829,-0.31266,-0.308474,-0.304276,-0.300063,
+ -0.295836,-0.291593,-0.287337,-0.283067,-0.278783,-0.274487,-0.270176,
+ -0.265852,-0.261515,-0.257168,-0.252806,-0.248431,-0.244045,-0.239649,
+ -0.23524,-0.230817,-0.226385,-0.221943,-0.21749,-0.213024,-0.208548,
+ -0.204064,-0.199571,-0.195064,-0.190549,-0.186026,-0.181495,-0.176952,
+ -0.1724,-0.167842,-0.163277,-0.1587,-0.154117,-0.149527,-0.14493,-0.140325,
+ -0.135712,-0.131094,-0.12647,-0.121839,-0.117201,-0.112559,-0.10791,
+ -0.103257,-0.0985979,-0.0939343,-0.0892662,-0.0845935,-0.079917,-0.0752362,
+ -0.0705516,-0.0658635,-0.0611729,-0.0564786,-0.0517814,-0.0470818,-0.0423802,
+ -0.0376765,-0.0329703,-0.0282629,-0.0235542,-0.0188445,-0.0141335,-0.00942183,
+ -0.00470983,2.41979e-06,0.00471481,0.00942681,0.0141384,0.0188494,0.023559,
+ 0.028268,0.0329754,0.0376813,0.0423851,0.0470868,0.0517863,0.0564836,
+ 0.0611777,0.0658683,0.0705566,0.0752412,0.0799218,0.0845982,0.0892712,
+ 0.0939393,0.0986028,0.103262,0.107915,0.112563,0.117206,0.121844,0.126475,
+ 0.131099,0.135717,0.14033,0.144935,0.149531,0.154122,0.158705,0.163281,
+ 0.167847,0.172405,0.176956,0.1815,0.18603,0.190553,0.195069,0.199576,
+ 0.204068,0.208552,0.213028,0.217495,0.221947,0.226389,0.230822,0.235245,
+ 0.239653,0.244049,0.248436,0.252811,0.257173,0.26152,0.265857,0.270181,
+ 0.274491,0.278788,0.283071,0.287341,0.291597,0.29584,0.300068,0.30428,
+ 0.308478,0.312664,0.316833,0.320984,0.325122,0.329246,0.333354,0.337442,
+ 0.341516,0.345576,0.34962,0.353642,0.357649,0.361642,0.36562,0.369572,
+ 0.373509,0.377432,0.38134,0.385221,0.389086,0.392936,0.39677,0.400579,
+ 0.404369,0.408143,0.4119,0.415634,0.419347,0.423044,0.426721,0.430377,
+ 0.434011,0.437627,0.441223,0.444798,0.448351,0.451885,0.455397,0.458887,
+ 0.462359,0.465807,0.469232,0.472637,0.476024,0.479386,0.482723,0.486039,
+ 0.489338,0.492613,0.49586,0.499086,0.502294,0.505481,0.508635,0.511769,
+ 0.514885,0.517982,0.521042,0.524083,0.527105,0.530107,0.533074,0.53602,
+ 0.538946,0.541851,0.544725,0.547574,0.550404,0.553211,0.555989,0.55874,
+ 0.561472,0.564179,0.566859,0.569514,0.572146,0.574753,0.577332,0.579889,
+ 0.582421,0.584926,0.587405,0.589863,0.592294,0.594696,0.597073,0.59943,
+ 0.60176,0.604059,0.606333,0.608588,0.610818,0.613012,0.615183,0.617335,
+ 0.619464,0.621553,0.623621,0.625669,0.627696,0.629681,0.631645,0.633588,
+ 0.63551,0.637393,0.639253,0.641093,0.642909,0.644691,0.646446,0.648181,
+ 0.649892,0.651572,0.653223,0.654854,0.656459,0.658035,0.659585,0.661112,
+ 0.662611,0.664083,0.665532,0.666955,0.66835,0.669718,0.671066,0.672386,
+ 0.673676,0.674941,0.676187,0.677407,0.678592,0.679755,0.680898,0.682019,
+ 0.683101,0.684162,0.685204,0.686227,0.687206,0.688166,0.689108,0.69003,
+ 0.690911,0.691771,0.692613,0.693435,0.694219,0.694981,0.695725,0.696447,
+ 0.697135,0.6978,0.698447,0.69907,0.699664,0.700234,0.700786,0.701312,
+ 0.70181,0.702288,0.702746,0.703177,0.703582,0.703969,0.704334,0.704671,
+ 0.704984,0.705282,0.705557,0.705802,0.706025,0.706233,0.706422,0.706576,
+ 0.706712,0.706832,0.706936,0.707002,0.707051,0.707086,0.707106,0.707086,
+ 0.707051,0.707003,0.706939,0.706838,0.706721,0.706592,0.706445,0.706265,
+ 0.70607,0.705861,0.705634,0.705378,0.705105,0.70482,0.704515,0.704184,
+ 0.703837,0.703478,0.703097,0.702694,0.702276,0.701846,0.701392,0.700917,
+ 0.700432,0.699932,0.699408,0.698866,0.698314,0.697749,0.697156,0.696549,
+ 0.695933,0.695305,0.694648,0.693979,0.693301,0.692613,0.691894,0.691165,
+ 0.690428,0.689683,0.688905,0.68812,0.687327,0.686525,0.685693,0.684854,
+ 0.684009,0.683152,0.68227,0.68138,0.680485,0.679577,0.678647,0.67771,
+ 0.676768,0.675811,0.674836,0.673855,0.672869,0.671867,0.670849,0.669827,
+ 0.668801,0.667757,0.6667,0.66564,0.664576,0.663493,0.6624,0.661305,
+ 0.660207,0.659088,0.657962,0.656834,0.655705,0.654553,0.653398,0.652241,
+ 0.651085,0.649903,0.648721,0.647539,0.646356,0.645149,0.643944,0.642739,
+ 0.641532,0.640304,0.639079,0.637855,0.636626,0.635381,0.634139,0.632899,
+ 0.631652,0.630392,0.629136,0.627883,0.626622,0.62535,0.624083,0.62282,
+ 0.621548,0.620268,0.618993,0.617724,0.616443,0.615158,0.613878,0.612605,
+ 0.61132,0.610032,0.608751,0.607477,0.606189,0.604903,0.603623,0.602351,
+ 0.601065,0.599782,0.598508,0.59724,0.595957,0.594682,0.593415,0.592154,
+ 0.59088,0.589615,0.588359,0.587106,0.585843,0.584591,0.583349,0.582108,
+ 0.580859,0.579623,0.578397,0.577172,0.575939,0.574721,0.573515,0.572307,
+ 0.571095,0.569897,0.568713,0.567525,0.566337,0.565161,0.564002,0.562837,
+ 0.561674,0.560525,0.559392,0.558252,0.557119,0.555998,0.554893,0.553782,
+ 0.552679,0.55159,0.550516,0.549434,0.548365,0.54731,0.546269,0.54522,
+ 0.544187,0.543168,0.542161,0.541148,0.540153,0.539173,0.538202,0.537226,
+ 0.536271,0.535332,0.5344,0.533464,0.532551,0.531654,0.530762,0.52987,
+ 0.528999,0.528147,0.527298,0.526451,0.525624,0.524819,0.524014,0.523214,
+ 0.522432,0.521675,0.520916,0.520166,0.519433,0.518724,0.518012,0.517312,
+ 0.51663,0.51597,0.515307,0.51466,0.51403,0.51342,0.512808,0.512213,
+ 0.511638,0.511079,0.510518,0.509979,0.509458,0.508951,0.508444,0.50796,
+ 0.507495,0.507042,0.506589,0.506162,0.505754,0.505356,0.504958,0.504587,
+ 0.504237,0.503895,0.503555,0.50324,0.502949,0.502662,0.502382,0.502123,
+ 0.501891,0.501661,0.50144,0.501239,0.501066,0.500893,0.500732,0.500591,
+ 0.500476,0.50036,0.500259,0.500179,0.500121,0.500063,0.500023,0.500003,0.500003};
+
+//This is a lookup table for converting midi to frequency
+double mtofarray[129]={0, 8.661957, 9.177024, 9.722718, 10.3, 10.913383, 11.562325, 12.25, 12.978271, 13.75, 14.567617, 15.433853, 16.351599, 17.323914, 18.354048, 19.445436, 20.601723, 21.826765, 23.124651, 24.5, 25.956543, 27.5, 29.135235, 30.867706, 32.703197, 34.647827, 36.708096, 38.890873, 41.203445, 43.65353, 46.249302, 49., 51.913086, 55., 58.27047, 61.735413, 65.406395, 69.295654, 73.416191, 77.781746, 82.406891, 87.30706, 92.498604, 97.998856, 103.826172, 110., 116.540939, 123.470825, 130.81279, 138.591309, 146.832382, 155.563492, 164.813782, 174.61412, 184.997208, 195.997711, 207.652344, 220., 233.081879, 246.94165, 261.62558, 277.182617,293.664764, 311.126984, 329.627563, 349.228241, 369.994415, 391.995422, 415.304688, 440., 466.163757, 493.883301, 523.25116, 554.365234, 587.329529, 622.253967, 659.255127, 698.456482, 739.988831, 783.990845, 830.609375, 880., 932.327515, 987.766602, 1046.502319, 1108.730469, 1174.659058, 1244.507935, 1318.510254, 1396.912964, 1479.977661, 1567.981689, 1661.21875, 1760., 1864.655029, 1975.533203, 2093.004639, 2217.460938, 2349.318115, 2489.015869, 2637.020508, 2793.825928, 2959.955322, 3135.963379, 3322.4375, 3520., 3729.31, 3951.066406, 4186.009277, 4434.921875, 4698.63623, 4978.031738, 5274.041016, 5587.651855, 5919.910645, 6271.926758, 6644.875, 7040., 7458.620117, 7902.132812, 8372.018555, 8869.84375, 9397.272461, 9956.063477, 10548.082031, 11175.303711, 11839.821289, 12543.853516, 13289.75};
+
+void setup();//use this to do any initialisation if you want.
+
+void play(double *channels);//run dac!
+
+maxiOsc::maxiOsc(){
+ //When you create an oscillator, the constructor sets the phase of the oscillator to 0.
+ phase = 0.0;
+}
+
+double maxiOsc::noise() {
+ //White Noise
+ //always the same unless you seed it.
+ float r = rand()/(float)RAND_MAX;
+ output=r*2-1;
+ return(output);
+}
+
+void maxiOsc::phaseReset(double phaseIn) {
+ //This allows you to set the phase of the oscillator to anything you like.
+ phase=phaseIn;
+
+}
+
+double maxiOsc::sinewave(double frequency) {
+ //This is a sinewave oscillator
+ output=sin (phase*(TWOPI));
+ if ( phase >= 1.0 ) phase -= 1.0;
+ phase += (1./(maxiSettings::sampleRate/(frequency)));
+ return(output);
+
+}
+
+double maxiOsc::sinebuf4(double frequency) {
+ //This is a sinewave oscillator that uses 4 point interpolation on a 514 point buffer
+ double remainder;
+ double a,b,c,d,a1,a2,a3;
+ phase += 512./(maxiSettings::sampleRate/(frequency));
+ if ( phase >= 511 ) phase -=512;
+ remainder = phase - floor(phase);
+
+ if (phase==0) {
+ a=sineBuffer[(long) 512];
+ b=sineBuffer[(long) phase];
+ c=sineBuffer[(long) phase+1];
+ d=sineBuffer[(long) phase+2];
+
+ } else {
+ a=sineBuffer[(long) phase-1];
+ b=sineBuffer[(long) phase];
+ c=sineBuffer[(long) phase+1];
+ d=sineBuffer[(long) phase+2];
+
+ }
+
+ a1 = 0.5f * (c - a);
+ a2 = a - 2.5 * b + 2.f * c - 0.5f * d;
+ a3 = 0.5f * (d - a) + 1.5f * (b - c);
+ output = double (((a3 * remainder + a2) * remainder + a1) * remainder + b);
+ return(output);
+}
+
+double maxiOsc::sinebuf(double frequency) { //specify the frequency of the oscillator in Hz / cps etc.
+ //This is a sinewave oscillator that uses linear interpolation on a 514 point buffer
+ double remainder;
+ phase += 512./(maxiSettings::sampleRate/(frequency*chandiv));
+ if ( phase >= 511 ) phase -=512;
+ remainder = phase - floor(phase);
+ output = (double) ((1-remainder) * sineBuffer[1+ (long) phase] + remainder * sineBuffer[2+(long) phase]);
+ return(output);
+}
+
+double maxiOsc::coswave(double frequency) {
+ //This is a cosine oscillator
+ output=cos (phase*(TWOPI));
+ if ( phase >= 1.0 ) phase -= 1.0;
+ phase += (1./(maxiSettings::sampleRate/(frequency)));
+ return(output);
+
+}
+
+double maxiOsc::phasor(double frequency) {
+ //This produces a floating point linear ramp between 0 and 1 at the desired frequency
+ output = phase;
+ if ( phase >= 1.0 ) phase -= 1.0;
+ phase += (1. / (maxiSettings::sampleRate/(frequency)));
+ return(output);
+}
+
+double maxiOsc::square(double frequency) {
+ //This is a square wave
+ if (phase<0.5) output=-1;
+ if (phase>0.5) output=1;
+ if ( phase >= 1.0 ) phase -= 1.0;
+ phase += (1./(maxiSettings::sampleRate/(frequency)));
+ return(output);
+}
+
+double maxiOsc::pulse(double frequency, double duty) {
+ //This is a pulse generator that creates a signal between -1 and 1.
+ if (duty<0.) duty=0;
+ if (duty>1.) duty=1;
+ if ( phase >= 1.0 ) phase -= 1.0;
+ phase += (1./(maxiSettings::sampleRate/(frequency)));
+ if (phase<duty) output=-1.;
+ if (phase>duty) output=1.;
+ return(output);
+}
+
+double maxiOsc::phasor(double frequency, double startphase, double endphase) {
+ //This is a phasor that takes a value for the start and end of the ramp.
+ output=phase;
+ if (phase<startphase) {
+ phase=startphase;
+ }
+ if ( phase >= endphase ) phase = startphase;
+ phase += ((endphase-startphase)/(maxiSettings::sampleRate/(frequency)));
+ return(output);
+}
+
+
+double maxiOsc::saw(double frequency) {
+ //Sawtooth generator. This is like a phasor but goes between -1 and 1
+ output=phase;
+ if ( phase >= 1.0 ) phase -= 2.0;
+ phase += (1./(maxiSettings::sampleRate/(frequency)));
+ return(output);
+
+}
+
+double maxiOsc::sawn(double frequency) {
+ //Bandlimited sawtooth generator. Woohoo.
+ if ( phase >= 0.5 ) phase -= 1.0;
+ phase += (1./(maxiSettings::sampleRate/(frequency)));
+ double temp=(8820.22/frequency)*phase;
+ if (temp<-0.5) {
+ temp=-0.5;
+ }
+ if (temp>0.5) {
+ temp=0.5;
+ }
+ temp*=1000.0f;
+ temp+=500.0f;
+ double remainder = temp - floor(temp);
+ output = (double) ((1.0f-remainder) * transition[(long)temp] + remainder * transition[1+(long)temp]) - phase;
+ return(output);
+
+}
+
+double maxiOsc::rect(double frequency, double duty) {
+
+ return (output);
+}
+
+double maxiOsc::triangle(double frequency) {
+ //This is a triangle wave.
+ if ( phase >= 1.0 ) phase -= 1.0;
+ phase += (1./(maxiSettings::sampleRate/(frequency)));
+ if (phase <= 0.5 ) {
+ output =(phase - 0.25) * 4;
+ } else {
+ output =((1.0-phase) - 0.25) * 4;
+ }
+ return(output);
+
+}
+
+double maxiEnvelope::line(int numberofsegments,double segments[1000]) {
+ //This is a basic multi-segment ramp generator that you can use for more or less anything.
+ //However, it's not that intuitive.
+ if (isPlaying==1) {//only make a sound once you've been triggered
+ period=2./(segments[valindex+1]*0.004);
+ nextval=segments[valindex+2];
+ currentval=segments[valindex];
+ if (currentval-amplitude > 0.0000001 && valindex < numberofsegments) {
+ amplitude += ((currentval-startval)/(maxiSettings::sampleRate/period));
+ } else if (currentval-amplitude < -0.0000001 && valindex < numberofsegments) {
+ amplitude -= (((currentval-startval)*(-1))/(maxiSettings::sampleRate/period));
+ } else if (valindex >numberofsegments-1) {
+ valindex=numberofsegments-2;
+ } else {
+ valindex=valindex+2;
+ startval=currentval;
+ }
+ output=amplitude;
+
+ }
+ else {
+ output=0;
+
+ }
+ return(output);
+}
+
+//and this
+void maxiEnvelope::trigger(int index, double amp) {
+ isPlaying=1;//ok the envelope is being used now.
+ valindex=index;
+ amplitude=amp;
+
+}
+
+//Delay with feedback
+maxiDelayline::maxiDelayline() {
+ memset( memory, 0, 88200*sizeof (double) );
+}
+
+
+double maxiDelayline::dl(double input, int size, double feedback) {
+ if ( phase >=size ) {
+ phase = 0;
+ }
+ output = memory[phase];
+ memory[phase] = (memory[phase] * feedback) + (input * feedback) * 0.5;
+ phase += 1;
+ return(output);
+}
+
+double maxiDelayline::dl(double input, int size, double feedback, int position) {
+ if ( phase >=size ) phase = 0;
+ if ( position >=size ) position = 0;
+ output=memory[position];
+ memory[phase]=(memory[phase]*feedback)+(input*feedback)*chandiv;
+ phase+=1;
+ return(output);
+
+}
+
+//I particularly like these. cutoff between 0 and 1
+double maxiFilter::lopass(double input, double cutoff) {
+ output=outputs[0] + cutoff*(input-outputs[0]);
+ outputs[0]=output;
+ return(output);
+}
+//as above
+double maxiFilter::hipass(double input, double cutoff) {
+ output=input-(outputs[0] + cutoff*(input-outputs[0]));
+ outputs[0]=output;
+ return(output);
+}
+//awesome. cuttof is freq in hz. res is between 1 and whatever. Watch out!
+double maxiFilter::lores(double input,double cutoff1, double resonance) {
+ cutoff=cutoff1*0.5;
+ if (cutoff<10) cutoff=10;
+ if (cutoff>(maxiSettings::sampleRate*0.5)) cutoff=(maxiSettings::sampleRate*0.5);
+ if (resonance<1.) resonance = 1.;
+ z=cos(TWOPI*cutoff/maxiSettings::sampleRate);
+ c=2-2*z;
+ double r=(sqrt(2.0)*sqrt(-pow((z-1.0),3.0))+resonance*(z-1))/(resonance*(z-1));
+ x=x+(input-y)*c;
+ y=y+x;
+ x=x*r;
+ output=y;
+ return(output);
+}
+
+//working hires filter
+double maxiFilter::hires(double input,double cutoff1, double resonance) {
+ cutoff=cutoff1*0.5;
+ if (cutoff<10) cutoff=10;
+ if (cutoff>(maxiSettings::sampleRate*0.5)) cutoff=(maxiSettings::sampleRate*0.5);
+ if (resonance<1.) resonance = 1.;
+ z=cos(TWOPI*cutoff/maxiSettings::sampleRate);
+ c=2-2*z;
+ double r=(sqrt(2.0)*sqrt(-pow((z-1.0),3.0))+resonance*(z-1))/(resonance*(z-1));
+ x=x+(input-y)*c;
+ y=y+x;
+ x=x*r;
+ output=input-y;
+ return(output);
+}
+
+//This works a bit. Needs attention.
+double maxiFilter::bandpass(double input,double cutoff1, double resonance) {
+ cutoff=cutoff1;
+ if (cutoff>(maxiSettings::sampleRate*0.5)) cutoff=(maxiSettings::sampleRate*0.5);
+ if (resonance>=1.) resonance=0.999999;
+ z=cos(TWOPI*cutoff/maxiSettings::sampleRate);
+ inputs[0] = (1-resonance)*(sqrt(resonance*(resonance-4.0*pow(z,2.0)+2.0)+1));
+ inputs[1] = 2*z*resonance;
+ inputs[2] = pow((resonance*-1),2);
+
+ output=inputs[0]*input+inputs[1]*outputs[1]+inputs[2]*outputs[2];
+ outputs[2]=outputs[1];
+ outputs[1]=output;
+ return(output);
+}
+
+//stereo bus
+double *maxiMix::stereo(double input,double two[2],double x) {
+ if (x>1) x=1;
+ if (x<0) x=0;
+ two[0]=input*sqrt(1.0-x);
+ two[1]=input*sqrt(x);
+ return(two);
+}
+
+//quad bus
+double *maxiMix::quad(double input,double four[4],double x,double y) {
+ if (x>1) x=1;
+ if (x<0) x=0;
+ if (y>1) y=1;
+ if (y<0) y=0;
+ four[0]=input*sqrt((1.0-x)*y);
+ four[1]=input*sqrt((1.0-x)*(1.0-y));
+ four[2]=input*sqrt(x*y);
+ four[3]=input*sqrt(x*(1.0-y));
+ return(four);
+}
+
+//ambisonic bus
+double *maxiMix::ambisonic(double input,double eight[8],double x,double y,double z) {
+ if (x>1) x=1;
+ if (x<0) x=0;
+ if (y>1) y=1;
+ if (y<0) y=0;
+ if (z>1) y=1;
+ if (z<0) y=0;
+ eight[0]=input*(sqrt((1.0-x)*y)*1.0-z);
+ eight[1]=input*(sqrt((1.0-x)*(1.0-y))*1.0-z);
+ eight[2]=input*(sqrt(x*y)*1.0-z);
+ eight[3]=input*(sqrt(x*(1.0-y))*1.0-z);
+ eight[4]=input*(sqrt((1.0-x)*y)*z);
+ eight[5]=input*(sqrt((1.0-x)*(1.0-y))*z);
+ eight[6]=input*sqrt((x*y)*z);
+ eight[7]=input*sqrt((x*(1.0-y))*z);
+ return(eight);
+}
+
+//This is the maxiSample load function. It just calls read.
+bool maxiSample::load(string fileName, int channel) {
+ myPath = fileName;
+ readChannel=channel;
+ return read();
+}
+
+// This is for OGG loading
+bool maxiSample::loadOgg(string fileName, int channel) {
+#ifdef VORBIS
+ bool result;
+ readChannel=channel;
+ int channelx;
+// cout << fileName << endl;
+ myDataSize = stb_vorbis_decode_filename(const_cast<char*>(fileName.c_str()), &channelx, &temp);
+ result = myDataSize > 0;
+ printf("\nchannels = %d\nlength = %d",channelx,myDataSize);
+ printf("\n");
+ myChannels=(short)channelx;
+ length=myDataSize;
+ mySampleRate=44100;
+
+ if (myChannels>1) {
+ int position=0;
+ int channel=readChannel;
+ for (int i=channel;i<myDataSize*2;i+=myChannels) {
+ temp[position]=temp[i];
+ position++;
+ }
+ }
+ return result; // this should probably be something more descriptive
+#endif
+ return 0;
+}
+
+//This sets the playback position to the start of a sample
+void maxiSample::trigger() {
+ position = 0;
+}
+
+//This is the main read function.
+bool maxiSample::read()
+{
+ bool result;
+ ifstream inFile( myPath.c_str(), ios::in | ios::binary);
+ result = (bool) inFile;
+ if (inFile) {
+ bool datafound = false;
+ inFile.seekg(4, ios::beg);
+ inFile.read( (char*) &myChunkSize, 4 ); // read the ChunkSize
+
+ inFile.seekg(16, ios::beg);
+ inFile.read( (char*) &mySubChunk1Size, 4 ); // read the SubChunk1Size
+
+ //inFile.seekg(20, ios::beg);
+ inFile.read( (char*) &myFormat, sizeof(short) ); // read the file format. This should be 1 for PCM
+
+ //inFile.seekg(22, ios::beg);
+ inFile.read( (char*) &myChannels, sizeof(short) ); // read the # of channels (1 or 2)
+
+ //inFile.seekg(24, ios::beg);
+ inFile.read( (char*) &mySampleRate, sizeof(int) ); // read the samplerate
+
+ //inFile.seekg(28, ios::beg);
+ inFile.read( (char*) &myByteRate, sizeof(int) ); // read the byterate
+
+ //inFile.seekg(32, ios::beg);
+ inFile.read( (char*) &myBlockAlign, sizeof(short) ); // read the blockalign
+
+ //inFile.seekg(34, ios::beg);
+ inFile.read( (char*) &myBitsPerSample, sizeof(short) ); // read the bitspersample
+
+ //ignore any extra chunks
+ char chunkID[5]="";
+ chunkID[4] = 0;
+ int filePos = 36;
+ while(!datafound && !inFile.eof()) {
+ inFile.seekg(filePos, ios::beg);
+ inFile.read((char*) &chunkID, sizeof(char) * 4);
+ inFile.seekg(filePos + 4, ios::beg);
+ inFile.read( (char*) &myDataSize, sizeof(int) ); // read the size of the data
+ filePos += 8;
+ if (strcmp(chunkID,"data") == 0) {
+ datafound = true;
+ }else{
+ filePos += myDataSize;
+ }
+ }
+
+ // read the data chunk
+ myData = (char*) malloc(myDataSize * sizeof(char));
+ inFile.seekg(filePos, ios::beg);
+ inFile.read(myData, myDataSize);
+ length=myDataSize*(0.5/myChannels);
+ inFile.close(); // close the input file
+
+ cout << "Ch: " << myChannels << ", len: " << length << endl;
+ if (myChannels>1) {
+ int position=0;
+ int channel=readChannel*2;
+ for (int i=channel;i<myDataSize+6;i+=(myChannels*2)) {
+ myData[position]=myData[i];
+ myData[position+1]=myData[i+1];
+ position+=2;
+ }
+ }
+ temp = (short*) malloc(myDataSize * sizeof(char));
+ memcpy(temp, myData, myDataSize * sizeof(char));
+
+ free(myData);
+
+ }else {
+// cout << "ERROR: Could not load sample: " <<myPath << endl; //This line seems to be hated by windows
+ printf("ERROR: Could not load sample.");
+
+ }
+
+
+ return result; // this should probably be something more descriptive
+}
+
+//This plays back at the correct speed. Always loops.
+double maxiSample::play() {
+ position++;
+ if ((long) position == length) position=0;
+ output = (double) temp[(long)position]/32767.0;
+ return output;
+}
+
+//This plays back at the correct speed. Only plays once. To retrigger, you have to manually reset the position
+double maxiSample::playOnce() {
+ position++;
+ if ((long) position<length)
+ output = (double) temp[(long)position]/32767.0;
+ else {
+ output=0;
+ }
+ return output;
+
+}
+
+//Same as above but takes a speed value specified as a ratio, with 1.0 as original speed
+double maxiSample::playOnce(double speed) {
+ position=position+((speed*chandiv)/(maxiSettings::sampleRate/mySampleRate));
+ double remainder = position - (long) position;
+ if ((long) position<length)
+ output = (double) ((1-remainder) * temp[1+ (long) position] + remainder * temp[2+(long) position])/32767;//linear interpolation
+ else
+ output=0;
+ return(output);
+}
+
+//As above but looping
+double maxiSample::play(double speed) {
+ double remainder;
+ long a,b;
+ position=position+((speed*chandiv)/(maxiSettings::sampleRate/mySampleRate));
+ if (speed >=0) {
+
+ if ((long) position>=length-1) position=1;
+ remainder = position - floor(position);
+ if (position+1<length) {
+ a=position+1;
+
+ }
+ else {
+ a=length-1;
+ }
+ if (position+2<length)
+ {
+ b=position+2;
+ }
+ else {
+ b=length-1;
+ }
+
+ output = (double) ((1-remainder) * temp[a] + remainder * temp[b])/32767;//linear interpolation
+} else {
+ if ((long) position<0) position=length;
+ remainder = position - floor(position);
+ if (position-1>=0) {
+ a=position-1;
+
+ }
+ else {
+ a=0;
+ }
+ if (position-2>=0) {
+ b=position-2;
+ }
+ else {
+ b=0;
+ }
+ output = (double) ((-1-remainder) * temp[a] + remainder * temp[b])/32767;//linear interpolation
+ }
+ return(output);
+}
+
+//placeholder
+double maxiSample::play(double frequency, double start, double end) {
+ return play(frequency, start, end, position);
+}
+
+//This allows you to say how often a second you want a specific chunk of audio to play
+double maxiSample::play(double frequency, double start, double end, double &pos) {
+ double remainder;
+ if (end>=length) end=length-1;
+ long a,b;
+
+ if (frequency >0.) {
+ if (pos<start) {
+ pos=start;
+ }
+
+ if ( pos >= end ) pos = start;
+ pos += ((end-start)/(maxiSettings::sampleRate/(frequency*chandiv)));
+ remainder = pos - floor(pos);
+ long posl = floor(pos);
+ if (posl+1<length) {
+ a=posl+1;
+
+ }
+ else {
+ a=posl-1;
+ }
+ if (posl+2<length) {
+ b=posl+2;
+ }
+ else {
+ b=length-1;
+ }
+
+ output = (double) ((1-remainder) * temp[a] +
+ remainder * temp[b])/32767;//linear interpolation
+ } else {
+ frequency=frequency-(frequency+frequency);
+ if ( pos <= start ) pos = end;
+ pos -= ((end-start)/(maxiSettings::sampleRate/(frequency*chandiv)));
+ remainder = pos - floor(pos);
+ long posl = floor(pos);
+ if (posl-1>=0) {
+ a=posl-1;
+ }
+ else {
+ a=0;
+ }
+ if (posl-2>=0) {
+ b=posl-2;
+ }
+ else {
+ b=0;
+ }
+ output = (double) ((-1-remainder) * temp[a] +
+ remainder * temp[b])/32767;//linear interpolation
+
+ }
+
+ return(output);
+}
+
+
+//Same as above. better cubic inerpolation. Cobbled together from various (pd externals, yehar, other places).
+double maxiSample::play4(double frequency, double start, double end) {
+ double remainder;
+ double a,b,c,d,a1,a2,a3;
+ if (frequency >0.) {
+ if (position<start) {
+ position=start;
+ }
+ if ( position >= end ) position = start;
+ position += ((end-start)/(maxiSettings::sampleRate/(frequency*chandiv)));
+ remainder = position - floor(position);
+ if (position>0) {
+ a=temp[(int)(floor(position))-1];
+
+ } else {
+ a=temp[0];
+
+ }
+
+ b=temp[(long) position];
+ if (position<end-2) {
+ c=temp[(long) position+1];
+
+ } else {
+ c=temp[0];
+
+ }
+ if (position<end-3) {
+ d=temp[(long) position+2];
+
+ } else {
+ d=temp[0];
+ }
+ a1 = 0.5f * (c - a);
+ a2 = a - 2.5 * b + 2.f * c - 0.5f * d;
+ a3 = 0.5f * (d - a) + 1.5f * (b - c);
+ output = (double) (((a3 * remainder + a2) * remainder + a1) * remainder + b) / 32767;
+
+ } else {
+ frequency=frequency-(frequency+frequency);
+ if ( position <= start ) position = end;
+ position -= ((end-start)/(maxiSettings::sampleRate/(frequency*chandiv)));
+ remainder = position - floor(position);
+ if (position>start && position < end-1) {
+ a=temp[(long) position+1];
+
+ } else {
+ a=temp[0];
+
+ }
+
+ b=temp[(long) position];
+ if (position>start) {
+ c=temp[(long) position-1];
+
+ } else {
+ c=temp[0];
+
+ }
+ if (position>start+1) {
+ d=temp[(long) position-2];
+
+ } else {
+ d=temp[0];
+ }
+ a1 = 0.5f * (c - a);
+ a2 = a - 2.5 * b + 2.f * c - 0.5f * d;
+ a3 = 0.5f * (d - a) + 1.5f * (b - c);
+ output = (double) (((a3 * remainder + a2) * -remainder + a1) * -remainder + b) / 32767;
+
+ }
+
+ return(output);
+}
+
+
+//You don't need to worry about this stuff.
+double maxiSample::bufferPlay(unsigned char &bufferin,long length) {
+ double remainder;
+ short* buffer = (short *)&bufferin;
+ position=(position+1);
+ remainder = position - (long) position;
+ if ((long) position>length) position=0;
+ output = (double) ((1-remainder) * buffer[1+ (long) position] + remainder * buffer[2+(long) position])/32767;//linear interpolation
+ return(output);
+}
+
+double maxiSample::bufferPlay(unsigned char &bufferin,double speed,long length) {
+ double remainder;
+ long a,b;
+ short* buffer = (short *)&bufferin;
+ position=position+((speed*chandiv)/(maxiSettings::sampleRate/mySampleRate));
+ if (speed >=0) {
+
+ if ((long) position>=length-1) position=1;
+ remainder = position - floor(position);
+ if (position+1<length) {
+ a=position+1;
+
+ }
+ else {
+ a=length-1;
+ }
+ if (position+2<length)
+ {
+ b=position+2;
+ }
+ else {
+ b=length-1;
+ }
+
+ output = (double) ((1-remainder) * buffer[a] + remainder * buffer[b])/32767;//linear interpolation
+ } else {
+ if ((long) position<0) position=length;
+ remainder = position - floor(position);
+ if (position-1>=0) {
+ a=position-1;
+
+ }
+ else {
+ a=0;
+ }
+ if (position-2>=0) {
+ b=position-2;
+ }
+ else {
+ b=0;
+ }
+ output = (double) ((-1-remainder) * buffer[a] + remainder * buffer[b])/32767;//linear interpolation
+ }
+ return(output);
+}
+
+double maxiSample::bufferPlay(unsigned char &bufferin,double frequency, double start, double end) {
+ double remainder;
+ length=end;
+ long a,b;
+ short* buffer = (short *)&bufferin;
+ if (frequency >0.) {
+ if (position<start) {
+ position=start;
+ }
+
+ if ( position >= end ) position = start;
+ position += ((end-start)/(maxiSettings::sampleRate/(frequency*chandiv)));
+ remainder = position - floor(position);
+ long pos = floor(position);
+ if (pos+1<length) {
+ a=pos+1;
+
+ }
+ else {
+ a=pos-1;
+ }
+ if (pos+2<length) {
+ b=pos+2;
+ }
+ else {
+ b=length-1;
+ }
+
+ output = (double) ((1-remainder) * buffer[a] +
+ remainder * buffer[b])/32767;//linear interpolation
+ } else {
+ frequency=frequency-(frequency+frequency);
+ if ( position <= start ) position = end;
+ position -= ((end-start)/(maxiSettings::sampleRate/(frequency*chandiv)));
+ remainder = position - floor(position);
+ long pos = floor(position);
+ if (pos-1>=0) {
+ a=pos-1;
+ }
+ else {
+ a=0;
+ }
+ if (pos-2>=0) {
+ b=pos-2;
+ }
+ else {
+ b=0;
+ }
+ output = (double) ((-1-remainder) * buffer[a] +
+ remainder * buffer[b])/32767;//linear interpolation
+
+ }
+
+ return(output);
+}
+
+//better cubic inerpolation. Cobbled together from various (pd externals, yehar, other places).
+double maxiSample::bufferPlay4(unsigned char &bufferin,double frequency, double start, double end) {
+ double remainder;
+ double a,b,c,d,a1,a2,a3;
+ short* buffer = (short*)&bufferin;
+ if (frequency >0.) {
+ if (position<start) {
+ position=start;
+ }
+ if ( position >= end ) position = start;
+ position += ((end-start)/(maxiSettings::sampleRate/(frequency*chandiv)));
+ remainder = position - floor(position);
+ if (position>0) {
+ a=buffer[(int)(floor(position))-1];
+
+ } else {
+ a=buffer[0];
+
+ }
+
+ b=buffer[(long) position];
+ if (position<end-2) {
+ c=buffer[(long) position+1];
+
+ } else {
+ c=buffer[0];
+
+ }
+ if (position<end-3) {
+ d=buffer[(long) position+2];
+
+ } else {
+ d=buffer[0];
+ }
+ a1 = 0.5f * (c - a);
+ a2 = a - 2.5 * b + 2.f * c - 0.5f * d;
+ a3 = 0.5f * (d - a) + 1.5f * (b - c);
+ output = (double) (((a3 * remainder + a2) * remainder + a1) * remainder + b) / 32767;
+
+ } else {
+ frequency=frequency-(frequency+frequency);
+ if ( position <= start ) position = end;
+ position -= ((end-start)/(maxiSettings::sampleRate/(frequency*chandiv)));
+ remainder = position - floor(position);
+ if (position>start && position < end-1) {
+ a=buffer[(long) position+1];
+
+ } else {
+ a=buffer[0];
+
+ }
+
+ b=buffer[(long) position];
+ if (position>start) {
+ c=buffer[(long) position-1];
+
+ } else {
+ c=buffer[0];
+
+ }
+ if (position>start+1) {
+ d=buffer[(long) position-2];
+
+ } else {
+ d=buffer[0];
+ }
+ a1 = 0.5f * (c - a);
+ a2 = a - 2.5 * b + 2.f * c - 0.5f * d;
+ a3 = 0.5f * (d - a) + 1.5f * (b - c);
+ output = (double) (((a3 * remainder + a2) * -remainder + a1) * -remainder + b) / 32767;
+
+ }
+
+ return(output);
+}
+
+
+void maxiSample::getLength() {
+ length=myDataSize*0.5;
+}
+
+void maxiSample::setLength(unsigned long numSamples) {
+ cout << "Length: " << numSamples << endl;
+ short *newData = (short*) malloc(sizeof(short) * numSamples);
+ if (NULL!=temp) {
+ unsigned long copyLength = min((unsigned long)length, numSamples);
+ memcpy(newData, temp, sizeof(short) * copyLength);
+ }
+ temp = newData;
+ myDataSize = numSamples * 2;
+ length=numSamples;
+ position=0;
+ recordPosition=0;
+}
+
+void maxiSample::clear() {
+ memset(myData, 0, myDataSize);
+}
+
+void maxiSample::reset() {
+ position=0;
+}
+
+
+
+
+
+/* OK this compressor and gate are now ready to use. The envelopes, like all the envelopes in this recent update, use stupid algorithms for
+ incrementing - consequently a long attack is something like 0.0001 and a long release is like 0.9999.
+ Annoyingly, a short attack is 0.1, and a short release is 0.99. I'll sort this out laters */
+
+double maxiDyn::gate(double input, double threshold, long holdtime, double attack, double release) {
+
+ if (fabs(input)>threshold && attackphase!=1){
+ holdcount=0;
+ releasephase=0;
+ attackphase=1;
+ if(amplitude==0) amplitude=0.01;
+ }
+
+ if (attackphase==1 && amplitude<1) {
+ amplitude*=(1+attack);
+ output=input*amplitude;
+ }
+
+ if (amplitude>=1) {
+ attackphase=0;
+ holdphase=1;
+ }
+
+ if (holdcount<holdtime && holdphase==1) {
+ output=input;
+ holdcount++;
+ }
+
+ if (holdcount==holdtime) {
+ holdphase=0;
+ releasephase=1;
+ }
+
+ if (releasephase==1 && amplitude>0.) {
+ output=input*(amplitude*=release);
+
+ }
+
+ return output;
+}
+
+
+double maxiDyn::compressor(double input, double ratio, double threshold, double attack, double release) {
+
+ if (fabs(input)>threshold && attackphase!=1){
+ holdcount=0;
+ releasephase=0;
+ attackphase=1;
+ if(currentRatio==0) currentRatio=ratio;
+ }
+
+ if (attackphase==1 && currentRatio<ratio-1) {
+ currentRatio*=(1+attack);
+ }
+
+ if (currentRatio>=ratio-1) {
+ attackphase=0;
+ releasephase=1;
+ }
+
+ if (releasephase==1 && currentRatio>0.) {
+ currentRatio*=release;
+ }
+
+ if (input>0.) {
+ output = input/(1.+currentRatio);
+ } else {
+ output = input/(1.+currentRatio);
+ }
+
+ return output*(1+log(ratio));
+}
+
+
+/* Lots of people struggle with the envelope generators so here's a new easy one.
+ It takes mental numbers for attack and release tho. Basically, they're exponentials.
+ I'll map them out later so that it's a bit more intuitive */
+double maxiEnv::ar(double input, double attack, double release, long holdtime, int trigger) {
+
+ if (trigger==1 && attackphase!=1 && holdphase!=1){
+ holdcount=0;
+ releasephase=0;
+ attackphase=1;
+ }
+
+ if (attackphase==1) {
+ amplitude+=(1*attack);
+ output=input*amplitude;
+ }
+
+ if (amplitude>=1) {
+ amplitude=1;
+ attackphase=0;
+ holdphase=1;
+ }
+
+ if (holdcount<holdtime && holdphase==1) {
+ output=input;
+ holdcount++;
+ }
+
+ if (holdcount==holdtime && trigger==1) {
+ output=input;
+ }
+
+ if (holdcount==holdtime && trigger!=1) {
+ holdphase=0;
+ releasephase=1;
+ }
+
+ if (releasephase==1 && amplitude>0.) {
+ output=input*(amplitude*=release);
+
+ }
+
+ return output;
+}
+
+/* and here's a new adsr. It's not bad, very simple to use*/
+
+double maxiEnv::adsr(double input, double attack, double decay, double sustain, double release, long holdtime, int trigger) {
+
+ if (trigger==1 && attackphase!=1 && holdphase!=1 && decayphase!=1){
+ holdcount=0;
+ decayphase=0;
+ sustainphase=0;
+ releasephase=0;
+ attackphase=1;
+ }
+
+ if (attackphase==1) {
+ amplitude+=(1*attack);
+ output=input*amplitude;
+ }
+
+ if (amplitude>=1) {
+ amplitude=1;
+ attackphase=0;
+ decayphase=1;
+ }
+
+ if (decayphase==1) {
+ output=input*(amplitude*=decay);
+ if (amplitude<=sustain) {
+ decayphase=0;
+ holdphase=1;
+ }
+ }
+
+ if (holdcount<holdtime && holdphase==1) {
+ output=input*amplitude;
+ holdcount++;
+ }
+
+ if (holdcount==holdtime && trigger==1) {
+ output=input*amplitude;
+ }
+
+ if (holdcount==holdtime && trigger!=1) {
+ holdphase=0;
+ releasephase=1;
+ }
+
+ if (releasephase==1 && amplitude>0.) {
+ output=input*(amplitude*=release);
+
+ }
+
+ return output;
+}
+
+double convert::mtof(int midinote) {
+
+ return mtofarray[midinote];
+}
+
+
+void maxiEnvelopeFollower::setAttack(double attackMS) {
+ attack = pow( 0.01, 1.0 / ( attackMS * maxiSettings::sampleRate * 0.001 ) );
+}
+
+void maxiEnvelopeFollower::setRelease(double releaseMS) {
+ release = pow( 0.01, 1.0 / ( releaseMS * maxiSettings::sampleRate * 0.001 ) );
+}
+
--- /dev/null
+/*
+ * maximilian.h
+ * platform independent synthesis library using portaudio or rtaudio
+ *
+ * Created by Mick Grierson on 29/12/2009.
+ * Copyright 2009 Mick Grierson & Strangeloop Limited. All rights reserved.
+ * Thanks to the Goldsmiths Creative Computing Team.
+ * Special thanks to Arturo Castro for the PortAudio implementation.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef MAXIMILIAN_H
+#define MAXIMILIAN_H
+
+//#define MAXIMILIAN_PORTAUDIO
+#define MAXIMILIAN_RT_AUDIO
+
+
+#include <iostream>
+#include <fstream>
+#include <string.h>
+#include <cstdlib>
+#include "math.h"
+
+using namespace std;
+#ifndef PI
+#define PI 3.1415926535897932384626433832795
+#endif
+#define TWOPI 6.283185307179586476925286766559
+
+class maxiSettings {
+public:
+ static int sampleRate;
+ static int channels;
+ static int bufferSize;
+ static void setup(int initSampleRate, int initChannels, int initBufferSize) {
+ maxiSettings::sampleRate = initSampleRate;
+ maxiSettings::channels = initChannels;
+ maxiSettings::bufferSize = initBufferSize;
+ }
+};
+
+
+class maxiOsc {
+
+ double frequency;
+ double phase;
+ double startphase;
+ double endphase;
+ double output;
+ double tri;
+
+
+public:
+ maxiOsc();
+ double sinewave(double frequency);
+ double coswave(double frequency);
+ double phasor(double frequency);
+ double phasor(double frequency, double startphase, double endphase);
+ double saw(double frequency);
+ double triangle(double frequency);
+ double square(double frequency);
+ double pulse(double frequency, double duty);
+ double noise();
+ double sinebuf(double frequency);
+ double sinebuf4(double frequency);
+ double sawn(double frequency);
+ double rect(double frequency, double duty=0.5);
+ void phaseReset(double phaseIn);
+
+};
+
+
+class maxiEnvelope {
+
+ double period;
+ double output;
+ double startval;
+ double currentval;
+ double nextval;
+ int isPlaying;
+
+public:
+ double line(int numberofsegments,double segments[100]);
+ void trigger(int index,double amp);
+ int valindex;
+ double amplitude;
+
+};
+
+
+class maxiDelayline {
+ double frequency;
+ int phase;
+ double startphase;
+ double endphase;
+ double output;
+ double memory[88200];
+
+public:
+ maxiDelayline();
+ double dl(double input, int size, double feedback);
+ double dl(double input, int size, double feedback, int position);
+
+
+};
+
+
+class maxiFilter {
+ double gain;
+ double input;
+ double output;
+ double inputs[10];
+ double outputs[10];
+ double cutoff1;
+ double x;//speed
+ double y;//pos
+ double z;//pole
+ double c;//filter coefficient
+
+public:
+ maxiFilter():x(0.0), y(0.0), z(0.0), c(0.0){};
+ double cutoff;
+ double resonance;
+ double lores(double input,double cutoff1, double resonance);
+ double hires(double input,double cutoff1, double resonance);
+ double bandpass(double input,double cutoff1, double resonance);
+ double lopass(double input,double cutoff);
+ double hipass(double input,double cutoff);
+
+};
+
+class maxiMix {
+ double input;
+ double two[2];
+ double four[4];
+ double eight[8];
+public:
+ double x;
+ double y;
+ double z;
+ double *stereo(double input,double two[2],double x);
+ double *quad(double input,double four[4], double x,double y);
+ double *ambisonic(double input,double eight[8],double x,double y, double z);
+
+};
+
+//lagging with an exponential moving average
+//a lower alpha value gives a slower lag
+template <class T>
+class maxiLagExp {
+public:
+ T alpha, alphaReciprocal;
+ T val;
+
+ maxiLagExp() {
+ init(0.5, 0.0);
+ };
+
+ maxiLagExp(T initAlpha, T initVal) {
+ init(initAlpha, initVal);
+ }
+
+ void init(T initAlpha, T initVal) {
+ alpha = initAlpha;
+ alphaReciprocal = 1.0 - alpha;
+ val = initVal;
+ }
+
+ inline void addSample(T newVal) {
+ val = (alpha * newVal) + (alphaReciprocal * val);
+ }
+
+ inline T value() {
+ return val;
+ }
+};
+
+
+class maxiSample {
+
+private:
+ string myPath;
+ int myChunkSize;
+ int mySubChunk1Size;
+ int readChannel;
+ short myFormat;
+ int myByteRate;
+ short myBlockAlign;
+ short myBitsPerSample;
+ double position, recordPosition;
+ double speed;
+ double output;
+ maxiLagExp<double> loopRecordLag;
+
+public:
+ int myDataSize;
+ short myChannels;
+ int mySampleRate;
+ long length;
+ void getLength();
+ void setLength(unsigned long numSamples);
+
+
+ char* myData;
+ short* temp;
+
+ // get/set for the Path property
+
+ ~maxiSample()
+ {
+ if (myData) free(myData);
+ if (temp) free(temp);
+ printf("freeing SampleData");
+
+ }
+
+ maxiSample():myData(NULL),temp(NULL),position(0), recordPosition(0), myChannels(1), mySampleRate(maxiSettings::sampleRate) {};
+
+ bool load(string fileName, int channel=0);
+
+ bool loadOgg(string filename,int channel=0);
+
+ void trigger();
+
+ // read a wav file into this class
+ bool read();
+
+ //read an ogg file into this class using stb_vorbis
+ bool readOgg();
+
+ void loopRecord(double newSample, const bool recordEnabled, const double recordMix) {
+ loopRecordLag.addSample(recordEnabled);
+ if(recordEnabled) {
+ double currentSample = ((short*)myData)[(unsigned long)recordPosition] / 32767.0;
+ newSample = (recordMix * currentSample) + ((1.0 - recordMix) * newSample);
+ newSample *= loopRecordLag.value();
+ ((short*)myData)[(unsigned long)recordPosition] = newSample * 32767;
+ }
+ ++recordPosition;
+ if (recordPosition == length)
+ recordPosition=0;
+ }
+
+ void clear();
+
+ void reset();
+
+ double play();
+
+ double playOnce();
+
+ double playOnce(double speed);
+
+ double play(double speed);
+
+ double play(double frequency, double start, double end, double &pos);
+
+ double play(double frequency, double start, double end);
+
+ double play4(double frequency, double start, double end);
+
+ double bufferPlay(unsigned char &bufferin,long length);
+
+ double bufferPlay(unsigned char &bufferin,double speed,long length);
+
+ double bufferPlay(unsigned char &bufferin,double frequency, double start, double end);
+
+ double bufferPlay4(unsigned char &bufferin,double frequency, double start, double end);
+ bool save() {
+ save(myPath);
+ }
+
+ bool save(string filename)
+ {
+ fstream myFile (filename.c_str(), ios::out | ios::binary);
+
+ // write the wav file per the wav file format
+ myFile.seekp (0, ios::beg);
+ myFile.write ("RIFF", 4);
+ myFile.write ((char*) &myChunkSize, 4);
+ myFile.write ("WAVE", 4);
+ myFile.write ("fmt ", 4);
+ myFile.write ((char*) &mySubChunk1Size, 4);
+ myFile.write ((char*) &myFormat, 2);
+ myFile.write ((char*) &myChannels, 2);
+ myFile.write ((char*) &mySampleRate, 4);
+ myFile.write ((char*) &myByteRate, 4);
+ myFile.write ((char*) &myBlockAlign, 2);
+ myFile.write ((char*) &myBitsPerSample, 2);
+ myFile.write ("data", 4);
+ myFile.write ((char*) &myDataSize, 4);
+ myFile.write (myData, myDataSize);
+
+ return true;
+ }
+
+ // return a printable summary of the wav file
+ char *getSummary()
+ {
+ char *summary = new char[250];
+ sprintf(summary, " Format: %d\n Channels: %d\n SampleRate: %d\n ByteRate: %d\n BlockAlign: %d\n BitsPerSample: %d\n DataSize: %d\n", myFormat, myChannels, mySampleRate, myByteRate, myBlockAlign, myBitsPerSample, myDataSize);
+ std::cout << myDataSize;
+ return summary;
+ }
+};
+
+
+class maxiMap {
+public:
+ static double inline linlin(double val, double inMin, double inMax, double outMin, double outMax) {
+ return ((val - inMin) / (inMax - inMin) * (outMax - outMin)) + outMin;
+ }
+
+ static double inline linexp(double val, double inMin, double inMax, double outMin, double outMax) {
+ //clipping
+ val = max(min(val, inMax), inMin);
+ return pow((outMax / outMin), (val - inMin) / (inMax - inMin)) * outMin;
+ }
+
+ static double inline explin(double val, double inMin, double inMax, double outMin, double outMax) {
+ //clipping
+ val = max(min(val, inMax), inMin);
+ return (log(val/inMin) / log(inMax/inMin) * (outMax - outMin)) + outMin;
+ }
+
+ static int inline clamp(int v, const int low, const int high) {
+ v = min(high, v);
+ v = max(low, v);
+ return v;
+ }
+
+};
+
+
+class maxiDyn {
+
+
+public:
+ double gate(double input, double threshold=0.9, long holdtime=1, double attack=1, double release=0.9995);
+ double compressor(double input, double ratio, double threshold=0.9, double attack=1, double release=0.9995);
+ double input;
+ double ratio;
+ double currentRatio;
+ double threshold;
+ double output;
+ double attack;
+ double release;
+ double amplitude;
+ long holdtime;
+ long holdcount;
+ int attackphase,holdphase,releasephase;
+};
+
+class maxiEnv {
+
+
+public:
+ double ar(double input, double attack=1, double release=0.9, long holdtime=1, int trigger=0);
+ double adsr(double input, double attack=1, double decay=0.99, double sustain=0.125, double release=0.9, long holdtime=1, int trigger=0);
+ double input;
+ double output;
+ double attack;
+ double decay;
+ double sustain;
+ double release;
+ double amplitude;
+ int trigger;
+ long holdtime;
+ long holdcount;
+ int attackphase,decayphase,sustainphase,holdphase,releasephase;
+};
+
+class convert {
+public:
+ double mtof(int midinote);
+};
+
+
+
+class maxiDistortion {
+public:
+ /*atan distortion, see http://www.musicdsp.org/showArchiveComment.php?ArchiveID=104*/
+ /*shape from 1 (soft clipping) to infinity (hard clipping)*/
+ double atanDist(const double in, const double shape);
+ double fastAtanDist(const double in, const double shape);
+ double fastatan( double x );
+};
+
+inline double maxiDistortion::fastatan(double x)
+{
+ return (x / (1.0 + 0.28 * (x * x)));
+}
+
+inline double maxiDistortion::atanDist(const double in, const double shape) {
+ double out;
+ out = (1.0 / atan(shape)) * atan(in * shape);
+ return out;
+}
+
+inline double maxiDistortion::fastAtanDist(const double in, const double shape) {
+ double out;
+ out = (1.0 / fastatan(shape)) * fastatan(in * shape);
+ return out;
+}
+
+
+class maxiFlanger {
+public:
+ //delay = delay time - ~800 sounds good
+ //feedback = 0 - 1
+ //speed = lfo speed in Hz, 0.0001 - 10 sounds good
+ //depth = 0 - 1
+ double flange(const double input, const unsigned int delay, const double feedback, const double speed, const double depth);
+ maxiDelayline dl;
+ maxiOsc lfo;
+
+};
+
+inline double maxiFlanger::flange(const double input, const unsigned int delay, const double feedback, const double speed, const double depth)
+{
+ //todo: needs fixing
+ double output;
+ double lfoVal = lfo.triangle(speed);
+ output = dl.dl(input, delay + (lfoVal * depth * delay) + 1, feedback) ;
+ double normalise = (1 - fabs(output));
+ output *= normalise;
+ return (output + input) / 2.0;
+}
+
+class maxiChorus {
+public:
+ //delay = delay time - ~800 sounds good
+ //feedback = 0 - 1
+ //speed = lfo speed in Hz, 0.0001 - 10 sounds good
+ //depth = 0 - 1
+ double chorus(const double input, const unsigned int delay, const double feedback, const double speed, const double depth);
+ maxiDelayline dl, dl2;
+ maxiOsc lfo;
+ maxiFilter lopass;
+
+};
+
+inline double maxiChorus::chorus(const double input, const unsigned int delay, const double feedback, const double speed, const double depth)
+{
+ //this needs fixing
+ double output1, output2;
+ double lfoVal = lfo.noise();
+ lfoVal = lopass.lores(lfoVal, speed, 1.0) * 2.0;
+ output1 = dl.dl(input, delay + (lfoVal * depth * delay) + 1, feedback) ;
+ output2 = dl2.dl(input, (delay + (lfoVal * depth * delay * 1.02) + 1) * 0.98, feedback * 0.99) ;
+ output1 *= (1.0 - fabs(output1));
+ output2 *= (1.0 - fabs(output2));
+ return (output1 + output2 + input) / 3.0;
+}
+
+class maxiEnvelopeFollower {
+public:
+ maxiEnvelopeFollower() {
+ setAttack(100);
+ setRelease(100);
+ env = 0;
+ }
+ void setAttack(double attackMS);
+ void setRelease(double releaseMS);
+ inline double play(double input) {
+ input = fabs(input);
+ if (input>env)
+ env = attack * (env - input) + input;
+ else
+ env = release * (env - input) + input;
+ return env;
+ }
+ void reset() {env=0;}
+private:
+ double attack, release, env;
+};
+
+
+#endif
--- /dev/null
+---
+The Synthesis ToolKit in C++ (STK)
+http://ccrma.stanford.edu/software/stk/
+
+By Perry R. Cook and Gary P. Scavone, 1995-2010.
+
+See README (contains original README from STK).
+
+---
+MoMu-STK (for iPhone, iPad, iPod Touch)
+
+authors:
+ Nicholas J. Bryan (njb@ccrma.stanford.edu)
+
+as part of the MoMu toolkit, co-created by:
+ Jorge Herrera (jorgeh@ccrma.stanford.edu)
+ Jieun Oh (jieun5@ccrma.stanford.edu)
+ Ge Wang (ge@ccrma.stanford.edu)
+
+ date: October 2009
+ version: 1.0.0
+
+---
+ MoMu STK:
+ http://momu.stanford.edu/stk/
+
+ Mobile Music Research at CCRMA:
+ http://momu.stanford.edu/
+
+ Music, Computing, and Design Research Group:
+ http://ccrma.stanford.edu/groups/mcd/
+
--- /dev/null
+See README
\ No newline at end of file
--- /dev/null
+---
+Please check out the MoMu STK and toolkit page:
+
+ http://momu.stanford.edu/stk/
+ http://momu.stanford.edu/toolkit/
+---
--- /dev/null
+As this current release of MoMu STK targets the iPhone platform,
+and the spirit of this toolkit to enable developers to rapidly
+develop sweet interactive audio applications, we'll leave the
+installation up to you. In some cases, you might simply want
+include a particular module, in which you only need to bring
+in or reference the associated files.
+
+We hope you find this useful! Have fun with it!
+
+All the best,
+Nick
--- /dev/null
+-----------------------------------------------------------------------
+The STK (MoMu release) is a slightly modified version of The Synthesis
+ToolKit in C++ (STK) by Perry R. Cook and Gary P. Scavone, 1995-2010.
+Slight modifications for iPhone OS by Nicholas J. Bryan (October 2009)
+as part of the MoMu project with Jorge Herrera, Jieun Oh, and Ge Wang
+(see http://momu.stanford.edu/). See VERSIONS and AUTHORS for more
+information. The original STK README (license, etc.) can be found below.
+All licensing or similar issues follow from the original license as
+specified by Perry R. Cook and Gary P. Scavone.
+-----------------------------------------------------------------------
+
+The Synthesis ToolKit in C++ (STK)
+
+By Perry R. Cook and Gary P. Scavone, 1995-2010.
+
+---
+This distribution of the Synthesis ToolKit in C++ (STK) contains the following:
+
+include: STK class header files
+src: STK class source files
+rawwaves: STK audio files (1-channel, 16-bit, big-endian)
+doc: STK documentation
+projects: example STK projects and programs
+
+Please read the Legal and Ethical notes near the bottom of this document.
+
+For compiling and installing STK, see the INSTALL file in this directory.
+
+OVERVIEW:
+
+The Synthesis ToolKit in C++ (STK) is a set of open source audio
+signal processing and algorithmic synthesis classes written in the C++
+programming language. STK was designed to facilitate rapid
+development of music synthesis and audio processing software, with an
+emphasis on cross-platform functionality, realtime control, ease of
+use, and educational example code. The Synthesis ToolKit is extremely
+portable (it's mostly platform-independent C and C++ code), and it's
+completely user-extensible (all source included, no unusual libraries,
+and no hidden drivers). We like to think that this increases the
+chances that our programs will still work in another 5-10 years. In
+fact, the ToolKit has been working continuously for nearly 15 years
+now. STK currently runs with "realtime" support (audio and MIDI) on
+Linux, Macintosh OS X, and Windows computer platforms. Generic,
+non-realtime support has been tested under NeXTStep, Sun, and other
+platforms and should work with any standard C++ compiler.
+
+The Synthesis ToolKit is free for non-commercial use. The only parts
+of the Synthesis ToolKit that are platform-dependent concern real-time
+audio and MIDI input and output, and that is taken care of with a few
+special classes. The interface for MIDI input and the simple Tcl/Tk
+graphical user interfaces (GUIs) provided is the same, so it's easy to
+experiment in real time using either the GUIs or MIDI. The Synthesis
+ToolKit can generate simultaneous SND (AU), WAV, AIFF, and MAT-file
+output soundfile formats (as well as realtime sound output), so you
+can view your results using one of a large variety of sound/signal
+analysis tools already available (e.g. Snd, Cool Edit, Matlab).
+
+The Synthesis Toolkit is not one particular program. Rather, it is a
+set of C++ classes that you can use to create your own programs. A
+few example applications are provided to demonstrate some of the ways
+to use the classes. If you have specific needs, you will probably
+have to either modify the example programs or write a new program
+altogether. Further, the example programs don't have a fancy GUI
+wrapper. If you feel the need to have a "drag and drop" graphical
+patching GUI, you probably don't want to use the ToolKit. Spending
+hundreds of hours making platform-dependent graphics code would go
+against one of the fundamental design goals of the ToolKit - platform
+independence.
+
+For those instances where a simple GUI with sliders and buttons is
+helpful, we use Tcl/Tk (http://dev.scriptics.com) which is freely
+distributed for all the supported ToolKit platforms. A number of
+Tcl/Tk GUI scripts are distributed with the ToolKit release. For
+control, the Synthesis Toolkit uses raw MIDI (on supported platforms),
+and SKINI (Synthesis ToolKit Instrument Network Interface, a MIDI-like
+text message synthesis control format).
+
+
+SYSTEM REQUIREMENTS:
+
+See the individual README's (eg. README-linux) in the /doc directory
+for platform specific information and system requirements. In
+general, you will use the configure script to create Makefiles on unix
+platforms (and MinGW) or the VC++ workspace files to compile the
+example programs. To use the Tcl/Tk GUIs, you will need Tcl/Tk
+version 8.0 or higher.
+
+
+WHAT'S NEW (AND NOT SO NEW):
+
+Despite being available in one form or another since 1996, we still
+consider STK to be alpha software. We attempt to maintain backward
+compatability but changes are sometimes made in an effort to improve
+the overall design or performance of the software. Please read the
+Release Notes to see what has changed since the last release.
+
+A new StkFrames class has been created to facilitate the handling and
+passing of multichannel, vectorized audio data. All STK classes have
+been updated to include tick() functions that accept StkFrames
+arguments.
+
+The control message handling scheme has been simplified greatly
+through the use of the Messager class. It is now possible to have
+access to simultaneous piped, socketed, and/or MIDI input control
+messages. In most cases, this should eliminate the use of the
+Md2Skini program.
+
+Realtime audio input capabilities were added to STK with release 3.0,
+though the behavior of such is very hardware dependent. Under Linux,
+Macintosh OS-X, and Irix, audio input and output are possible with
+very low latency. Using the Windoze DirectSound API, minimum
+dependable output sound latency seems to be around 20 milliseconds or
+so, while input sound latency is on the order of a hundred
+milliseconds or more!
+
+As mentioned above, it is possible to record the audio ouput of an STK
+program to .snd, .wav, .raw, .aif, and .mat (Matlab MAT-file) output
+file types. Though somewhat obsolete, the program Md2Skini can be
+used to write SKINI scorefiles from realtime MIDI input. Finally, STK
+should compile with non-realtime functionality on any platform with a
+generic C++ compiler.
+
+For those who wish to make a library from the core STK classes, the
+configure script generates a Makefile in the src directory that will
+accomplish that (Linux, SGI, and Macintosh OS X only).
+
+
+DISCLAIMER:
+
+You probably already guessed this, but just to be sure, we don't
+guarantee anything works. :-) It's free ... what do you expect? If
+you find a bug, please let us know and we'll try to correct it. You
+can also make suggestions, but again, no guarantees. Send email to
+the mail list.
+
+
+LEGAL AND ETHICAL:
+
+This software was designed and created to be made publicly available
+for free, primarily for academic purposes, so if you use it, pass it
+on with this documentation, and for free.
+
+If you make a million dollars with it, it would be nice if you would
+share. If you make compositions with it, put us in the program notes.
+
+Some of the concepts are covered by various patents, some known to us
+and likely others which are unknown. Many of the ones known to us are
+administered by the Stanford Office of Technology and Licensing.
+
+The good news is that large hunks of the techniques used here are
+public domain. To avoid subtle legal issues, we'll not state what's
+freely useable here, but we'll try to note within the various classes
+where certain things are likely to be protected by patents.
+
+LICENSE:
+
+STK WWW site: http://ccrma.stanford.edu/software/stk/
+
+The Synthesis ToolKit in C++ (STK)
+Copyright (c) 1995-2010 Perry R. Cook and Gary P. Scavone
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+Any person wishing to distribute modifications to the Software is
+asked to send the modifications to the original developer so that they
+can be incorporated into the canonical version. This is, however, not
+a binding provision of this license.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+FURTHER READING:
+
+For complete documentation on this ToolKit, the classes, etc., see the
+doc directory of the distribution or surf to
+http://ccrma.stanford.edu/software/stk/. Also check the platform
+specific README's for specific system requirements.
+
+
+PERRY'S NOTES FROM THE ORIGINAL DISTRIBUTION:
+
+This whole world was created with no particular hardware in mind.
+These examples are intended to be tutorial in nature, as a platform
+for the continuation of my research, and as a possible starting point
+for a software synthesis system. The basic motivation was to create
+the necessary unit generators to do the synthesis, processing, and
+control that I want to do and teach about. Little thought for
+optimization was given and therefore improvements, especially speed
+enhancements, should be possible with these classes. It was written
+with some basic concepts in mind about how to let compilers optimize.
+
+Your question at this point might be, "But Perry, with CMix, CMusic,
+CSound, CShells, CMonkeys, etc. already cluttering the landscape, why
+a new set of stupid C functions for music synthesis and processing?"
+The answers lie below.
+
+1) I needed to port many of the things I've done into something which is generic enough to port further to different machines.
+
+2) I really plan to document this stuff, so that you don't have to be me to figure out what's going on. (I'll probably be sorry I said this in a couple of years, when even I can't figure out what I was thinking.)
+
+3) The classic difficulties most people have in trying to implement physical models are:
+
+ A) They have trouble understanding the papers, and/or in turning the theory into practice.
+
+ B) The Physical Model instruments are a pain to get to oscillate, and coming up with stable and meaningful parameter values is required to get the models to work at all.
+
+ This set of C++ unit generators and instruments might help to diminish the scores of emails I get asking what to do with those block diagrams I put in my papers.
+
+4) I wanted to try some new stuff with modal synthesis, and implement some classic FM patches as well.
+
+5) I wanted to reimplement, and newly implement more of the intelligent and physical performer models I've talked about in some of my papers. But I wanted to do it in a portable way, and in such a way that I can hook up modules quickly. I also wanted to make these instruments connectable to such player objects, so folks like Brad Garton who really think a lot about the players can connect them to my instruments, a lot about which I think.
+
+6) More rationalizations to follow . . .
+
+
+
+
--- /dev/null
+- Connect MoAudio (from MoMu) to RtWvIn.h/cpp and RtWvOut.h/cpp
\ No newline at end of file
--- /dev/null
+---
+MoMu STK-1.0.0
+ - initial release based on STK 4.4.2!
+ - includes everything in STK 4.4.2 except:
+ -RtAudio.h/cpp
+ -RtError.h
+ -RtMidi.h/cpp
+ -RtWvIn.h/cpp
+ -RtWvOut.h/cpp
+ - slight modifications were made to:
+ -Stk.h
+ -Stk.cpp -> Stk.mm
+ -UdpSocket.h/cpp -> StkUdpSocket.h/cpp
+ -makefunc.c
+ -makemidi.c
+ -makewavs.c
+ -sine.c
+
--- /dev/null
+#ifndef STK_ADSR_H
+#define STK_ADSR_H
+
+#include "Generator.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class ADSR
+ \brief STK ADSR envelope class.
+
+ This class implements a traditional ADSR (Attack, Decay, Sustain,
+ Release) envelope. It responds to simple keyOn and keyOff
+ messages, keeping track of its state. The \e state = ADSR::DONE
+ after the envelope value reaches 0.0 in the ADSR::RELEASE state.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class ADSR : public Generator
+{
+ public:
+
+ //! ADSR envelope states.
+ enum {
+ ATTACK, /*!< Attack */
+ DECAY, /*!< Decay */
+ SUSTAIN, /*!< Sustain */
+ RELEASE, /*!< Release */
+ DONE /*!< End of release */
+ };
+
+ //! Default constructor.
+ ADSR( void );
+
+ //! Class destructor.
+ ~ADSR( void );
+
+ //! Set target = 1, state = \e ADSR::ATTACK.
+ void keyOn( void );
+
+ //! Set target = 0, state = \e ADSR::RELEASE.
+ void keyOff( void );
+
+ //! Set the attack rate.
+ void setAttackRate( StkFloat rate );
+
+ //! Set the decay rate.
+ void setDecayRate( StkFloat rate );
+
+ //! Set the sustain level.
+ void setSustainLevel( StkFloat level );
+
+ //! Set the release rate.
+ void setReleaseRate( StkFloat rate );
+
+ //! Set the attack rate based on a time duration.
+ void setAttackTime( StkFloat time );
+
+ //! Set the decay rate based on a time duration.
+ void setDecayTime( StkFloat time );
+
+ //! Set the release rate based on a time duration.
+ void setReleaseTime( StkFloat time );
+
+ //! Set sustain level and attack, decay, and release time durations.
+ void setAllTimes( StkFloat aTime, StkFloat dTime, StkFloat sLevel, StkFloat rTime );
+
+ //! Set the target value.
+ void setTarget( StkFloat target );
+
+ //! Return the current envelope \e state (ATTACK, DECAY, SUSTAIN, RELEASE, DONE).
+ int getState( void ) const { return state_; };
+
+ //! Set to state = ADSR::SUSTAIN with current and target values of \e value.
+ void setValue( StkFloat value );
+
+ //! Return the last computed output value.
+ StkFloat lastOut( void ) const { return lastFrame_[0]; };
+
+ //! Compute and return one output sample.
+ StkFloat tick( void );
+
+ //! Fill a channel of the StkFrames object with computed outputs.
+ /*!
+ The \c channel argument must be less than the number of
+ channels in the StkFrames argument (the first channel is specified
+ by 0). However, range checking is only performed if _STK_DEBUG_
+ is defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
+
+ protected:
+
+ void sampleRateChanged( StkFloat newRate, StkFloat oldRate );
+
+ int state_;
+ StkFloat value_;
+ StkFloat target_;
+ StkFloat attackRate_;
+ StkFloat decayRate_;
+ StkFloat releaseRate_;
+ StkFloat sustainLevel_;
+};
+
+inline StkFloat ADSR :: tick( void )
+{
+ switch ( state_ ) {
+
+ case ATTACK:
+ value_ += attackRate_;
+ if ( value_ >= target_ ) {
+ value_ = target_;
+ target_ = sustainLevel_;
+ state_ = DECAY;
+ }
+ lastFrame_[0] = value_;
+ break;
+
+ case DECAY:
+ value_ -= decayRate_;
+ if ( value_ <= sustainLevel_ ) {
+ value_ = sustainLevel_;
+ state_ = SUSTAIN;
+ }
+ lastFrame_[0] = value_;
+ break;
+
+ case RELEASE:
+ value_ -= releaseRate_;
+ if ( value_ <= 0.0 ) {
+ value_ = (StkFloat) 0.0;
+ state_ = DONE;
+ }
+ lastFrame_[0] = value_;
+
+ }
+
+ return value_;
+}
+
+inline StkFrames& ADSR :: tick( StkFrames& frames, unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel >= frames.channels() ) {
+ errorString_ << "ADSR::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *samples = &frames[channel];
+ unsigned int hop = frames.channels();
+ for ( unsigned int i=0; i<frames.frames(); i++, samples += hop )
+ *samples = ADSR::tick();
+
+ return frames;
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_ASYMP_H
+#define STK_ASYMP_H
+
+#include "Generator.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class Asymp
+ \brief STK asymptotic curve envelope class
+
+ This class implements a simple envelope generator
+ which asymptotically approaches a target value.
+ The algorithm used is of the form:
+
+ y[n] = a y[n-1] + (1-a) target,
+
+ where a = exp(-T/tau), T is the sample period, and
+ tau is a time constant. The user can set the time
+ constant (default value = 0.3) and target value.
+ Theoretically, this recursion never reaches its
+ target, though the calculations in this class are
+ stopped when the current value gets within a small
+ threshold value of the target (at which time the
+ current value is set to the target). It responds
+ to \e keyOn and \e keyOff messages by ramping to
+ 1.0 on keyOn and to 0.0 on keyOff.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+const StkFloat TARGET_THRESHOLD = 0.000001;
+
+class Asymp : public Generator
+{
+ public:
+
+ //! Default constructor.
+ Asymp( void );
+
+ //! Class destructor.
+ ~Asymp( void );
+
+ //! Set target = 1.
+ void keyOn( void );
+
+ //! Set target = 0.
+ void keyOff( void );
+
+ //! Set the asymptotic rate via the time factor \e tau (must be > 0).
+ /*!
+ The rate is computed as described above. The value of \e tau
+ must be greater than zero. Values of \e tau close to zero produce
+ fast approach rates, while values greater than 1.0 produce rather
+ slow rates.
+ */
+ void setTau( StkFloat tau );
+
+ //! Set the asymptotic rate based on a time duration (must be > 0).
+ void setTime( StkFloat time );
+
+ //! Set the target value.
+ void setTarget( StkFloat target );
+
+ //! Set current and target values to \e value.
+ void setValue( StkFloat value );
+
+ //! Return the current envelope \e state (0 = at target, 1 otherwise).
+ int getState( void ) const { return state_; };
+
+ //! Return the last computed output value.
+ StkFloat lastOut( void ) const { return lastFrame_[0]; };
+
+ //! Compute and return one output sample.
+ StkFloat tick( void );
+
+ //! Fill a channel of the StkFrames object with computed outputs.
+ /*!
+ The \c channel argument must be less than the number of
+ channels in the StkFrames argument (the first channel is specified
+ by 0). However, range checking is only performed if _STK_DEBUG_
+ is defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
+
+ protected:
+
+ void sampleRateChanged( StkFloat newRate, StkFloat oldRate );
+
+ StkFloat value_;
+ StkFloat target_;
+ StkFloat factor_;
+ StkFloat constant_;
+ int state_;
+};
+
+inline StkFloat Asymp :: tick( void )
+{
+ if ( state_ ) {
+
+ value_ = factor_ * value_ + constant_;
+
+ // Check threshold.
+ if ( target_ > value_ ) {
+ if ( target_ - value_ <= TARGET_THRESHOLD ) {
+ value_ = target_;
+ state_ = 0;
+ }
+ }
+ else {
+ if ( value_ - target_ <= TARGET_THRESHOLD ) {
+ value_ = target_;
+ state_ = 0;
+ }
+ }
+ lastFrame_[0] = value_;
+ }
+
+ return value_;
+}
+
+inline StkFrames& Asymp :: tick( StkFrames& frames, unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel >= frames.channels() ) {
+ errorString_ << "Asymp::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *samples = &frames[channel];
+ unsigned int hop = frames.channels();
+ for ( unsigned int i=0; i<frames.frames(); i++, samples += hop )
+ *samples = Asymp::tick();
+
+ return frames;
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_BANDEDWG_H
+#define STK_BANDEDWG_H
+
+#include "Instrmnt.h"
+#include "DelayL.h"
+#include "BowTable.h"
+#include "ADSR.h"
+#include "BiQuad.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class BandedWG
+ \brief Banded waveguide modeling class.
+
+ This class uses banded waveguide techniques to
+ model a variety of sounds, including bowed
+ bars, glasses, and bowls. For more
+ information, see Essl, G. and Cook, P. "Banded
+ Waveguides: Towards Physical Modelling of Bar
+ Percussion Instruments", Proceedings of the
+ 1999 International Computer Music Conference.
+
+ Control Change Numbers:
+ - Bow Pressure = 2
+ - Bow Motion = 4
+ - Strike Position = 8 (not implemented)
+ - Vibrato Frequency = 11
+ - Gain = 1
+ - Bow Velocity = 128
+ - Set Striking = 64
+ - Instrument Presets = 16
+ - Uniform Bar = 0
+ - Tuned Bar = 1
+ - Glass Harmonica = 2
+ - Tibetan Bowl = 3
+
+ by Georg Essl, 1999 - 2004.
+ Modified for STK 4.0 by Gary Scavone.
+*/
+/***************************************************/
+
+const int MAX_BANDED_MODES = 20;
+
+class BandedWG : public Instrmnt
+{
+ public:
+ //! Class constructor.
+ BandedWG( void );
+
+ //! Class destructor.
+ ~BandedWG( void );
+
+ //! Reset and clear all internal state.
+ void clear( void );
+
+ //! Set strike position (0.0 - 1.0).
+ void setStrikePosition( StkFloat position );
+
+ //! Select a preset.
+ void setPreset( int preset );
+
+ //! Set instrument parameters for a particular frequency.
+ void setFrequency( StkFloat frequency );
+
+ //! Apply bow velocity/pressure to instrument with given amplitude and rate of increase.
+ void startBowing( StkFloat amplitude, StkFloat rate );
+
+ //! Decrease bow velocity/breath pressure with given rate of decrease.
+ void stopBowing( StkFloat rate );
+
+ //! Pluck the instrument with given amplitude.
+ void pluck( StkFloat amp );
+
+ //! Start a note with the given frequency and amplitude.
+ void noteOn( StkFloat frequency, StkFloat amplitude );
+
+ //! Stop a note with the given amplitude (speed of decay).
+ void noteOff( StkFloat amplitude );
+
+ //! Perform the control change specified by \e number and \e value (0.0 - 128.0).
+ void controlChange( int number, StkFloat value );
+
+ //! Compute and return one output sample.
+ StkFloat tick( unsigned int channel = 0 );
+
+ protected:
+
+ bool doPluck_;
+ bool trackVelocity_;
+ int nModes_;
+ int presetModes_;
+ BowTable bowTable_;
+ ADSR adsr_;
+ BiQuad bandpass_[MAX_BANDED_MODES];
+ DelayL delay_[MAX_BANDED_MODES];
+ StkFloat maxVelocity_;
+ StkFloat modes_[MAX_BANDED_MODES];
+ StkFloat frequency_;
+ StkFloat baseGain_;
+ StkFloat gains_[MAX_BANDED_MODES];
+ StkFloat basegains_[MAX_BANDED_MODES];
+ StkFloat excitation_[MAX_BANDED_MODES];
+ StkFloat integrationConstant_;
+ StkFloat velocityInput_;
+ StkFloat bowVelocity_;
+ StkFloat bowTarget_;
+ StkFloat bowPosition_;
+ StkFloat strikeAmp_;
+ int strikePosition_;
+
+};
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_BEETHREE_H
+#define STK_BEETHREE_H
+
+#include "FM.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class BeeThree
+ \brief STK Hammond-oid organ FM synthesis instrument.
+
+ This class implements a simple 4 operator
+ topology, also referred to as algorithm 8 of
+ the TX81Z.
+
+ \code
+ Algorithm 8 is :
+ 1 --.
+ 2 -\|
+ +-> Out
+ 3 -/|
+ 4 --
+ \endcode
+
+ Control Change Numbers:
+ - Operator 4 (feedback) Gain = 2
+ - Operator 3 Gain = 4
+ - LFO Speed = 11
+ - LFO Depth = 1
+ - ADSR 2 & 4 Target = 128
+
+ The basic Chowning/Stanford FM patent expired
+ in 1995, but there exist follow-on patents,
+ mostly assigned to Yamaha. If you are of the
+ type who should worry about this (making
+ money) worry away.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class BeeThree : public FM
+{
+ public:
+ //! Class constructor.
+ /*!
+ An StkError will be thrown if the rawwave path is incorrectly set.
+ */
+ BeeThree( void );
+
+ //! Class destructor.
+ ~BeeThree( void );
+
+ //! Start a note with the given frequency and amplitude.
+ void noteOn( StkFloat frequency, StkFloat amplitude );
+
+ //! Compute and return one output sample.
+ StkFloat tick( unsigned int channel = 0 );
+
+ protected:
+
+};
+
+inline StkFloat BeeThree :: tick( unsigned int )
+{
+ register StkFloat temp;
+
+ if ( modDepth_ > 0.0 ) {
+ temp = 1.0 + ( modDepth_ * vibrato_.tick() * 0.1 );
+ waves_[0]->setFrequency( baseFrequency_ * temp * ratios_[0] );
+ waves_[1]->setFrequency( baseFrequency_ * temp * ratios_[1] );
+ waves_[2]->setFrequency( baseFrequency_ * temp * ratios_[2] );
+ waves_[3]->setFrequency( baseFrequency_ * temp * ratios_[3] );
+ }
+
+ waves_[3]->addPhaseOffset( twozero_.lastOut() );
+ temp = control1_ * 2.0 * gains_[3] * adsr_[3]->tick() * waves_[3]->tick();
+ twozero_.tick( temp );
+
+ temp += control2_ * 2.0 * gains_[2] * adsr_[2]->tick() * waves_[2]->tick();
+ temp += gains_[1] * adsr_[1]->tick() * waves_[1]->tick();
+ temp += gains_[0] * adsr_[0]->tick() * waves_[0]->tick();
+
+ lastFrame_[0] = temp * 0.125;
+ return lastFrame_[0];
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_BIQUAD_H
+#define STK_BIQUAD_H
+
+#include "Filter.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class BiQuad
+ \brief STK biquad (two-pole, two-zero) filter class.
+
+ This class implements a two-pole, two-zero digital filter.
+ Methods are provided for creating a resonance or notch in the
+ frequency response while maintaining a constant filter gain.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class BiQuad : public Filter
+{
+public:
+
+ //! Default constructor creates a second-order pass-through filter.
+ BiQuad();
+
+ //! Class destructor.
+ ~BiQuad();
+
+ //! A function to enable/disable the automatic updating of class data when the STK sample rate changes.
+ void ignoreSampleRateChange( bool ignore = true ) { ignoreSampleRateChange_ = ignore; };
+
+ //! Set all filter coefficients.
+ void setCoefficients( StkFloat b0, StkFloat b1, StkFloat b2, StkFloat a1, StkFloat a2, bool clearState = false );
+
+ //! Set the b[0] coefficient value.
+ void setB0( StkFloat b0 ) { b_[0] = b0; };
+
+ //! Set the b[1] coefficient value.
+ void setB1( StkFloat b1 ) { b_[1] = b1; };
+
+ //! Set the b[2] coefficient value.
+ void setB2( StkFloat b2 ) { b_[2] = b2; };
+
+ //! Set the a[1] coefficient value.
+ void setA1( StkFloat a1 ) { a_[1] = a1; };
+
+ //! Set the a[2] coefficient value.
+ void setA2( StkFloat a2 ) { a_[2] = a2; };
+
+ //! Sets the filter coefficients for a resonance at \e frequency (in Hz).
+ /*!
+ This method determines the filter coefficients corresponding to
+ two complex-conjugate poles with the given \e frequency (in Hz)
+ and \e radius from the z-plane origin. If \e normalize is true,
+ the filter zeros are placed at z = 1, z = -1, and the coefficients
+ are then normalized to produce a constant unity peak gain
+ (independent of the filter \e gain parameter). The resulting
+ filter frequency response has a resonance at the given \e
+ frequency. The closer the poles are to the unit-circle (\e radius
+ close to one), the narrower the resulting resonance width.
+ */
+ void setResonance( StkFloat frequency, StkFloat radius, bool normalize = false );
+
+ //! Set the filter coefficients for a notch at \e frequency (in Hz).
+ /*!
+ This method determines the filter coefficients corresponding to
+ two complex-conjugate zeros with the given \e frequency (in Hz)
+ and \e radius from the z-plane origin. No filter normalization
+ is attempted.
+ */
+ void setNotch( StkFloat frequency, StkFloat radius );
+
+ //! Sets the filter zeroes for equal resonance gain.
+ /*!
+ When using the filter as a resonator, zeroes places at z = 1, z
+ = -1 will result in a constant gain at resonance of 1 / (1 - R),
+ where R is the pole radius setting.
+
+ */
+ void setEqualGainZeroes( void );
+
+ //! Return the last computed output value.
+ StkFloat lastOut( void ) const { return lastFrame_[0]; };
+
+ //! Input one sample to the filter and return a reference to one output.
+ StkFloat tick( StkFloat input );
+
+ //! Take a channel of the StkFrames object as inputs to the filter and replace with corresponding outputs.
+ /*!
+ The StkFrames argument reference is returned. The \c channel
+ argument must be less than the number of channels in the
+ StkFrames argument (the first channel is specified by 0).
+ However, range checking is only performed if _STK_DEBUG_ is
+ defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
+
+ //! Take a channel of the \c iFrames object as inputs to the filter and write outputs to the \c oFrames object.
+ /*!
+ The \c iFrames object reference is returned. Each channel
+ argument must be less than the number of channels in the
+ corresponding StkFrames argument (the first channel is specified
+ by 0). However, range checking is only performed if _STK_DEBUG_
+ is defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& iFrames, StkFrames &oFrames, unsigned int iChannel = 0, unsigned int oChannel = 0 );
+
+ protected:
+
+ virtual void sampleRateChanged( StkFloat newRate, StkFloat oldRate );
+};
+
+inline StkFloat BiQuad :: tick( StkFloat input )
+{
+ inputs_[0] = gain_ * input;
+ lastFrame_[0] = b_[0] * inputs_[0] + b_[1] * inputs_[1] + b_[2] * inputs_[2];
+ lastFrame_[0] -= a_[2] * outputs_[2] + a_[1] * outputs_[1];
+ inputs_[2] = inputs_[1];
+ inputs_[1] = inputs_[0];
+ outputs_[2] = outputs_[1];
+ outputs_[1] = lastFrame_[0];
+
+ return lastFrame_[0];
+}
+
+inline StkFrames& BiQuad :: tick( StkFrames& frames, unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel >= frames.channels() ) {
+ errorString_ << "BiQuad::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *samples = &frames[channel];
+ unsigned int hop = frames.channels();
+ for ( unsigned int i=0; i<frames.frames(); i++, samples += hop ) {
+ inputs_[0] = gain_ * *samples;
+ *samples = b_[0] * inputs_[0] + b_[1] * inputs_[1] + b_[2] * inputs_[2];
+ *samples -= a_[2] * outputs_[2] + a_[1] * outputs_[1];
+ inputs_[2] = inputs_[1];
+ inputs_[1] = inputs_[0];
+ outputs_[2] = outputs_[1];
+ outputs_[1] = *samples;
+ }
+
+ lastFrame_[0] = outputs_[1];
+ return frames;
+}
+
+inline StkFrames& BiQuad :: tick( StkFrames& iFrames, StkFrames& oFrames, unsigned int iChannel, unsigned int oChannel )
+{
+#if defined(_STK_DEBUG_)
+ if ( iChannel >= iFrames.channels() || oChannel >= oFrames.channels() ) {
+ errorString_ << "BiQuad::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *iSamples = &iFrames[iChannel];
+ StkFloat *oSamples = &oFrames[oChannel];
+ unsigned int iHop = iFrames.channels(), oHop = oFrames.channels();
+ for ( unsigned int i=0; i<iFrames.frames(); i++, iSamples += iHop, oSamples += oHop ) {
+ inputs_[0] = gain_ * *iSamples;
+ *oSamples = b_[0] * inputs_[0] + b_[1] * inputs_[1] + b_[2] * inputs_[2];
+ *oSamples -= a_[2] * outputs_[2] + a_[1] * outputs_[1];
+ inputs_[2] = inputs_[1];
+ inputs_[1] = inputs_[0];
+ outputs_[2] = outputs_[1];
+ outputs_[1] = *oSamples;
+ }
+
+ lastFrame_[0] = outputs_[1];
+ return iFrames;
+}
+
+} // stk namespace
+
+#endif
+
--- /dev/null
+#ifndef STK_BLIT_H
+#define STK_BLIT_H
+
+#include "Generator.h"
+#include <cmath>
+#include <limits>
+
+namespace stk {
+
+/***************************************************/
+/*! \class Blit
+ \brief STK band-limited impulse train class.
+
+ This class generates a band-limited impulse train using a
+ closed-form algorithm reported by Stilson and Smith in "Alias-Free
+ Digital Synthesis of Classic Analog Waveforms", 1996. The user
+ can specify both the fundamental frequency of the impulse train
+ and the number of harmonics contained in the resulting signal.
+
+ The signal is normalized so that the peak value is +/-1.0.
+
+ If nHarmonics is 0, then the signal will contain all harmonics up
+ to half the sample rate. Note, however, that this setting may
+ produce aliasing in the signal when the frequency is changing (no
+ automatic modification of the number of harmonics is performed by
+ the setFrequency() function).
+
+ Original code by Robin Davies, 2005.
+ Revisions by Gary Scavone for STK, 2005.
+*/
+/***************************************************/
+
+class Blit: public Generator
+{
+ public:
+ //! Default constructor that initializes BLIT frequency to 220 Hz.
+ Blit( StkFloat frequency = 220.0 );
+
+ //! Class destructor.
+ ~Blit();
+
+ //! Resets the oscillator state and phase to 0.
+ void reset();
+
+ //! Set the phase of the signal.
+ /*!
+ Set the phase of the signal, in the range 0 to 1.
+ */
+ void setPhase( StkFloat phase ) { phase_ = PI * phase; };
+
+ //! Get the current phase of the signal.
+ /*!
+ Get the phase of the signal, in the range [0 to 1.0).
+ */
+ StkFloat getPhase() const { return phase_ / PI; };
+
+ //! Set the impulse train rate in terms of a frequency in Hz.
+ void setFrequency( StkFloat frequency );
+
+ //! Set the number of harmonics generated in the signal.
+ /*!
+ This function sets the number of harmonics contained in the
+ resulting signal. It is equivalent to (2 * M) + 1 in the BLIT
+ algorithm. The default value of 0 sets the algorithm for maximum
+ harmonic content (harmonics up to half the sample rate). This
+ parameter is not checked against the current sample rate and
+ fundamental frequency. Thus, aliasing can result if one or more
+ harmonics for a given fundamental frequency exceeds fs / 2. This
+ behavior was chosen over the potentially more problematic solution
+ of automatically modifying the M parameter, which can produce
+ audible clicks in the signal.
+ */
+ void setHarmonics( unsigned int nHarmonics = 0 );
+
+ //! Return the last computed output value.
+ StkFloat lastOut( void ) const { return lastFrame_[0]; };
+
+ //! Compute and return one output sample.
+ StkFloat tick( void );
+
+ //! Fill a channel of the StkFrames object with computed outputs.
+ /*!
+ The \c channel argument must be less than the number of
+ channels in the StkFrames argument (the first channel is specified
+ by 0). However, range checking is only performed if _STK_DEBUG_
+ is defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
+
+ protected:
+
+ void updateHarmonics( void );
+
+ unsigned int nHarmonics_;
+ unsigned int m_;
+ StkFloat rate_;
+ StkFloat phase_;
+ StkFloat p_;
+
+};
+
+inline StkFloat Blit :: tick( void )
+{
+ // The code below implements the SincM algorithm of Stilson and
+ // Smith with an additional scale factor of P / M applied to
+ // normalize the output.
+
+ // A fully optimized version of this code would replace the two sin
+ // calls with a pair of fast sin oscillators, for which stable fast
+ // two-multiply algorithms are well known. In the spirit of STK,
+ // which favors clarity over performance, the optimization has not
+ // been made here.
+
+ // Avoid a divide by zero at the sinc peak, which has a limiting
+ // value of 1.0.
+ StkFloat tmp, denominator = sin( phase_ );
+ if ( denominator <= std::numeric_limits<StkFloat>::epsilon() )
+ tmp = 1.0;
+ else {
+ tmp = sin( m_ * phase_ );
+ tmp /= m_ * denominator;
+ }
+
+ phase_ += rate_;
+ if ( phase_ >= PI ) phase_ -= PI;
+
+ lastFrame_[0] = tmp;
+ return lastFrame_[0];
+}
+
+inline StkFrames& Blit :: tick( StkFrames& frames, unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel >= frames.channels() ) {
+ errorString_ << "Blit::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *samples = &frames[channel];
+ unsigned int hop = frames.channels();
+ for ( unsigned int i=0; i<frames.frames(); i++, samples += hop )
+ *samples = Blit::tick();
+
+ return frames;
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_BLITSAW_H
+#define STK_BLITSAW_H
+
+#include "Generator.h"
+#include <cmath>
+#include <limits>
+
+namespace stk {
+
+/***************************************************/
+/*! \class BlitSaw
+ \brief STK band-limited sawtooth wave class.
+
+ This class generates a band-limited sawtooth waveform using a
+ closed-form algorithm reported by Stilson and Smith in "Alias-Free
+ Digital Synthesis of Classic Analog Waveforms", 1996. The user
+ can specify both the fundamental frequency of the sawtooth and the
+ number of harmonics contained in the resulting signal.
+
+ If nHarmonics is 0, then the signal will contain all harmonics up
+ to half the sample rate. Note, however, that this setting may
+ produce aliasing in the signal when the frequency is changing (no
+ automatic modification of the number of harmonics is performed by
+ the setFrequency() function).
+
+ Based on initial code of Robin Davies, 2005.
+ Modified algorithm code by Gary Scavone, 2005.
+*/
+/***************************************************/
+
+class BlitSaw: public Generator
+{
+ public:
+ //! Class constructor.
+ BlitSaw( StkFloat frequency = 220.0 );
+
+ //! Class destructor.
+ ~BlitSaw();
+
+ //! Resets the oscillator state and phase to 0.
+ void reset();
+
+ //! Set the sawtooth oscillator rate in terms of a frequency in Hz.
+ void setFrequency( StkFloat frequency );
+
+ //! Set the number of harmonics generated in the signal.
+ /*!
+ This function sets the number of harmonics contained in the
+ resulting signal. It is equivalent to (2 * M) + 1 in the BLIT
+ algorithm. The default value of 0 sets the algorithm for maximum
+ harmonic content (harmonics up to half the sample rate). This
+ parameter is not checked against the current sample rate and
+ fundamental frequency. Thus, aliasing can result if one or more
+ harmonics for a given fundamental frequency exceeds fs / 2. This
+ behavior was chosen over the potentially more problematic solution
+ of automatically modifying the M parameter, which can produce
+ audible clicks in the signal.
+ */
+ void setHarmonics( unsigned int nHarmonics = 0 );
+
+ //! Return the last computed output value.
+ StkFloat lastOut( void ) const { return lastFrame_[0]; };
+
+ //! Compute and return one output sample.
+ StkFloat tick( void );
+
+ //! Fill a channel of the StkFrames object with computed outputs.
+ /*!
+ The \c channel argument must be less than the number of
+ channels in the StkFrames argument (the first channel is specified
+ by 0). However, range checking is only performed if _STK_DEBUG_
+ is defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
+
+ protected:
+
+ void updateHarmonics( void );
+
+ unsigned int nHarmonics_;
+ unsigned int m_;
+ StkFloat rate_;
+ StkFloat phase_;
+ StkFloat p_;
+ StkFloat C2_;
+ StkFloat a_;
+ StkFloat state_;
+
+};
+
+inline StkFloat BlitSaw :: tick( void )
+{
+ // The code below implements the BLIT algorithm of Stilson and
+ // Smith, followed by a summation and filtering operation to produce
+ // a sawtooth waveform. After experimenting with various approaches
+ // to calculate the average value of the BLIT over one period, I
+ // found that an estimate of C2_ = 1.0 / period (in samples) worked
+ // most consistently. A "leaky integrator" is then applied to the
+ // difference of the BLIT output and C2_. (GPS - 1 October 2005)
+
+ // A fully optimized version of this code would replace the two sin
+ // calls with a pair of fast sin oscillators, for which stable fast
+ // two-multiply algorithms are well known. In the spirit of STK,
+ // which favors clarity over performance, the optimization has
+ // not been made here.
+
+ // Avoid a divide by zero, or use of a denormalized divisor
+ // at the sinc peak, which has a limiting value of m_ / p_.
+ StkFloat tmp, denominator = sin( phase_ );
+ if ( fabs(denominator) <= std::numeric_limits<StkFloat>::epsilon() )
+ tmp = a_;
+ else {
+ tmp = sin( m_ * phase_ );
+ tmp /= p_ * denominator;
+ }
+
+ tmp += state_ - C2_;
+ state_ = tmp * 0.995;
+
+ phase_ += rate_;
+ if ( phase_ >= PI ) phase_ -= PI;
+
+ lastFrame_[0] = tmp;
+ return lastFrame_[0];
+}
+
+inline StkFrames& BlitSaw :: tick( StkFrames& frames, unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel >= frames.channels() ) {
+ errorString_ << "BlitSaw::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+
+ StkFloat *samples = &frames[channel];
+ unsigned int hop = frames.channels();
+ for ( unsigned int i=0; i<frames.frames(); i++, samples += hop )
+ *samples = BlitSaw::tick();
+
+ return frames;
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_BLITSQUARE_H
+#define STK_BLITSQUARE_H
+
+#include "Generator.h"
+#include <cmath>
+#include <limits>
+
+namespace stk {
+
+/***************************************************/
+/*! \class BlitSquare
+ \brief STK band-limited square wave class.
+
+ This class generates a band-limited square wave signal. It is
+ derived in part from the approach reported by Stilson and Smith in
+ "Alias-Free Digital Synthesis of Classic Analog Waveforms", 1996.
+ The algorithm implemented in this class uses a SincM function with
+ an even M value to achieve a bipolar bandlimited impulse train.
+ This signal is then integrated to achieve a square waveform. The
+ integration process has an associated DC offset so a DC blocking
+ filter is applied at the output.
+
+ The user can specify both the fundamental frequency of the
+ waveform and the number of harmonics contained in the resulting
+ signal.
+
+ If nHarmonics is 0, then the signal will contain all harmonics up
+ to half the sample rate. Note, however, that this setting may
+ produce aliasing in the signal when the frequency is changing (no
+ automatic modification of the number of harmonics is performed by
+ the setFrequency() function). Also note that the harmonics of a
+ square wave fall at odd integer multiples of the fundamental, so
+ aliasing will happen with a lower fundamental than with the other
+ Blit waveforms. This class is not guaranteed to be well behaved
+ in the presence of significant aliasing.
+
+ Based on initial code of Robin Davies, 2005.
+ Modified algorithm code by Gary Scavone, 2005 - 2006.
+*/
+/***************************************************/
+
+class BlitSquare: public Generator
+{
+ public:
+ //! Default constructor that initializes BLIT frequency to 220 Hz.
+ BlitSquare( StkFloat frequency = 220.0 );
+
+ //! Class destructor.
+ ~BlitSquare();
+
+ //! Resets the oscillator state and phase to 0.
+ void reset();
+
+ //! Set the phase of the signal.
+ /*!
+ Set the phase of the signal, in the range 0 to 1.
+ */
+ void setPhase( StkFloat phase ) { phase_ = PI * phase; };
+
+ //! Get the current phase of the signal.
+ /*!
+ Get the phase of the signal, in the range [0 to 1.0).
+ */
+ StkFloat getPhase() const { return phase_ / PI; };
+
+ //! Set the impulse train rate in terms of a frequency in Hz.
+ void setFrequency( StkFloat frequency );
+
+ //! Set the number of harmonics generated in the signal.
+ /*!
+ This function sets the number of harmonics contained in the
+ resulting signal. It is equivalent to (2 * M) + 1 in the BLIT
+ algorithm. The default value of 0 sets the algorithm for maximum
+ harmonic content (harmonics up to half the sample rate). This
+ parameter is not checked against the current sample rate and
+ fundamental frequency. Thus, aliasing can result if one or more
+ harmonics for a given fundamental frequency exceeds fs / 2. This
+ behavior was chosen over the potentially more problematic solution
+ of automatically modifying the M parameter, which can produce
+ audible clicks in the signal.
+ */
+ void setHarmonics( unsigned int nHarmonics = 0 );
+
+ //! Return the last computed output value.
+ StkFloat lastOut( void ) const { return lastFrame_[0]; };
+
+ //! Compute and return one output sample.
+ StkFloat tick( void );
+
+ //! Fill a channel of the StkFrames object with computed outputs.
+ /*!
+ The \c channel argument must be less than the number of
+ channels in the StkFrames argument (the first channel is specified
+ by 0). However, range checking is only performed if _STK_DEBUG_
+ is defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
+
+ protected:
+
+ void updateHarmonics( void );
+
+ unsigned int nHarmonics_;
+ unsigned int m_;
+ StkFloat rate_;
+ StkFloat phase_;
+ StkFloat p_;
+ StkFloat a_;
+ StkFloat lastBlitOutput_;
+ StkFloat dcbState_;
+};
+
+inline StkFloat BlitSquare :: tick( void )
+{
+ StkFloat temp = lastBlitOutput_;
+
+ // A fully optimized version of this would replace the two sin calls
+ // with a pair of fast sin oscillators, for which stable fast
+ // two-multiply algorithms are well known. In the spirit of STK,
+ // which favors clarity over performance, the optimization has
+ // not been made here.
+
+ // Avoid a divide by zero, or use of a denomralized divisor
+ // at the sinc peak, which has a limiting value of 1.0.
+ StkFloat denominator = sin( phase_ );
+ if ( fabs( denominator ) < std::numeric_limits<StkFloat>::epsilon() ) {
+ // Inexact comparison safely distinguishes betwen *close to zero*, and *close to PI*.
+ if ( phase_ < 0.1f || phase_ > TWO_PI - 0.1f )
+ lastBlitOutput_ = a_;
+ else
+ lastBlitOutput_ = -a_;
+ }
+ else {
+ lastBlitOutput_ = sin( m_ * phase_ );
+ lastBlitOutput_ /= p_ * denominator;
+ }
+
+ lastBlitOutput_ += temp;
+
+ // Now apply DC blocker.
+ lastFrame_[0] = lastBlitOutput_ - dcbState_ + 0.999 * lastFrame_[0];
+ dcbState_ = lastBlitOutput_;
+
+ phase_ += rate_;
+ if ( phase_ >= TWO_PI ) phase_ -= TWO_PI;
+
+ return lastFrame_[0];
+}
+
+inline StkFrames& BlitSquare :: tick( StkFrames& frames, unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel >= frames.channels() ) {
+ errorString_ << "BlitSquare::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *samples = &frames[channel];
+ unsigned int hop = frames.channels();
+ for ( unsigned int i=0; i<frames.frames(); i++, samples += hop )
+ *samples = BlitSquare::tick();
+
+ return frames;
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_BLOWBOTL_H
+#define STK_BLOWBOTL_H
+
+#include "Instrmnt.h"
+#include "JetTable.h"
+#include "BiQuad.h"
+#include "PoleZero.h"
+#include "Noise.h"
+#include "ADSR.h"
+#include "SineWave.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class BlowBotl
+ \brief STK blown bottle instrument class.
+
+ This class implements a helmholtz resonator
+ (biquad filter) with a polynomial jet
+ excitation (a la Cook).
+
+ Control Change Numbers:
+ - Noise Gain = 4
+ - Vibrato Frequency = 11
+ - Vibrato Gain = 1
+ - Volume = 128
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class BlowBotl : public Instrmnt
+{
+ public:
+ //! Class constructor.
+ /*!
+ An StkError will be thrown if the rawwave path is incorrectly set.
+ */
+ BlowBotl( void );
+
+ //! Class destructor.
+ ~BlowBotl( void );
+
+ //! Reset and clear all internal state.
+ void clear( void );
+
+ //! Set instrument parameters for a particular frequency.
+ void setFrequency( StkFloat frequency );
+
+ //! Apply breath velocity to instrument with given amplitude and rate of increase.
+ void startBlowing( StkFloat amplitude, StkFloat rate );
+
+ //! Decrease breath velocity with given rate of decrease.
+ void stopBlowing( StkFloat rate );
+
+ //! Start a note with the given frequency and amplitude.
+ void noteOn( StkFloat frequency, StkFloat amplitude );
+
+ //! Stop a note with the given amplitude (speed of decay).
+ void noteOff( StkFloat amplitude );
+
+ //! Perform the control change specified by \e number and \e value (0.0 - 128.0).
+ void controlChange( int number, StkFloat value );
+
+ //! Compute and return one output sample.
+ StkFloat tick( unsigned int channel = 0 );
+
+ protected:
+
+ JetTable jetTable_;
+ BiQuad resonator_;
+ PoleZero dcBlock_;
+ Noise noise_;
+ ADSR adsr_;
+ SineWave vibrato_;
+ StkFloat maxPressure_;
+ StkFloat noiseGain_;
+ StkFloat vibratoGain_;
+ StkFloat outputGain_;
+
+};
+
+inline StkFloat BlowBotl :: tick( unsigned int )
+{
+ StkFloat breathPressure;
+ StkFloat randPressure;
+ StkFloat pressureDiff;
+
+ // Calculate the breath pressure (envelope + vibrato)
+ breathPressure = maxPressure_ * adsr_.tick();
+ breathPressure += vibratoGain_ * vibrato_.tick();
+
+ pressureDiff = breathPressure - resonator_.lastOut();
+
+ randPressure = noiseGain_ * noise_.tick();
+ randPressure *= breathPressure;
+ randPressure *= (1.0 + pressureDiff);
+
+ resonator_.tick( breathPressure + randPressure - ( jetTable_.tick( pressureDiff ) * pressureDiff ) );
+ lastFrame_[0] = 0.2 * outputGain_ * dcBlock_.tick( pressureDiff );
+
+ return lastFrame_[0];
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_BLOWHOLE_H
+#define STK_BLOWHOLE_H
+
+#include "Instrmnt.h"
+#include "DelayL.h"
+#include "ReedTable.h"
+#include "OneZero.h"
+#include "PoleZero.h"
+#include "Envelope.h"
+#include "Noise.h"
+#include "SineWave.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class BlowHole
+ \brief STK clarinet physical model with one
+ register hole and one tonehole.
+
+ This class is based on the clarinet model,
+ with the addition of a two-port register hole
+ and a three-port dynamic tonehole
+ implementation, as discussed by Scavone and
+ Cook (1998).
+
+ In this implementation, the distances between
+ the reed/register hole and tonehole/bell are
+ fixed. As a result, both the tonehole and
+ register hole will have variable influence on
+ the playing frequency, which is dependent on
+ the length of the air column. In addition,
+ the highest playing freqeuency is limited by
+ these fixed lengths.
+
+ This is a digital waveguide model, making its
+ use possibly subject to patents held by Stanford
+ University, Yamaha, and others.
+
+ Control Change Numbers:
+ - Reed Stiffness = 2
+ - Noise Gain = 4
+ - Tonehole State = 11
+ - Register State = 1
+ - Breath Pressure = 128
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class BlowHole : public Instrmnt
+{
+ public:
+ //! Class constructor.
+ /*!
+ An StkError will be thrown if the rawwave path is incorrectly set.
+ */
+ BlowHole( StkFloat lowestFrequency );
+
+ //! Class destructor.
+ ~BlowHole( void );
+
+ //! Reset and clear all internal state.
+ void clear( void );
+
+ //! Set instrument parameters for a particular frequency.
+ void setFrequency( StkFloat frequency );
+
+ //! Set the tonehole state (0.0 = closed, 1.0 = fully open).
+ void setTonehole( StkFloat newValue );
+
+ //! Set the register hole state (0.0 = closed, 1.0 = fully open).
+ void setVent( StkFloat newValue );
+
+ //! Apply breath pressure to instrument with given amplitude and rate of increase.
+ void startBlowing( StkFloat amplitude, StkFloat rate );
+
+ //! Decrease breath pressure with given rate of decrease.
+ void stopBlowing( StkFloat rate );
+
+ //! Start a note with the given frequency and amplitude.
+ void noteOn( StkFloat frequency, StkFloat amplitude );
+
+ //! Stop a note with the given amplitude (speed of decay).
+ void noteOff( StkFloat amplitude );
+
+ //! Perform the control change specified by \e number and \e value (0.0 - 128.0).
+ void controlChange( int number, StkFloat value );
+
+ //! Compute and return one output sample.
+ StkFloat tick( unsigned int channel = 0 );
+
+ protected:
+
+ DelayL delays_[3];
+ ReedTable reedTable_;
+ OneZero filter_;
+ PoleZero tonehole_;
+ PoleZero vent_;
+ Envelope envelope_;
+ Noise noise_;
+ SineWave vibrato_;
+ unsigned long length_;
+ StkFloat scatter_;
+ StkFloat thCoeff_;
+ StkFloat rhGain_;
+ StkFloat outputGain_;
+ StkFloat noiseGain_;
+ StkFloat vibratoGain_;
+
+};
+
+ inline StkFloat BlowHole :: tick( unsigned int )
+{
+ StkFloat pressureDiff;
+ StkFloat breathPressure;
+ StkFloat temp;
+
+ // Calculate the breath pressure (envelope + noise + vibrato)
+ breathPressure = envelope_.tick();
+ breathPressure += breathPressure * noiseGain_ * noise_.tick();
+ breathPressure += breathPressure * vibratoGain_ * vibrato_.tick();
+
+ // Calculate the differential pressure = reflected - mouthpiece pressures
+ pressureDiff = delays_[0].lastOut() - breathPressure;
+
+ // Do two-port junction scattering for register vent
+ StkFloat pa = breathPressure + pressureDiff * reedTable_.tick( pressureDiff );
+ StkFloat pb = delays_[1].lastOut();
+ vent_.tick( pa+pb );
+
+ lastFrame_[0] = delays_[0].tick( vent_.lastOut()+pb );
+ lastFrame_[0] *= outputGain_;
+
+ // Do three-port junction scattering (under tonehole)
+ pa += vent_.lastOut();
+ pb = delays_[2].lastOut();
+ StkFloat pth = tonehole_.lastOut();
+ temp = scatter_ * (pa + pb - 2 * pth);
+
+ delays_[2].tick( filter_.tick(pa + temp) * -0.95 );
+ delays_[1].tick( pb + temp );
+ tonehole_.tick( pa + pb - pth + temp );
+
+ return lastFrame_[0];
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_BOWTABL_H
+#define STK_BOWTABL_H
+
+#include "Function.h"
+#include <cmath>
+
+namespace stk {
+
+/***************************************************/
+/*! \class BowTable
+ \brief STK bowed string table class.
+
+ This class implements a simple bowed string
+ non-linear function, as described by Smith (1986).
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class BowTable : public Function
+{
+public:
+ //! Default constructor.
+ BowTable( void ) : offset_(0.0), slope_(0.1) {};
+
+ //! Set the table offset value.
+ /*!
+ The table offset is a bias which controls the
+ symmetry of the friction. If you want the
+ friction to vary with direction, use a non-zero
+ value for the offset. The default value is zero.
+ */
+ void setOffset( StkFloat offset ) { offset_ = offset; };
+
+ //! Set the table slope value.
+ /*!
+ The table slope controls the width of the friction
+ pulse, which is related to bow force.
+ */
+ void setSlope( StkFloat slope ) { slope_ = slope; };
+
+ //! Take one sample input and map to one sample of output.
+ StkFloat tick( StkFloat input );
+
+ //! Take a channel of the StkFrames object as inputs to the table and replace with corresponding outputs.
+ /*!
+ The StkFrames argument reference is returned. The \c channel
+ argument must be less than the number of channels in the
+ StkFrames argument (the first channel is specified by 0).
+ However, range checking is only performed if _STK_DEBUG_ is
+ defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
+
+ //! Take a channel of the \c iFrames object as inputs to the table and write outputs to the \c oFrames object.
+ /*!
+ The \c iFrames object reference is returned. Each channel
+ argument must be less than the number of channels in the
+ corresponding StkFrames argument (the first channel is specified
+ by 0). However, range checking is only performed if _STK_DEBUG_
+ is defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& iFrames, StkFrames &oFrames, unsigned int iChannel = 0, unsigned int oChannel = 0 );
+
+protected:
+
+ StkFloat offset_;
+ StkFloat slope_;
+
+};
+
+inline StkFloat BowTable :: tick( StkFloat input )
+{
+ // The input represents differential string vs. bow velocity.
+ StkFloat sample = input + offset_; // add bias to input
+ sample *= slope_; // then scale it
+ lastFrame_[0] = (StkFloat) fabs( (double) sample ) + (StkFloat) 0.75;
+ lastFrame_[0] = (StkFloat) pow( lastFrame_[0], (StkFloat) -4.0 );
+
+ // Set minimum friction to 0.0
+ // if ( lastFrame_[0] < 0.0 ) lastFrame_[0] = 0.0;
+
+ // Set maximum friction to 1.0.
+ if ( lastFrame_[0] > 1.0 ) lastFrame_[0] = (StkFloat) 1.0;
+
+ return lastFrame_[0];
+}
+
+inline StkFrames& BowTable :: tick( StkFrames& frames, unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel >= frames.channels() ) {
+ errorString_ << "BowTable::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *samples = &frames[channel];
+ unsigned int hop = frames.channels();
+ for ( unsigned int i=0; i<frames.frames(); i++, samples += hop ) {
+ *samples = *samples + offset_;
+ *samples *= slope_;
+ *samples = (StkFloat) fabs( (double) *samples ) + 0.75;
+ *samples = (StkFloat) pow( *samples, (StkFloat) -4.0 );
+ if ( *samples > 1.0) *samples = 1.0;
+ }
+
+ lastFrame_[0] = *(samples-hop);
+ return frames;
+}
+
+inline StkFrames& BowTable :: tick( StkFrames& iFrames, StkFrames& oFrames, unsigned int iChannel, unsigned int oChannel )
+{
+#if defined(_STK_DEBUG_)
+ if ( iChannel >= iFrames.channels() || oChannel >= oFrames.channels() ) {
+ errorString_ << "BowTable::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *iSamples = &iFrames[iChannel];
+ StkFloat *oSamples = &oFrames[oChannel];
+ unsigned int iHop = iFrames.channels(), oHop = oFrames.channels();
+ for ( unsigned int i=0; i<iFrames.frames(); i++, iSamples += iHop, oSamples += oHop ) {
+ *oSamples = *iSamples + offset_;
+ *oSamples *= slope_;
+ *oSamples = (StkFloat) fabs( (double) *oSamples ) + 0.75;
+ *oSamples = (StkFloat) pow( *oSamples, (StkFloat) -4.0 );
+ if ( *oSamples > 1.0) *oSamples = 1.0;
+ }
+
+ lastFrame_[0] = *(oSamples-oHop);
+ return iFrames;
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_BOWED_H
+#define STK_BOWED_H
+
+#include "Instrmnt.h"
+#include "DelayL.h"
+#include "BowTable.h"
+#include "OnePole.h"
+#include "BiQuad.h"
+#include "SineWave.h"
+#include "ADSR.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class Bowed
+ \brief STK bowed string instrument class.
+
+ This class implements a bowed string model, a
+ la Smith (1986), after McIntyre, Schumacher,
+ Woodhouse (1983).
+
+ This is a digital waveguide model, making its
+ use possibly subject to patents held by
+ Stanford University, Yamaha, and others.
+
+ Control Change Numbers:
+ - Bow Pressure = 2
+ - Bow Position = 4
+ - Vibrato Frequency = 11
+ - Vibrato Gain = 1
+ - Volume = 128
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class Bowed : public Instrmnt
+{
+ public:
+ //! Class constructor, taking the lowest desired playing frequency.
+ Bowed( StkFloat lowestFrequency );
+
+ //! Class destructor.
+ ~Bowed( void );
+
+ //! Reset and clear all internal state.
+ void clear( void );
+
+ //! Set instrument parameters for a particular frequency.
+ void setFrequency( StkFloat frequency );
+
+ //! Set vibrato gain.
+ void setVibrato( StkFloat gain );
+
+ //! Apply breath pressure to instrument with given amplitude and rate of increase.
+ void startBowing( StkFloat amplitude, StkFloat rate );
+
+ //! Decrease breath pressure with given rate of decrease.
+ void stopBowing( StkFloat rate );
+
+ //! Start a note with the given frequency and amplitude.
+ void noteOn( StkFloat frequency, StkFloat amplitude );
+
+ //! Stop a note with the given amplitude (speed of decay).
+ void noteOff( StkFloat amplitude );
+
+ //! Perform the control change specified by \e number and \e value (0.0 - 128.0).
+ void controlChange( int number, StkFloat value );
+
+ //! Compute and return one output sample.
+ StkFloat tick( unsigned int channel = 0 );
+
+ protected:
+
+ DelayL neckDelay_;
+ DelayL bridgeDelay_;
+ BowTable bowTable_;
+ OnePole stringFilter_;
+ BiQuad bodyFilter_;
+ SineWave vibrato_;
+ ADSR adsr_;
+ StkFloat maxVelocity_;
+ StkFloat baseDelay_;
+ StkFloat vibratoGain_;
+ StkFloat betaRatio_;
+
+};
+
+inline StkFloat Bowed :: tick( unsigned int )
+{
+ StkFloat bowVelocity = maxVelocity_ * adsr_.tick();
+ StkFloat bridgeRefl = -stringFilter_.tick( bridgeDelay_.lastOut() );
+ StkFloat nutRefl = -neckDelay_.lastOut();
+ StkFloat stringVel = bridgeRefl + nutRefl; // Sum is string velocity
+ StkFloat velDiff = bowVelocity - stringVel; // Differential velocity
+ StkFloat newVel = velDiff * bowTable_.tick( velDiff ); // Non-Linear bow function
+ neckDelay_.tick(bridgeRefl + newVel); // Do string propagations
+ bridgeDelay_.tick(nutRefl + newVel);
+
+ if ( vibratoGain_ > 0.0 ) {
+ neckDelay_.setDelay( (baseDelay_ * (1.0 - betaRatio_) ) +
+ (baseDelay_ * vibratoGain_ * vibrato_.tick()) );
+ }
+
+ lastFrame_[0] = bodyFilter_.tick( bridgeDelay_.lastOut() );
+
+ return lastFrame_[0];
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_BRASS_H
+#define STK_BRASS_H
+
+#include "Instrmnt.h"
+#include "DelayA.h"
+#include "BiQuad.h"
+#include "PoleZero.h"
+#include "ADSR.h"
+#include "SineWave.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class Brass
+ \brief STK simple brass instrument class.
+
+ This class implements a simple brass instrument
+ waveguide model, a la Cook (TBone, HosePlayer).
+
+ This is a digital waveguide model, making its
+ use possibly subject to patents held by
+ Stanford University, Yamaha, and others.
+
+ Control Change Numbers:
+ - Lip Tension = 2
+ - Slide Length = 4
+ - Vibrato Frequency = 11
+ - Vibrato Gain = 1
+ - Volume = 128
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class Brass: public Instrmnt
+{
+ public:
+ //! Class constructor, taking the lowest desired playing frequency.
+ /*!
+ An StkError will be thrown if the rawwave path is incorrectly set.
+ */
+ Brass( StkFloat lowestFrequency );
+
+ //! Class destructor.
+ ~Brass( );
+
+ //! Reset and clear all internal state.
+ void clear( );
+
+ //! Set instrument parameters for a particular frequency.
+ void setFrequency( StkFloat frequency );
+
+ //! Set the lips frequency.
+ void setLip( StkFloat frequency );
+
+ //! Apply breath pressure to instrument with given amplitude and rate of increase.
+ void startBlowing( StkFloat amplitude, StkFloat rate );
+
+ //! Decrease breath pressure with given rate of decrease.
+ void stopBlowing( StkFloat rate );
+
+ //! Start a note with the given frequency and amplitude.
+ void noteOn( StkFloat frequency, StkFloat amplitude );
+
+ //! Stop a note with the given amplitude (speed of decay).
+ void noteOff( StkFloat amplitude );
+
+ //! Perform the control change specified by \e number and \e value (0.0 - 128.0).
+ void controlChange( int number, StkFloat value );
+
+ //! Compute and return one output sample.
+ StkFloat tick( unsigned int channel = 0 );
+
+ protected:
+
+ DelayA delayLine_;
+ BiQuad lipFilter_;
+ PoleZero dcBlock_;
+ ADSR adsr_;
+ SineWave vibrato_;
+ unsigned long length_;
+ StkFloat lipTarget_;
+ StkFloat slideTarget_;
+ StkFloat vibratoGain_;
+ StkFloat maxPressure_;
+
+};
+
+inline StkFloat Brass :: tick( unsigned int )
+{
+ StkFloat breathPressure = maxPressure_ * adsr_.tick();
+ breathPressure += vibratoGain_ * vibrato_.tick();
+
+ StkFloat mouthPressure = 0.3 * breathPressure;
+ StkFloat borePressure = 0.85 * delayLine_.lastOut();
+ StkFloat deltaPressure = mouthPressure - borePressure; // Differential pressure.
+ deltaPressure = lipFilter_.tick( deltaPressure ); // Force - > position.
+ deltaPressure *= deltaPressure; // Basic position to area mapping.
+ if ( deltaPressure > 1.0 ) deltaPressure = 1.0; // Non-linear saturation.
+
+ // The following input scattering assumes the mouthPressure = area.
+ lastFrame_[0] = deltaPressure * mouthPressure + ( 1.0 - deltaPressure) * borePressure;
+ lastFrame_[0] = delayLine_.tick( dcBlock_.tick( lastFrame_[0] ) );
+
+ return lastFrame_[0];
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_CHORUS_H
+#define STK_CHORUS_H
+
+#include "Effect.h"
+#include "DelayL.h"
+#include "SineWave.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class Chorus
+ \brief STK chorus effect class.
+
+ This class implements a chorus effect. It takes a monophonic
+ input signal and produces a stereo output signal.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class Chorus : public Effect
+{
+ public:
+ //! Class constructor, taking the median desired delay length.
+ /*!
+ An StkError can be thrown if the rawwave path is incorrect.
+ */
+ Chorus( StkFloat baseDelay = 6000 );
+
+ //! Reset and clear all internal state.
+ void clear( void );
+
+ //! Set modulation depth.
+ void setModDepth( StkFloat depth ) { modDepth_ = depth; };
+
+ //! Set modulation frequency.
+ void setModFrequency( StkFloat frequency );
+
+ //! Return the specified channel value of the last computed stereo frame.
+ /*!
+ Use the lastFrame() function to get both values of the last
+ computed stereo frame. The \c channel argument must be 0 or 1
+ (the first channel is specified by 0). However, range checking is
+ only performed if _STK_DEBUG_ is defined during compilation, in
+ which case an out-of-range value will trigger an StkError
+ exception.
+ */
+ StkFloat lastOut( unsigned int channel = 0 );
+
+ //! Input one sample to the effect and return the specified \c channel value of the computed stereo frame.
+ /*!
+ Use the lastFrame() function to get both values of the computed
+ stereo output frame. The \c channel argument must be 0 or 1 (the
+ first channel is specified by 0). However, range checking is only
+ performed if _STK_DEBUG_ is defined during compilation, in which
+ case an out-of-range value will trigger an StkError exception.
+ */
+ StkFloat tick( StkFloat input, unsigned int channel = 0 );
+
+ //! Take a channel of the StkFrames object as inputs to the effect and replace with stereo outputs.
+ /*!
+ The StkFrames argument reference is returned. The stereo
+ outputs are written to the StkFrames argument starting at the
+ specified \c channel. Therefore, the \c channel argument must be
+ less than ( channels() - 1 ) of the StkFrames argument (the first
+ channel is specified by 0). However, range checking is only
+ performed if _STK_DEBUG_ is defined during compilation, in which
+ case an out-of-range value will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
+
+ //! Take a channel of the \c iFrames object as inputs to the effect and write stereo outputs to the \c oFrames object.
+ /*!
+ The \c iFrames object reference is returned. The \c iChannel
+ argument must be less than the number of channels in the \c
+ iFrames argument (the first channel is specified by 0). The \c
+ oChannel argument must be less than ( channels() - 1 ) of the \c
+ oFrames argument. However, range checking is only performed if
+ _STK_DEBUG_ is defined during compilation, in which case an
+ out-of-range value will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& iFrames, StkFrames &oFrames, unsigned int iChannel = 0, unsigned int oChannel = 0 );
+
+ protected:
+
+ DelayL delayLine_[2];
+ SineWave mods_[2];
+ StkFloat baseLength_;
+ StkFloat modDepth_;
+
+};
+
+inline StkFloat Chorus :: lastOut( unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel > 1 ) {
+ errorString_ << "Chorus::lastOut(): channel argument must be less than 2!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ return lastFrame_[channel];
+}
+
+inline StkFloat Chorus :: tick( StkFloat input, unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel > 1 ) {
+ errorString_ << "Chorus::tick(): channel argument must be less than 2!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ delayLine_[0].setDelay( baseLength_ * 0.707 * ( 1.0 + modDepth_ * mods_[0].tick() ) );
+ delayLine_[1].setDelay( baseLength_ * 0.5 * ( 1.0 - modDepth_ * mods_[1].tick() ) );
+ lastFrame_[0] = effectMix_ * ( delayLine_[0].tick( input ) - input ) + input;
+ lastFrame_[1] = effectMix_ * ( delayLine_[1].tick( input ) - input ) + input;
+ return lastFrame_[channel];
+}
+
+inline StkFrames& Chorus :: tick( StkFrames& frames, unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel >= frames.channels() - 1 ) {
+ errorString_ << "Chorus::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *samples = &frames[channel];
+ unsigned int hop = frames.channels() - 1;
+ for ( unsigned int i=0; i<frames.frames(); i++, samples += hop ) {
+ *samples = effectMix_ * ( delayLine_[0].tick( *samples ) - *samples ) + *samples;
+ samples++;
+ *samples = effectMix_ * ( delayLine_[1].tick( *samples ) - *samples ) + *samples;
+ }
+
+ lastFrame_[0] = *(samples-hop);
+ lastFrame_[1] = *(samples-hop+1);
+ return frames;
+}
+
+inline StkFrames& Chorus :: tick( StkFrames& iFrames, StkFrames& oFrames, unsigned int iChannel, unsigned int oChannel )
+{
+#if defined(_STK_DEBUG_)
+ if ( iChannel >= iFrames.channels() || oChannel >= oFrames.channels() - 1 ) {
+ errorString_ << "Chorus::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *iSamples = &iFrames[iChannel];
+ StkFloat *oSamples = &oFrames[oChannel];
+ unsigned int iHop = iFrames.channels(), oHop = oFrames.channels();
+ for ( unsigned int i=0; i<iFrames.frames(); i++, iSamples += iHop, oSamples += oHop ) {
+ *oSamples++ = effectMix_ * ( delayLine_[0].tick( *iSamples ) - *iSamples ) + *iSamples;
+ *oSamples = effectMix_ * ( delayLine_[1].tick( *iSamples ) - *iSamples ) + *iSamples;
+ }
+
+ lastFrame_[0] = *(oSamples-oHop);
+ lastFrame_[1] = *(oSamples-oHop+1);
+ return iFrames;
+}
+
+} // stk namespace
+
+#endif
+
--- /dev/null
+#ifndef STK_CLARINET_H
+#define STK_CLARINET_H
+
+#include "Instrmnt.h"
+#include "DelayL.h"
+#include "ReedTable.h"
+#include "OneZero.h"
+#include "Envelope.h"
+#include "Noise.h"
+#include "SineWave.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class Clarinet
+ \brief STK clarinet physical model class.
+
+ This class implements a simple clarinet
+ physical model, as discussed by Smith (1986),
+ McIntyre, Schumacher, Woodhouse (1983), and
+ others.
+
+ This is a digital waveguide model, making its
+ use possibly subject to patents held by Stanford
+ University, Yamaha, and others.
+
+ Control Change Numbers:
+ - Reed Stiffness = 2
+ - Noise Gain = 4
+ - Vibrato Frequency = 11
+ - Vibrato Gain = 1
+ - Breath Pressure = 128
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class Clarinet : public Instrmnt
+{
+ public:
+ //! Class constructor, taking the lowest desired playing frequency.
+ /*!
+ An StkError will be thrown if the rawwave path is incorrectly set.
+ */
+ Clarinet( StkFloat lowestFrequency );
+
+ //! Class destructor.
+ ~Clarinet( void );
+
+ //! Reset and clear all internal state.
+ void clear( void );
+
+ //! Set instrument parameters for a particular frequency.
+ void setFrequency( StkFloat frequency );
+
+ //! Apply breath pressure to instrument with given amplitude and rate of increase.
+ void startBlowing( StkFloat amplitude, StkFloat rate );
+
+ //! Decrease breath pressure with given rate of decrease.
+ void stopBlowing( StkFloat rate );
+
+ //! Start a note with the given frequency and amplitude.
+ void noteOn( StkFloat frequency, StkFloat amplitude );
+
+ //! Stop a note with the given amplitude (speed of decay).
+ void noteOff( StkFloat amplitude );
+
+ //! Perform the control change specified by \e number and \e value (0.0 - 128.0).
+ void controlChange( int number, StkFloat value );
+
+ //! Compute and return one output sample.
+ StkFloat tick( unsigned int channel = 0 );
+
+ protected:
+
+ DelayL delayLine_;
+ ReedTable reedTable_;
+ OneZero filter_;
+ Envelope envelope_;
+ Noise noise_;
+ SineWave vibrato_;
+ long length_;
+ StkFloat outputGain_;
+ StkFloat noiseGain_;
+ StkFloat vibratoGain_;
+
+};
+
+inline StkFloat Clarinet :: tick( unsigned int )
+{
+ StkFloat pressureDiff;
+ StkFloat breathPressure;
+
+ // Calculate the breath pressure (envelope + noise + vibrato)
+ breathPressure = envelope_.tick();
+ breathPressure += breathPressure * noiseGain_ * noise_.tick();
+ breathPressure += breathPressure * vibratoGain_ * vibrato_.tick();
+
+ // Perform commuted loss filtering.
+ pressureDiff = -0.95 * filter_.tick( delayLine_.lastOut() );
+
+ // Calculate pressure difference of reflected and mouthpiece pressures.
+ pressureDiff = pressureDiff - breathPressure;
+
+ // Perform non-linear scattering using pressure difference in reed function.
+ lastFrame_[0] = delayLine_.tick(breathPressure + pressureDiff * reedTable_.tick(pressureDiff));
+
+ // Apply output gain.
+ lastFrame_[0] *= outputGain_;
+
+ return lastFrame_[0];
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_DELAY_H
+#define STK_DELAY_H
+
+#include "Filter.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class Delay
+ \brief STK non-interpolating delay line class.
+
+ This class implements a non-interpolating digital delay-line. If
+ the delay and maximum length are not specified during
+ instantiation, a fixed maximum length of 4095 and a delay of zero
+ is set.
+
+ A non-interpolating delay line is typically used in fixed
+ delay-length applications, such as for reverberation.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class Delay : public Filter
+{
+public:
+
+ //! The default constructor creates a delay-line with maximum length of 4095 samples and zero delay.
+ /*!
+ An StkError will be thrown if the delay parameter is less than
+ zero, the maximum delay parameter is less than one, or the delay
+ parameter is greater than the maxDelay value.
+ */
+ Delay( unsigned long delay = 0, unsigned long maxDelay = 4095 );
+
+ //! Class destructor.
+ ~Delay();
+
+ //! Set the maximum delay-line length.
+ /*!
+ This method should generally only be used during initial setup
+ of the delay line. If it is used between calls to the tick()
+ function, without a call to clear(), a signal discontinuity will
+ likely occur. If the current maximum length is greater than the
+ new length, no change will be made.
+ */
+ void setMaximumDelay( unsigned long delay );
+
+ //! Set the delay-line length.
+ /*!
+ The valid range for \e delay is from 0 to the maximum delay-line length.
+ */
+ void setDelay( unsigned long delay );
+
+ //! Return the current delay-line length.
+ unsigned long getDelay( void ) const { return delay_; };
+
+ //! Return the value at \e tapDelay samples from the delay-line input.
+ /*!
+ The tap point is determined modulo the delay-line length and is
+ relative to the last input value (i.e., a tapDelay of zero returns
+ the last input value).
+ */
+ StkFloat contentsAt( unsigned long tapDelay );
+
+ //! Sum the provided value into the delay line at \e tapDelay samples from the input.
+ /*!
+ The new value is returned. The tap point is determined modulo
+ the delay-line length and is relative to the last input value
+ (i.e., a tapDelay of zero sums into the last input value).
+ */
+ StkFloat addTo( unsigned long tapDelay, StkFloat value );
+
+ //! Return the last computed output value.
+ StkFloat lastOut( void ) const { return lastFrame_[0]; };
+
+ //! Return the value that will be output by the next call to tick().
+ /*!
+ This method is valid only for delay settings greater than zero!
+ */
+ StkFloat nextOut( void ) { return inputs_[outPoint_]; };
+
+ //! Calculate and return the signal energy in the delay-line.
+ StkFloat energy( void ) const;
+
+ //! Input one sample to the filter and return one output.
+ StkFloat tick( StkFloat input );
+
+ //! Take a channel of the StkFrames object as inputs to the filter and replace with corresponding outputs.
+ /*!
+ The StkFrames argument reference is returned. The \c channel
+ argument must be less than the number of channels in the
+ StkFrames argument (the first channel is specified by 0).
+ However, range checking is only performed if _STK_DEBUG_ is
+ defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
+
+ //! Take a channel of the \c iFrames object as inputs to the filter and write outputs to the \c oFrames object.
+ /*!
+ The \c iFrames object reference is returned. Each channel
+ argument must be less than the number of channels in the
+ corresponding StkFrames argument (the first channel is specified
+ by 0). However, range checking is only performed if _STK_DEBUG_
+ is defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& iFrames, StkFrames &oFrames, unsigned int iChannel = 0, unsigned int oChannel = 0 );
+
+protected:
+
+ unsigned long inPoint_;
+ unsigned long outPoint_;
+ unsigned long delay_;
+};
+
+inline StkFloat Delay :: tick( StkFloat input )
+{
+ inputs_[inPoint_++] = input * gain_;
+
+ // Check for end condition
+ if ( inPoint_ == inputs_.size() )
+ inPoint_ = 0;
+
+ // Read out next value
+ lastFrame_[0] = inputs_[outPoint_++];
+
+ if ( outPoint_ == inputs_.size() )
+ outPoint_ = 0;
+
+ return lastFrame_[0];
+}
+
+inline StkFrames& Delay :: tick( StkFrames& frames, unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel >= frames.channels() ) {
+ errorString_ << "Delay::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *samples = &frames[channel];
+ unsigned int hop = frames.channels();
+ for ( unsigned int i=0; i<frames.frames(); i++, samples += hop ) {
+ inputs_[inPoint_++] = *samples * gain_;
+ if ( inPoint_ == inputs_.size() ) inPoint_ = 0;
+ *samples = inputs_[outPoint_++];
+ if ( outPoint_ == inputs_.size() ) outPoint_ = 0;
+ }
+
+ lastFrame_[0] = *(samples-hop);
+ return frames;
+}
+
+inline StkFrames& Delay :: tick( StkFrames& iFrames, StkFrames& oFrames, unsigned int iChannel, unsigned int oChannel )
+{
+#if defined(_STK_DEBUG_)
+ if ( iChannel >= iFrames.channels() || oChannel >= oFrames.channels() ) {
+ errorString_ << "Delay::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *iSamples = &iFrames[iChannel];
+ StkFloat *oSamples = &oFrames[oChannel];
+ unsigned int iHop = iFrames.channels(), oHop = oFrames.channels();
+ for ( unsigned int i=0; i<iFrames.frames(); i++, iSamples += iHop, oSamples += oHop ) {
+ inputs_[inPoint_++] = *iSamples * gain_;
+ if ( inPoint_ == inputs_.size() ) inPoint_ = 0;
+ *oSamples = inputs_[outPoint_++];
+ if ( outPoint_ == inputs_.size() ) outPoint_ = 0;
+ }
+
+ lastFrame_[0] = *(oSamples-oHop);
+ return iFrames;
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_DELAYA_H
+#define STK_DELAYA_H
+
+#include "Filter.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class DelayA
+ \brief STK allpass interpolating delay line class.
+
+ This class implements a fractional-length digital delay-line using
+ a first-order allpass filter. If the delay and maximum length are
+ not specified during instantiation, a fixed maximum length of 4095
+ and a delay of 0.5 is set.
+
+ An allpass filter has unity magnitude gain but variable phase
+ delay properties, making it useful in achieving fractional delays
+ without affecting a signal's frequency magnitude response. In
+ order to achieve a maximally flat phase delay response, the
+ minimum delay possible in this implementation is limited to a
+ value of 0.5.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class DelayA : public Filter
+{
+public:
+
+ //! Default constructor creates a delay-line with maximum length of 4095 samples and delay = 0.5.
+ /*!
+ An StkError will be thrown if the delay parameter is less than
+ zero, the maximum delay parameter is less than one, or the delay
+ parameter is greater than the maxDelay value.
+ */
+ DelayA( StkFloat delay = 0.5, unsigned long maxDelay = 4095 );
+
+ //! Class destructor.
+ ~DelayA();
+
+ //! Clears all internal states of the delay line.
+ void clear( void );
+
+ //! Set the maximum delay-line length.
+ /*!
+ This method should generally only be used during initial setup
+ of the delay line. If it is used between calls to the tick()
+ function, without a call to clear(), a signal discontinuity will
+ likely occur. If the current maximum length is greater than the
+ new length, no change will be made.
+ */
+ void setMaximumDelay( unsigned long delay );
+
+ //! Set the delay-line length
+ /*!
+ The valid range for \e delay is from 0.5 to the maximum delay-line length.
+ */
+ void setDelay( StkFloat delay );
+
+ //! Return the current delay-line length.
+ StkFloat getDelay( void ) const { return delay_; };
+
+ //! Return the value at \e tapDelay samples from the delay-line input.
+ /*!
+ The tap point is determined modulo the delay-line length and is
+ relative to the last input value (i.e., a tapDelay of zero returns
+ the last input value).
+ */
+ StkFloat contentsAt( unsigned long tapDelay );
+
+ //! Return the last computed output value.
+ StkFloat lastOut( void ) const { return lastFrame_[0]; };
+
+ //! Return the value which will be output by the next call to tick().
+ /*!
+ This method is valid only for delay settings greater than zero!
+ */
+ StkFloat nextOut( void );
+
+ //! Input one sample to the filter and return one output.
+ StkFloat tick( StkFloat input );
+
+ //! Take a channel of the StkFrames object as inputs to the filter and replace with corresponding outputs.
+ /*!
+ The StkFrames argument reference is returned. The \c channel
+ argument must be less than the number of channels in the
+ StkFrames argument (the first channel is specified by 0).
+ However, range checking is only performed if _STK_DEBUG_ is
+ defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
+
+ //! Take a channel of the \c iFrames object as inputs to the filter and write outputs to the \c oFrames object.
+ /*!
+ The \c iFrames object reference is returned. Each channel
+ argument must be less than the number of channels in the
+ corresponding StkFrames argument (the first channel is specified
+ by 0). However, range checking is only performed if _STK_DEBUG_
+ is defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& iFrames, StkFrames &oFrames, unsigned int iChannel = 0, unsigned int oChannel = 0 );
+
+protected:
+
+ unsigned long inPoint_;
+ unsigned long outPoint_;
+ StkFloat delay_;
+ StkFloat alpha_;
+ StkFloat coeff_;
+ StkFloat apInput_;
+ StkFloat nextOutput_;
+ bool doNextOut_;
+};
+
+inline StkFloat DelayA :: nextOut( void )
+{
+ if ( doNextOut_ ) {
+ // Do allpass interpolation delay.
+ nextOutput_ = -coeff_ * lastFrame_[0];
+ nextOutput_ += apInput_ + ( coeff_ * inputs_[outPoint_] );
+ doNextOut_ = false;
+ }
+
+ return nextOutput_;
+}
+
+inline StkFloat DelayA :: tick( StkFloat input )
+{
+ inputs_[inPoint_++] = input * gain_;
+
+ // Increment input pointer modulo length.
+ if ( inPoint_ == inputs_.size() )
+ inPoint_ = 0;
+
+ lastFrame_[0] = nextOut();
+ doNextOut_ = true;
+
+ // Save the allpass input and increment modulo length.
+ apInput_ = inputs_[outPoint_++];
+ if ( outPoint_ == inputs_.size() )
+ outPoint_ = 0;
+
+ return lastFrame_[0];
+}
+
+inline StkFrames& DelayA :: tick( StkFrames& frames, unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel >= frames.channels() ) {
+ errorString_ << "DelayA::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *samples = &frames[channel];
+ unsigned int hop = frames.channels();
+ for ( unsigned int i=0; i<frames.frames(); i++, samples += hop ) {
+ inputs_[inPoint_++] = *samples * gain_;
+ if ( inPoint_ == inputs_.size() ) inPoint_ = 0;
+ *samples = nextOut();
+ lastFrame_[0] = *samples;
+ doNextOut_ = true;
+ apInput_ = inputs_[outPoint_++];
+ if ( outPoint_ == inputs_.size() ) outPoint_ = 0;
+ }
+
+ return frames;
+}
+
+inline StkFrames& DelayA :: tick( StkFrames& iFrames, StkFrames& oFrames, unsigned int iChannel, unsigned int oChannel )
+{
+#if defined(_STK_DEBUG_)
+ if ( iChannel >= iFrames.channels() || oChannel >= oFrames.channels() ) {
+ errorString_ << "DelayA::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *iSamples = &iFrames[iChannel];
+ StkFloat *oSamples = &oFrames[oChannel];
+ unsigned int iHop = iFrames.channels(), oHop = oFrames.channels();
+ for ( unsigned int i=0; i<iFrames.frames(); i++, iSamples += iHop, oSamples += oHop ) {
+ inputs_[inPoint_++] = *iSamples * gain_;
+ if ( inPoint_ == inputs_.size() ) inPoint_ = 0;
+ *oSamples = nextOut();
+ lastFrame_[0] = *oSamples;
+ doNextOut_ = true;
+ apInput_ = inputs_[outPoint_++];
+ if ( outPoint_ == inputs_.size() ) outPoint_ = 0;
+ }
+
+ return iFrames;
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_DELAYL_H
+#define STK_DELAYL_H
+
+#include "Delay.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class DelayL
+ \brief STK linear interpolating delay line class.
+
+ This class implements a fractional-length digital delay-line using
+ first-order linear interpolation. If the delay and maximum length
+ are not specified during instantiation, a fixed maximum length of
+ 4095 and a delay of zero is set.
+
+ Linear interpolation is an efficient technique for achieving
+ fractional delay lengths, though it does introduce high-frequency
+ signal attenuation to varying degrees depending on the fractional
+ delay setting. The use of higher order Lagrange interpolators can
+ typically improve (minimize) this attenuation characteristic.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class DelayL : public Filter
+{
+public:
+
+ //! Default constructor creates a delay-line with maximum length of 4095 samples and zero delay.
+ /*!
+ An StkError will be thrown if the delay parameter is less than
+ zero, the maximum delay parameter is less than one, or the delay
+ parameter is greater than the maxDelay value.
+ */
+ DelayL( StkFloat delay = 0.0, unsigned long maxDelay = 4095 );
+
+ //! Class destructor.
+ ~DelayL();
+
+ //! Set the maximum delay-line length.
+ /*!
+ This method should generally only be used during initial setup
+ of the delay line. If it is used between calls to the tick()
+ function, without a call to clear(), a signal discontinuity will
+ likely occur. If the current maximum length is greater than the
+ new length, no change will be made.
+ */
+ void setMaximumDelay( unsigned long delay );
+
+ //! Set the delay-line length.
+ /*!
+ The valid range for \e delay is from 0 to the maximum delay-line length.
+ */
+ void setDelay( StkFloat delay );
+
+ //! Return the current delay-line length.
+ StkFloat getDelay( void ) const { return delay_; };
+
+ //! Return the value at \e tapDelay samples from the delay-line input.
+ /*!
+ The tap point is determined modulo the delay-line length and is
+ relative to the last input value (i.e., a tapDelay of zero returns
+ the last input value).
+ */
+ StkFloat contentsAt( unsigned long tapDelay );
+
+ //! Return the last computed output value.
+ StkFloat lastOut( void ) const { return lastFrame_[0]; };
+
+ //! Return the value which will be output by the next call to tick().
+ /*!
+ This method is valid only for delay settings greater than zero!
+ */
+ StkFloat nextOut( void );
+
+ //! Input one sample to the filter and return one output.
+ StkFloat tick( StkFloat input );
+
+ //! Take a channel of the StkFrames object as inputs to the filter and replace with corresponding outputs.
+ /*!
+ The StkFrames argument reference is returned. The \c channel
+ argument must be less than the number of channels in the
+ StkFrames argument (the first channel is specified by 0).
+ However, range checking is only performed if _STK_DEBUG_ is
+ defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
+
+ //! Take a channel of the \c iFrames object as inputs to the filter and write outputs to the \c oFrames object.
+ /*!
+ The \c iFrames object reference is returned. Each channel
+ argument must be less than the number of channels in the
+ corresponding StkFrames argument (the first channel is specified
+ by 0). However, range checking is only performed if _STK_DEBUG_
+ is defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& iFrames, StkFrames &oFrames, unsigned int iChannel = 0, unsigned int oChannel = 0 );
+
+ protected:
+
+ unsigned long inPoint_;
+ unsigned long outPoint_;
+ StkFloat delay_;
+ StkFloat alpha_;
+ StkFloat omAlpha_;
+ StkFloat nextOutput_;
+ bool doNextOut_;
+};
+
+inline StkFloat DelayL :: nextOut( void )
+{
+ if ( doNextOut_ ) {
+ // First 1/2 of interpolation
+ nextOutput_ = inputs_[outPoint_] * omAlpha_;
+ // Second 1/2 of interpolation
+ if (outPoint_+1 < inputs_.size())
+ nextOutput_ += inputs_[outPoint_+1] * alpha_;
+ else
+ nextOutput_ += inputs_[0] * alpha_;
+ doNextOut_ = false;
+ }
+
+ return nextOutput_;
+}
+
+inline StkFloat DelayL :: tick( StkFloat input )
+{
+ inputs_[inPoint_++] = input * gain_;
+
+ // Increment input pointer modulo length.
+ if ( inPoint_ == inputs_.size() )
+ inPoint_ = 0;
+
+ lastFrame_[0] = nextOut();
+ doNextOut_ = true;
+
+ // Increment output pointer modulo length.
+ if ( ++outPoint_ == inputs_.size() )
+ outPoint_ = 0;
+
+ return lastFrame_[0];
+}
+
+inline StkFrames& DelayL :: tick( StkFrames& frames, unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel >= frames.channels() ) {
+ errorString_ << "DelayL::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *samples = &frames[channel];
+ unsigned int hop = frames.channels();
+ for ( unsigned int i=0; i<frames.frames(); i++, samples += hop ) {
+ inputs_[inPoint_++] = *samples * gain_;
+ if ( inPoint_ == inputs_.size() ) inPoint_ = 0;
+ *samples = nextOut();
+ doNextOut_ = true;
+ if ( ++outPoint_ == inputs_.size() ) outPoint_ = 0;
+ }
+
+ lastFrame_[0] = *(samples-hop);
+ return frames;
+}
+
+inline StkFrames& DelayL :: tick( StkFrames& iFrames, StkFrames& oFrames, unsigned int iChannel, unsigned int oChannel )
+{
+#if defined(_STK_DEBUG_)
+ if ( iChannel >= iFrames.channels() || oChannel >= oFrames.channels() ) {
+ errorString_ << "DelayL::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *iSamples = &iFrames[iChannel];
+ StkFloat *oSamples = &oFrames[oChannel];
+ unsigned int iHop = iFrames.channels(), oHop = oFrames.channels();
+ for ( unsigned int i=0; i<iFrames.frames(); i++, iSamples += iHop, oSamples += oHop ) {
+ inputs_[inPoint_++] = *iSamples * gain_;
+ if ( inPoint_ == inputs_.size() ) inPoint_ = 0;
+ *oSamples = nextOut();
+ doNextOut_ = true;
+ if ( ++outPoint_ == inputs_.size() ) outPoint_ = 0;
+ }
+
+ lastFrame_[0] = *(oSamples-oHop);
+ return iFrames;
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_DRUMMER_H
+#define STK_DRUMMER_H
+
+#include "Instrmnt.h"
+#include "FileWvIn.h"
+#include "OnePole.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class Drummer
+ \brief STK drum sample player class.
+
+ This class implements a drum sampling
+ synthesizer using WvIn objects and one-pole
+ filters. The drum rawwave files are sampled
+ at 22050 Hz, but will be appropriately
+ interpolated for other sample rates. You can
+ specify the maximum polyphony (maximum number
+ of simultaneous voices) via a #define in the
+ Drummer.h.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+const int DRUM_NUMWAVES = 11;
+const int DRUM_POLYPHONY = 4;
+
+class Drummer : public Instrmnt
+{
+ public:
+ //! Class constructor.
+ /*!
+ An StkError will be thrown if the rawwave path is incorrectly set.
+ */
+ Drummer( void );
+
+ //! Class destructor.
+ ~Drummer( void );
+
+ //! Start a note with the given drum type and amplitude.
+ /*!
+ Use general MIDI drum instrument numbers, converted to
+ frequency values as if MIDI note numbers, to select a particular
+ instrument. An StkError will be thrown if the rawwave path is
+ incorrectly set.
+ */
+ void noteOn( StkFloat instrument, StkFloat amplitude );
+
+ //! Stop a note with the given amplitude (speed of decay).
+ void noteOff( StkFloat amplitude );
+
+ //! Compute and return one output sample.
+ StkFloat tick( unsigned int channel = 0 );
+
+ protected:
+
+ FileWvIn waves_[DRUM_POLYPHONY];
+ OnePole filters_[DRUM_POLYPHONY];
+ std::vector<int> soundOrder_;
+ std::vector<int> soundNumber_;
+ int nSounding_;
+};
+
+inline StkFloat Drummer :: tick( unsigned int )
+{
+ lastFrame_[0] = 0.0;
+ if ( nSounding_ == 0 ) return lastFrame_[0];
+
+ for ( int i=0; i<DRUM_POLYPHONY; i++ ) {
+ if ( soundOrder_[i] >= 0 ) {
+ if ( waves_[i].isFinished() ) {
+ // Re-order the list.
+ for ( int j=0; j<DRUM_POLYPHONY; j++ ) {
+ if ( soundOrder_[j] > soundOrder_[i] )
+ soundOrder_[j] -= 1;
+ }
+ soundOrder_[i] = -1;
+ nSounding_--;
+ }
+ else
+ lastFrame_[0] += filters_[i].tick( waves_[i].tick() );
+ }
+ }
+
+ return lastFrame_[0];
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_ECHO_H
+#define STK_ECHO_H
+
+#include "Effect.h"
+#include "Delay.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class Echo
+ \brief STK echo effect class.
+
+ This class implements an echo effect.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class Echo : public Effect
+{
+ public:
+ //! Class constructor, taking the longest desired delay length (one second default value).
+ /*!
+ The default delay value is set to 1/2 the maximum delay length.
+ */
+ Echo( unsigned long maximumDelay = (unsigned long) Stk::sampleRate() );
+
+ //! Reset and clear all internal state.
+ void clear();
+
+ //! Set the maximum delay line length in samples.
+ void setMaximumDelay( unsigned long delay );
+
+ //! Set the delay line length in samples.
+ void setDelay( unsigned long delay );
+
+ //! Return the last computed output value.
+ StkFloat lastOut( void ) const { return lastFrame_[0]; };
+
+ //! Input one sample to the effect and return one output.
+ StkFloat tick( StkFloat input );
+
+ //! Take a channel of the StkFrames object as inputs to the effect and replace with corresponding outputs.
+ /*!
+ The StkFrames argument reference is returned. The \c channel
+ argument must be less than the number of channels in the
+ StkFrames argument (the first channel is specified by 0).
+ However, range checking is only performed if _STK_DEBUG_ is
+ defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
+
+ //! Take a channel of the \c iFrames object as inputs to the effect and write outputs to the \c oFrames object.
+ /*!
+ The \c iFrames object reference is returned. Each channel
+ argument must be less than the number of channels in the
+ corresponding StkFrames argument (the first channel is specified
+ by 0). However, range checking is only performed if _STK_DEBUG_
+ is defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& iFrames, StkFrames &oFrames, unsigned int iChannel = 0, unsigned int oChannel = 0 );
+
+ protected:
+
+ Delay delayLine_;
+ unsigned long length_;
+
+};
+
+inline StkFloat Echo :: tick( StkFloat input )
+{
+ lastFrame_[0] = effectMix_ * ( delayLine_.tick( input ) - input ) + input;
+ return lastFrame_[0];
+}
+
+inline StkFrames& Echo :: tick( StkFrames& frames, unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel >= frames.channels() ) {
+ errorString_ << "Echo::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *samples = &frames[channel];
+ unsigned int hop = frames.channels();
+ for ( unsigned int i=0; i<frames.frames(); i++, samples += hop ) {
+ *samples = effectMix_ * ( delayLine_.tick( *samples ) - *samples ) + *samples;
+ }
+
+ lastFrame_[0] = *(samples-hop);
+ return frames;
+}
+
+inline StkFrames& Echo :: tick( StkFrames& iFrames, StkFrames& oFrames, unsigned int iChannel, unsigned int oChannel )
+{
+#if defined(_STK_DEBUG_)
+ if ( iChannel >= iFrames.channels() || oChannel >= oFrames.channels() ) {
+ errorString_ << "Echo::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *iSamples = &iFrames[iChannel];
+ StkFloat *oSamples = &oFrames[oChannel];
+ unsigned int iHop = iFrames.channels(), oHop = oFrames.channels();
+ for ( unsigned int i=0; i<iFrames.frames(); i++, iSamples += iHop, oSamples += oHop ) {
+ *oSamples = effectMix_ * ( delayLine_.tick( *iSamples ) - *iSamples ) + *iSamples;
+ }
+
+ lastFrame_[0] = *(oSamples-oHop);
+ return iFrames;
+}
+
+} // stk namespace
+
+#endif
+
--- /dev/null
+#ifndef STK_EFFECT_H
+#define STK_EFFECT_H
+
+#include "Stk.h"
+#include <cmath>
+
+namespace stk {
+
+/***************************************************/
+/*! \class Effect
+ \brief STK abstract effects parent class.
+
+ This class provides common functionality for STK effects
+ subclasses. It is general enough to support both monophonic and
+ polyphonic input/output classes.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class Effect : public Stk
+{
+ public:
+ //! Class constructor.
+ Effect( void ) { lastFrame_.resize( 1, 1, 0.0 ); };
+
+ //! Return the number of output channels for the class.
+ unsigned int channelsOut( void ) const { return lastFrame_.channels(); };
+
+ //! Return an StkFrames reference to the last output sample frame.
+ const StkFrames& lastFrame( void ) const { return lastFrame_; };
+
+ //! Reset and clear all internal state.
+ virtual void clear() = 0;
+
+ //! Set the mixture of input and "effected" levels in the output (0.0 = input only, 1.0 = effect only).
+ void setEffectMix( StkFloat mix );
+
+ protected:
+
+ // Returns true if argument value is prime.
+ bool isPrime( unsigned int number );
+
+ StkFrames lastFrame_;
+ StkFloat effectMix_;
+
+};
+
+inline void Effect :: setEffectMix( StkFloat mix )
+{
+ if ( mix < 0.0 ) {
+ errorString_ << "Effect::setEffectMix: mix parameter is less than zero ... setting to zero!";
+ handleError( StkError::WARNING );
+ effectMix_ = 0.0;
+ }
+ else if ( mix > 1.0 ) {
+ errorString_ << "Effect::setEffectMix: mix parameter is greater than 1.0 ... setting to one!";
+ handleError( StkError::WARNING );
+ effectMix_ = 1.0;
+ }
+ else
+ effectMix_ = mix;
+}
+
+inline bool Effect :: isPrime( unsigned int number )
+{
+ if ( number == 2 ) return true;
+ if ( number & 1 ) {
+ for ( int i=3; i<(int)sqrt((double)number)+1; i+=2 )
+ if ( (number % i) == 0 ) return false;
+ return true; // prime
+ }
+ else return false; // even
+}
+
+} // stk namespace
+
+#endif
+
--- /dev/null
+#ifndef STK_ENVELOPE_H
+#define STK_ENVELOPE_H
+
+#include "Generator.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class Envelope
+ \brief STK linear line envelope class.
+
+ This class implements a simple linear line envelope generator
+ which is capable of ramping to an arbitrary target value by a
+ specified \e rate. It also responds to simple \e keyOn and \e
+ keyOff messages, ramping to 1.0 on keyOn and to 0.0 on keyOff.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class Envelope : public Generator
+{
+ public:
+
+ //! Default constructor.
+ Envelope( void );
+
+ //! Class destructor.
+ ~Envelope( void );
+
+ //! Assignment operator.
+ Envelope& operator= ( const Envelope& e );
+
+ //! Set target = 1.
+ void keyOn( void ) { this->setTarget( 1.0 ); };
+
+ //! Set target = 0.
+ void keyOff( void ) { this->setTarget( 0.0 ); };
+
+ //! Set the \e rate.
+ void setRate( StkFloat rate );
+
+ //! Set the \e rate based on a time duration.
+ void setTime( StkFloat time );
+
+ //! Set the target value.
+ void setTarget( StkFloat target );
+
+ //! Set current and target values to \e value.
+ void setValue( StkFloat value );
+
+ //! Return the current envelope \e state (0 = at target, 1 otherwise).
+ int getState( void ) const { return state_; };
+
+ //! Return the last computed output value.
+ StkFloat lastOut( void ) const { return lastFrame_[0]; };
+
+ //! Compute and return one output sample.
+ StkFloat tick( void );
+
+ //! Fill a channel of the StkFrames object with computed outputs.
+ /*!
+ The \c channel argument must be less than the number of
+ channels in the StkFrames argument (the first channel is specified
+ by 0). However, range checking is only performed if _STK_DEBUG_
+ is defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
+
+ protected:
+
+ void sampleRateChanged( StkFloat newRate, StkFloat oldRate );
+
+ StkFloat value_;
+ StkFloat target_;
+ StkFloat rate_;
+ int state_;
+};
+
+inline void Envelope :: setRate( StkFloat rate )
+{
+#if defined(_STK_DEBUG_)
+ if ( rate < 0.0 ) {
+ errorString_ << "Envelope::setRate: negative rates not allowed ... correcting!";
+ handleError( StkError::WARNING );
+ rate_ = -rate;
+ }
+ else
+#endif
+ rate_ = rate;
+}
+
+inline void Envelope :: setTime( StkFloat time )
+{
+#if defined(_STK_DEBUG_)
+ if ( time < 0.0 ) {
+ errorString_ << "Envelope::setTime: negative times not allowed ... correcting!";
+ handleError( StkError::WARNING );
+ rate_ = 1.0 / ( -time * Stk::sampleRate() );
+ }
+ else
+#endif
+ rate_ = 1.0 / ( time * Stk::sampleRate() );
+}
+
+inline void Envelope :: setTarget( StkFloat target )
+{
+ target_ = target;
+ if ( value_ != target_ ) state_ = 1;
+}
+
+inline void Envelope :: setValue( StkFloat value )
+{
+ state_ = 0;
+ target_ = value;
+ value_ = value;
+}
+
+inline StkFloat Envelope :: tick( void )
+{
+ if ( state_ ) {
+ if ( target_ > value_ ) {
+ value_ += rate_;
+ if ( value_ >= target_ ) {
+ value_ = target_;
+ state_ = 0;
+ }
+ }
+ else {
+ value_ -= rate_;
+ if ( value_ <= target_ ) {
+ value_ = target_;
+ state_ = 0;
+ }
+ }
+ lastFrame_[0] = value_;
+ }
+
+ return value_;
+}
+
+inline StkFrames& Envelope :: tick( StkFrames& frames, unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel >= frames.channels() ) {
+ errorString_ << "Envelope::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *samples = &frames[channel];
+ unsigned int hop = frames.channels();
+ for ( unsigned int i=0; i<frames.frames(); i++, samples += hop )
+ *samples = tick();
+
+ return frames;
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_FM_H
+#define STK_FM_H
+
+#include "Instrmnt.h"
+#include "ADSR.h"
+#include "FileLoop.h"
+#include "SineWave.h"
+#include "TwoZero.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class FM
+ \brief STK abstract FM synthesis base class.
+
+ This class controls an arbitrary number of
+ waves and envelopes, determined via a
+ constructor argument.
+
+ Control Change Numbers:
+ - Control One = 2
+ - Control Two = 4
+ - LFO Speed = 11
+ - LFO Depth = 1
+ - ADSR 2 & 4 Target = 128
+
+ The basic Chowning/Stanford FM patent expired
+ in 1995, but there exist follow-on patents,
+ mostly assigned to Yamaha. If you are of the
+ type who should worry about this (making
+ money) worry away.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class FM : public Instrmnt
+{
+ public:
+ //! Class constructor, taking the number of wave/envelope operators to control.
+ /*!
+ An StkError will be thrown if the rawwave path is incorrectly set.
+ */
+ FM( unsigned int operators = 4 );
+
+ //! Class destructor.
+ virtual ~FM( void );
+
+ //! Reset and clear all wave and envelope states.
+ void clear( void );
+
+ //! Load the rawwave filenames in waves.
+ void loadWaves( const char **filenames );
+
+ //! Set instrument parameters for a particular frequency.
+ virtual void setFrequency( StkFloat frequency );
+
+ //! Set the frequency ratio for the specified wave.
+ void setRatio( unsigned int waveIndex, StkFloat ratio );
+
+ //! Set the gain for the specified wave.
+ void setGain( unsigned int waveIndex, StkFloat gain );
+
+ //! Set the modulation speed in Hz.
+ void setModulationSpeed( StkFloat mSpeed ) { vibrato_.setFrequency( mSpeed ); };
+
+ //! Set the modulation depth.
+ void setModulationDepth( StkFloat mDepth ) { modDepth_ = mDepth; };
+
+ //! Set the value of control1.
+ void setControl1( StkFloat cVal ) { control1_ = cVal * 2.0; };
+
+ //! Set the value of control1.
+ void setControl2( StkFloat cVal ) { control2_ = cVal * 2.0; };
+
+ //! Start envelopes toward "on" targets.
+ void keyOn( void );
+
+ //! Start envelopes toward "off" targets.
+ void keyOff( void );
+
+ //! Stop a note with the given amplitude (speed of decay).
+ void noteOff( StkFloat amplitude );
+
+ //! Perform the control change specified by \e number and \e value (0.0 - 128.0).
+ virtual void controlChange( int number, StkFloat value );
+
+ //! Compute and return one output sample.
+ virtual StkFloat tick( unsigned int ) = 0;
+
+ protected:
+
+ std::vector<ADSR *> adsr_;
+ std::vector<FileLoop *> waves_;
+ SineWave vibrato_;
+ TwoZero twozero_;
+ unsigned int nOperators_;
+ StkFloat baseFrequency_;
+ std::vector<StkFloat> ratios_;
+ std::vector<StkFloat> gains_;
+ StkFloat modDepth_;
+ StkFloat control1_;
+ StkFloat control2_;
+ StkFloat fmGains_[100];
+ StkFloat fmSusLevels_[16];
+ StkFloat fmAttTimes_[32];
+
+};
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_FMVOICES_H
+#define STK_FMVOICES_H
+
+#include "FM.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class FMVoices
+ \brief STK singing FM synthesis instrument.
+
+ This class implements 3 carriers and a common
+ modulator, also referred to as algorithm 6 of
+ the TX81Z.
+
+ \code
+ Algorithm 6 is :
+ /->1 -\
+ 4-|-->2 - +-> Out
+ \->3 -/
+ \endcode
+
+ Control Change Numbers:
+ - Vowel = 2
+ - Spectral Tilt = 4
+ - LFO Speed = 11
+ - LFO Depth = 1
+ - ADSR 2 & 4 Target = 128
+
+ The basic Chowning/Stanford FM patent expired
+ in 1995, but there exist follow-on patents,
+ mostly assigned to Yamaha. If you are of the
+ type who should worry about this (making
+ money) worry away.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class FMVoices : public FM
+{
+ public:
+ //! Class constructor.
+ /*!
+ An StkError will be thrown if the rawwave path is incorrectly set.
+ */
+ FMVoices( void );
+
+ //! Class destructor.
+ ~FMVoices( void );
+
+ //! Set instrument parameters for a particular frequency.
+ void setFrequency( StkFloat frequency );
+
+ //! Start a note with the given frequency and amplitude.
+ void noteOn( StkFloat frequency, StkFloat amplitude );
+
+ //! Perform the control change specified by \e number and \e value (0.0 - 128.0).
+ void controlChange( int number, StkFloat value );
+
+ //! Compute and return one output sample.
+ StkFloat tick( unsigned int channel = 0 );
+
+ protected:
+
+ int currentVowel_;
+ StkFloat tilt_[3];
+ StkFloat mods_[3];
+};
+
+inline StkFloat FMVoices :: tick( unsigned int )
+{
+ register StkFloat temp, temp2;
+
+ temp = gains_[3] * adsr_[3]->tick() * waves_[3]->tick();
+ temp2 = vibrato_.tick() * modDepth_ * 0.1;
+
+ waves_[0]->setFrequency(baseFrequency_ * (1.0 + temp2) * ratios_[0]);
+ waves_[1]->setFrequency(baseFrequency_ * (1.0 + temp2) * ratios_[1]);
+ waves_[2]->setFrequency(baseFrequency_ * (1.0 + temp2) * ratios_[2]);
+ waves_[3]->setFrequency(baseFrequency_ * (1.0 + temp2) * ratios_[3]);
+
+ waves_[0]->addPhaseOffset(temp * mods_[0]);
+ waves_[1]->addPhaseOffset(temp * mods_[1]);
+ waves_[2]->addPhaseOffset(temp * mods_[2]);
+ waves_[3]->addPhaseOffset( twozero_.lastOut() );
+ twozero_.tick( temp );
+ temp = gains_[0] * tilt_[0] * adsr_[0]->tick() * waves_[0]->tick();
+ temp += gains_[1] * tilt_[1] * adsr_[1]->tick() * waves_[1]->tick();
+ temp += gains_[2] * tilt_[2] * adsr_[2]->tick() * waves_[2]->tick();
+
+ lastFrame_[0] = temp * 0.33;
+ return lastFrame_[0];
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_FILELOOP_H
+#define STK_FILELOOP_H
+
+#include "FileWvIn.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class FileLoop
+ \brief STK file looping / oscillator class.
+
+ This class provides audio file looping functionality. Any audio
+ file that can be loaded by FileRead can be looped using this
+ class.
+
+ FileLoop supports multi-channel data. It is important to
+ distinguish the tick() method that computes a single frame (and
+ returns only the specified sample of a multi-channel frame) from
+ the overloaded one that takes an StkFrames object for
+ multi-channel and/or multi-frame data.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class FileLoop : protected FileWvIn
+{
+ public:
+ //! Default constructor.
+ FileLoop( unsigned long chunkThreshold = 1000000, unsigned long chunkSize = 1024 );
+
+ //! Class constructor that opens a specified file.
+ FileLoop( std::string fileName, bool raw = false, bool doNormalize = true,
+ unsigned long chunkThreshold = 1000000, unsigned long chunkSize = 1024 );
+
+ //! Class destructor.
+ ~FileLoop( void );
+
+ //! Open the specified file and load its data.
+ /*!
+ Data from a previously opened file will be overwritten by this
+ function. An StkError will be thrown if the file is not found,
+ its format is unknown, or a read error occurs. If the file data
+ is to be loaded incrementally from disk and normalization is
+ specified, a scaling will be applied with respect to fixed-point
+ limits. If the data format is floating-point, no scaling is
+ performed.
+ */
+ void openFile( std::string fileName, bool raw = false, bool doNormalize = true );
+
+ //! Close a file if one is open.
+ void closeFile( void ) { FileWvIn::closeFile(); };
+
+ //! Clear outputs and reset time (file) pointer to zero.
+ void reset( void ) { FileWvIn::reset(); };
+
+ //! Normalize data to a maximum of +-1.0.
+ /*!
+ This function has no effect when data is incrementally loaded
+ from disk.
+ */
+ void normalize( void ) { FileWvIn::normalize( 1.0 ); };
+
+ //! Normalize data to a maximum of \e +-peak.
+ /*!
+ This function has no effect when data is incrementally loaded
+ from disk.
+ */
+ void normalize( StkFloat peak ) { FileWvIn::normalize( peak ); };
+
+ //! Return the file size in sample frames.
+ unsigned long getSize( void ) const { return data_.frames(); };
+
+ //! Return the input file sample rate in Hz (not the data read rate).
+ /*!
+ WAV, SND, and AIF formatted files specify a sample rate in
+ their headers. STK RAW files have a sample rate of 22050 Hz
+ by definition. MAT-files are assumed to have a rate of 44100 Hz.
+ */
+ StkFloat getFileRate( void ) const { return data_.dataRate(); };
+
+ //! Set the data read rate in samples. The rate can be negative.
+ /*!
+ If the rate value is negative, the data is read in reverse order.
+ */
+ void setRate( StkFloat rate );
+
+ //! Set the data interpolation rate based on a looping frequency.
+ /*!
+ This function determines the interpolation rate based on the file
+ size and the current Stk::sampleRate. The \e frequency value
+ corresponds to file cycles per second. The frequency can be
+ negative, in which case the loop is read in reverse order.
+ */
+ void setFrequency( StkFloat frequency ) { this->setRate( file_.fileSize() * frequency / Stk::sampleRate() ); };
+
+ //! Increment the read pointer by \e time samples, modulo file size.
+ void addTime( StkFloat time );
+
+ //! Increment current read pointer by \e angle, relative to a looping frequency.
+ /*!
+ This function increments the read pointer based on the file
+ size and the current Stk::sampleRate. The \e anAngle value
+ is a multiple of file size.
+ */
+ void addPhase( StkFloat angle );
+
+ //! Add a phase offset to the current read pointer.
+ /*!
+ This function determines a time offset based on the file
+ size and the current Stk::sampleRate. The \e angle value
+ is a multiple of file size.
+ */
+ void addPhaseOffset( StkFloat angle );
+
+ //! Return the specified channel value of the last computed frame.
+ /*!
+ For multi-channel files, use the lastFrame() function to get
+ all values from the last computed frame. If no file data is
+ loaded, the returned value is 0.0. The \c channel argument must
+ be less than the number of channels in the file data (the first
+ channel is specified by 0). However, range checking is only
+ performed if _STK_DEBUG_ is defined during compilation, in which
+ case an out-of-range value will trigger an StkError exception.
+ */
+ StkFloat lastOut( unsigned int channel = 0 ) { return FileWvIn::lastOut( channel ); };
+
+ //! Compute a sample frame and return the specified \c channel value.
+ /*!
+ For multi-channel files, use the lastFrame() function to get
+ all values from the computed frame. If no file data is loaded,
+ the returned value is 0.0. The \c channel argument must be less
+ than the number of channels in the file data (the first channel is
+ specified by 0). However, range checking is only performed if
+ _STK_DEBUG_ is defined during compilation, in which case an
+ out-of-range value will trigger an StkError exception.
+ */
+ StkFloat tick( unsigned int channel = 0 );
+
+ //! Fill the StkFrames argument with computed frames and return the same reference.
+ /*!
+ The number of channels in the StkFrames argument should equal
+ the number of channels in the file data. However, this is only
+ checked if _STK_DEBUG_ is defined during compilation, in which
+ case an incompatibility will trigger an StkError exception. If no
+ file data is loaded, the function does nothing (a warning will be
+ issued if _STK_DEBUG_ is defined during compilation and
+ Stk::showWarnings() has been set to \e true).
+ */
+ StkFrames& tick( StkFrames& frames );
+
+ protected:
+
+ StkFrames firstFrame_;
+ StkFloat phaseOffset_;
+
+};
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_FILEREAD_H
+#define STK_FILEREAD_H
+
+#include "Stk.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class FileRead
+ \brief STK audio file input class.
+
+ This class provides input support for various
+ audio file formats. Multi-channel (>2)
+ soundfiles are supported. The file data is
+ returned via an external StkFrames object
+ passed to the read() function. This class
+ does not store its own copy of the file data,
+ rather the data is read directly from disk.
+
+ FileRead currently supports uncompressed WAV,
+ AIFF/AIFC, SND (AU), MAT-file (Matlab), and
+ STK RAW file formats. Signed integer (8-,
+ 16-, and 32-bit) and floating-point (32- and
+ 64-bit) data types are supported. Compressed
+ data types are not supported.
+
+ STK RAW files have no header and are assumed
+ to contain a monophonic stream of 16-bit
+ signed integers in big-endian byte order at a
+ sample rate of 22050 Hz. MAT-file data should
+ be saved in an array with each data channel
+ filling a matrix row. The sample rate for
+ MAT-files is assumed to be 44100 Hz.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class FileRead : public Stk
+{
+public:
+ //! Default constructor.
+ FileRead( void );
+
+ //! Overloaded constructor that opens a file during instantiation.
+ /*!
+ An StkError will be thrown if the file is not found or its
+ format is unknown or unsupported. The optional arguments allow a
+ headerless file type to be supported. If \c typeRaw is false (the
+ default), the subsequent parameters are ignored.
+ */
+ FileRead( std::string fileName, bool typeRaw = false, unsigned int nChannels = 1,
+ StkFormat format = STK_SINT16, StkFloat rate = 22050.0 );
+
+ //! Class destructor.
+ ~FileRead( void );
+
+ //! Open the specified file and determine its formatting.
+ /*!
+ An StkError will be thrown if the file is not found or its
+ format is unknown or unsupported. The optional arguments allow a
+ headerless file type to be supported. If \c typeRaw is false (the
+ default), the subsequent parameters are ignored.
+ */
+ void open( std::string fileName, bool typeRaw = false, unsigned int nChannels = 1,
+ StkFormat format = STK_SINT16, StkFloat rate = 22050.0 );
+
+ //! If a file is open, close it.
+ void close( void );
+
+ //! Returns \e true if a file is currently open.
+ bool isOpen( void );
+
+ //! Return the file size in sample frames.
+ unsigned long fileSize( void ) const { return fileSize_; };
+
+ //! Return the number of audio channels in the file.
+ unsigned int channels( void ) const { return channels_; };
+
+ //! Return the file sample rate in Hz.
+ /*!
+ WAV, SND, and AIF formatted files specify a sample rate in
+ their headers. By definition, STK RAW files have a sample rate of
+ 22050 Hz. MAT-files are assumed to have a rate of 44100 Hz.
+ */
+ StkFloat fileRate( void ) const { return fileRate_; };
+
+ //! Read sample frames from the file into an StkFrames object.
+ /*!
+ The number of sample frames to read will be determined from the
+ number of frames of the StkFrames argument. If this size is
+ larger than the available data in the file (given the file size
+ and starting frame index), the extra frames will be unaffected
+ (the StkFrames object will not be resized). Optional parameters
+ are provided to specify the starting sample frame within the file
+ (default = 0) and whether to normalize the data with respect to
+ fixed-point limits (default = true). An StkError will be thrown
+ if a file error occurs or if the number of channels in the
+ StkFrames argument is not equal to that in the file.
+ */
+ void read( StkFrames& buffer, unsigned long startFrame = 0, bool doNormalize = true );
+
+protected:
+
+ // Get STK RAW file information.
+ bool getRawInfo( const char *fileName, unsigned int nChannels,
+ StkFormat format, StkFloat rate );
+
+ // Get WAV file header information.
+ bool getWavInfo( const char *fileName );
+
+ // Get SND (AU) file header information.
+ bool getSndInfo( const char *fileName );
+
+ // Get AIFF file header information.
+ bool getAifInfo( const char *fileName );
+
+ // Get MAT-file header information.
+ bool getMatInfo( const char *fileName );
+
+ FILE *fd_;
+ bool byteswap_;
+ bool wavFile_;
+ unsigned long fileSize_;
+ unsigned long dataOffset_;
+ unsigned int channels_;
+ StkFormat dataType_;
+ StkFloat fileRate_;
+};
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_FILEWRITE_H
+#define STK_FILEWRITE_H
+
+#include "Stk.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class FileWrite
+ \brief STK audio file output class.
+
+ This class provides output support for various
+ audio file formats.
+
+ FileWrite writes samples to an audio file. It supports
+ multi-channel data.
+
+ FileWrite currently supports uncompressed WAV, AIFF, AIFC, SND
+ (AU), MAT-file (Matlab), and STK RAW file formats. Signed integer
+ (8-, 16-, and 32-bit) and floating- point (32- and 64-bit) data
+ types are supported. STK RAW files use 16-bit integers by
+ definition. MAT-files will always be written as 64-bit floats.
+ If a data type specification does not match the specified file
+ type, the data type will automatically be modified. Compressed
+ data types are not supported.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class FileWrite : public Stk
+{
+ public:
+
+ typedef unsigned long FILE_TYPE;
+
+ static const FILE_TYPE FILE_RAW; /*!< STK RAW file type. */
+ static const FILE_TYPE FILE_WAV; /*!< WAV file type. */
+ static const FILE_TYPE FILE_SND; /*!< SND (AU) file type. */
+ static const FILE_TYPE FILE_AIF; /*!< AIFF file type. */
+ static const FILE_TYPE FILE_MAT; /*!< Matlab MAT-file type. */
+
+ //! Default constructor.
+ FileWrite( void );
+
+ //! Overloaded constructor used to specify a file name, type, and data format with this object.
+ /*!
+ An StkError is thrown for invalid argument values or if an error occurs when initializing the output file.
+ */
+ FileWrite( std::string fileName, unsigned int nChannels = 1, FILE_TYPE type = FILE_WAV, Stk::StkFormat format = STK_SINT16 );
+
+ //! Class destructor.
+ virtual ~FileWrite();
+
+ //! Create a file of the specified type and name and output samples to it in the given data format.
+ /*!
+ An StkError is thrown for invalid argument values or if an error occurs when initializing the output file.
+ */
+ void open( std::string fileName, unsigned int nChannels = 1,
+ FileWrite::FILE_TYPE type = FILE_WAV, Stk::StkFormat format = STK_SINT16 );
+
+ //! If a file is open, write out samples in the queue and then close it.
+ void close( void );
+
+ //! Returns \e true if a file is currently open.
+ bool isOpen( void );
+
+ //! Write sample frames from the StkFrames object to the file.
+ /*!
+ An StkError will be thrown if the number of channels in the
+ StkFrames argument does not agree with the number of channels
+ specified when opening the file.
+ */
+ void write( StkFrames& buffer );
+
+ protected:
+
+ // Write STK RAW file header.
+ bool setRawFile( const char *fileName );
+
+ // Write WAV file header.
+ bool setWavFile( const char *fileName );
+
+ // Close WAV file, updating the header.
+ void closeWavFile( void );
+
+ // Write SND (AU) file header.
+ bool setSndFile( const char *fileName );
+
+ // Close SND file, updating the header.
+ void closeSndFile( void );
+
+ // Write AIFF file header.
+ bool setAifFile( const char *fileName );
+
+ // Close AIFF file, updating the header.
+ void closeAifFile( void );
+
+ // Write MAT-file header.
+ bool setMatFile( const char *fileName );
+
+ // Close MAT-file, updating the header.
+ void closeMatFile( void );
+
+ FILE *fd_;
+ FILE_TYPE fileType_;
+ StkFormat dataType_;
+ unsigned int channels_;
+ unsigned long frameCounter_;
+ bool byteswap_;
+
+};
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_FILEWVIN_H
+#define STK_FILEWVIN_H
+
+#include "WvIn.h"
+#include "FileRead.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class FileWvIn
+ \brief STK audio file input class.
+
+ This class inherits from WvIn. It provides a "tick-level"
+ interface to the FileRead class. It also provides variable-rate
+ playback functionality. Audio file support is provided by the
+ FileRead class. Linear interpolation is used for fractional read
+ rates.
+
+ FileWvIn supports multi-channel data. It is important to
+ distinguish the tick() method that computes a single frame (and
+ returns only the specified sample of a multi-channel frame) from
+ the overloaded one that takes an StkFrames object for
+ multi-channel and/or multi-frame data.
+
+ FileWvIn will either load the entire content of an audio file into
+ local memory or incrementally read file data from disk in chunks.
+ This behavior is controlled by the optional constructor arguments
+ \e chunkThreshold and \e chunkSize. File sizes greater than \e
+ chunkThreshold (in sample frames) will be read incrementally in
+ chunks of \e chunkSize each (also in sample frames).
+
+ When the file end is reached, subsequent calls to the tick()
+ functions return zeros and isFinished() returns \e true.
+
+ See the FileRead class for a description of the supported audio
+ file formats.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class FileWvIn : public WvIn
+{
+public:
+ //! Default constructor.
+ FileWvIn( unsigned long chunkThreshold = 1000000, unsigned long chunkSize = 1024 );
+
+ //! Overloaded constructor for file input.
+ /*!
+ An StkError will be thrown if the file is not found, its format is
+ unknown, or a read error occurs.
+ */
+ FileWvIn( std::string fileName, bool raw = false, bool doNormalize = true,
+ unsigned long chunkThreshold = 1000000, unsigned long chunkSize = 1024 );
+
+ //! Class destructor.
+ ~FileWvIn( void );
+
+ //! Open the specified file and load its data.
+ /*!
+ Data from a previously opened file will be overwritten by this
+ function. An StkError will be thrown if the file is not found,
+ its format is unknown, or a read error occurs. If the file data
+ is to be loaded incrementally from disk and normalization is
+ specified, a scaling will be applied with respect to fixed-point
+ limits. If the data format is floating-point, no scaling is
+ performed.
+ */
+ virtual void openFile( std::string fileName, bool raw = false, bool doNormalize = true );
+
+ //! Close a file if one is open.
+ virtual void closeFile( void );
+
+ //! Clear outputs and reset time (file) pointer to zero.
+ virtual void reset( void );
+
+ //! Normalize data to a maximum of +-1.0.
+ /*!
+ This function has no effect when data is incrementally loaded
+ from disk.
+ */
+ virtual void normalize( void );
+
+ //! Normalize data to a maximum of \e +-peak.
+ /*!
+ This function has no effect when data is incrementally loaded
+ from disk.
+ */
+ virtual void normalize( StkFloat peak );
+
+ //! Return the file size in sample frames.
+ virtual unsigned long getSize( void ) const { return data_.frames(); };
+
+ //! Return the input file sample rate in Hz (not the data read rate).
+ /*!
+ WAV, SND, and AIF formatted files specify a sample rate in
+ their headers. STK RAW files have a sample rate of 22050 Hz
+ by definition. MAT-files are assumed to have a rate of 44100 Hz.
+ */
+ virtual StkFloat getFileRate( void ) const { return data_.dataRate(); };
+
+ //! Query whether reading is complete.
+ bool isFinished( void ) const { return finished_; };
+
+ //! Set the data read rate in samples. The rate can be negative.
+ /*!
+ If the rate value is negative, the data is read in reverse order.
+ */
+ virtual void setRate( StkFloat rate );
+
+ //! Increment the read pointer by \e time samples.
+ /*!
+ Note that this function will not modify the interpolation flag status.
+ */
+ virtual void addTime( StkFloat time );
+
+ //! Turn linear interpolation on/off.
+ /*!
+ Interpolation is automatically off when the read rate is
+ an integer value. If interpolation is turned off for a
+ fractional rate, the time index is truncated to an integer
+ value.
+ */
+ void setInterpolate( bool doInterpolate ) { interpolate_ = doInterpolate; };
+
+ //! Return the specified channel value of the last computed frame.
+ /*!
+ If no file is loaded, the returned value is 0.0. The \c
+ channel argument must be less than the number of output channels,
+ which can be determined with the channelsOut() function (the first
+ channel is specified by 0). However, range checking is only
+ performed if _STK_DEBUG_ is defined during compilation, in which
+ case an out-of-range value will trigger an StkError exception. \sa
+ lastFrame()
+ */
+ StkFloat lastOut( unsigned int channel = 0 );
+
+ //! Compute a sample frame and return the specified \c channel value.
+ /*!
+ For multi-channel files, use the lastFrame() function to get
+ all values from the computed frame. If no file data is loaded,
+ the returned value is 0.0. The \c channel argument must be less
+ than the number of channels in the file data (the first channel is
+ specified by 0). However, range checking is only performed if
+ _STK_DEBUG_ is defined during compilation, in which case an
+ out-of-range value will trigger an StkError exception.
+ */
+ virtual StkFloat tick( unsigned int channel = 0 );
+
+ //! Fill the StkFrames argument with computed frames and return the same reference.
+ /*!
+ The number of channels in the StkFrames argument must equal
+ the number of channels in the file data. However, this is only
+ checked if _STK_DEBUG_ is defined during compilation, in which
+ case an incompatibility will trigger an StkError exception. If no
+ file data is loaded, the function does nothing (a warning will be
+ issued if _STK_DEBUG_ is defined during compilation).
+ */
+ virtual StkFrames& tick( StkFrames& frames );
+
+protected:
+
+ void sampleRateChanged( StkFloat newRate, StkFloat oldRate );
+
+ FileRead file_;
+ bool finished_;
+ bool interpolate_;
+ bool normalizing_;
+ bool chunking_;
+ StkFloat time_;
+ StkFloat rate_;
+ unsigned long chunkThreshold_;
+ unsigned long chunkSize_;
+ long chunkPointer_;
+
+};
+
+inline StkFloat FileWvIn :: lastOut( unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel >= data_.channels() ) {
+ errorString_ << "FileWvIn::lastOut(): channel argument and soundfile data are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ if ( finished_ ) return 0.0;
+ return lastFrame_[channel];
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_FILEWVOUT_H
+#define STK_FILEWVOUT_H
+
+#include "WvOut.h"
+#include "FileWrite.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class FileWvOut
+ \brief STK audio file output class.
+
+ This class inherits from WvOut. It provides a "tick-level"
+ interface to the FileWrite class.
+
+ FileWvOut writes samples to an audio file and supports
+ multi-channel data. It is important to distinguish the tick()
+ method that outputs a single sample to all channels in a sample
+ frame from the overloaded one that takes a reference to an
+ StkFrames object for multi-channel and/or multi-frame data.
+
+ See the FileWrite class for a description of the supported audio
+ file formats.
+
+ Currently, FileWvOut is non-interpolating and the output rate is
+ always Stk::sampleRate().
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class FileWvOut : public WvOut
+{
+ public:
+
+ //! Default constructor with optional output buffer size argument.
+ /*!
+ The output buffer size defines the number of frames that are
+ accumulated between writes to disk.
+ */
+ FileWvOut( unsigned int bufferFrames = 1024 );
+
+ //! Overloaded constructor used to specify a file name, type, and data format with this object.
+ /*!
+ An StkError is thrown for invalid argument values or if an error occurs when initializing the output file.
+ */
+ FileWvOut( std::string fileName,
+ unsigned int nChannels = 1,
+ FileWrite::FILE_TYPE type = FileWrite::FILE_WAV,
+ Stk::StkFormat format = STK_SINT16,
+ unsigned int bufferFrames = 1024 );
+
+ //! Class destructor.
+ virtual ~FileWvOut();
+
+ //! Open a new file with the specified parameters.
+ /*!
+ If a file was previously open, it will be closed. An StkError
+ will be thrown if any of the specified arguments are invalid or a
+ file error occurs during opening.
+ */
+ void openFile( std::string fileName,
+ unsigned int nChannels,
+ FileWrite::FILE_TYPE type,
+ Stk::StkFormat format );
+
+ //! Close a file if one is open.
+ /*!
+ Any data remaining in the internal buffer will be written to
+ the file before closing.
+ */
+ void closeFile( void );
+
+ //! Output a single sample to all channels in a sample frame.
+ /*!
+ An StkError is thrown if an output error occurs.
+ */
+ void tick( const StkFloat sample );
+
+ //! Output the StkFrames data.
+ /*!
+ An StkError will be thrown if an output error occurs. An
+ StkError will also be thrown if _STK_DEBUG_ is defined during
+ compilation and there is an incompatability between the number of
+ channels in the FileWvOut object and that in the StkFrames object.
+ */
+ void tick( const StkFrames& frames );
+
+ protected:
+
+ void incrementFrame( void );
+
+ FileWrite file_;
+ unsigned int bufferFrames_;
+ unsigned int bufferIndex_;
+ unsigned int iData_;
+
+};
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_FILTER_H
+#define STK_FILTER_H
+
+#include "Stk.h"
+#include <vector>
+
+namespace stk {
+
+/***************************************************/
+/*! \class Filter
+ \brief STK abstract filter class.
+
+ This class provides limited common functionality for STK digital
+ filter subclasses. It is general enough to support both
+ monophonic and polyphonic input/output classes.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class Filter : public Stk
+{
+public:
+ //! Class constructor.
+ Filter( void ) { gain_ = 1.0; channelsIn_ = 1; lastFrame_.resize( 1, 1, 0.0 ); };
+
+ //! Return the number of input channels for the class.
+ unsigned int channelsIn( void ) const { return channelsIn_; };
+
+ //! Return the number of output channels for the class.
+ unsigned int channelsOut( void ) const { return lastFrame_.channels(); };
+
+ //! Clears all internal states of the filter.
+ virtual void clear( void );
+
+ //! Set the filter gain.
+ /*!
+ The gain is applied at the filter input and does not affect the
+ coefficient values. The default gain value is 1.0.
+ */
+ void setGain( StkFloat gain ) { gain_ = gain; };
+
+ //! Return the current filter gain.
+ StkFloat getGain( void ) const { return gain_; };
+
+ //! Return an StkFrames reference to the last output sample frame.
+ const StkFrames& lastFrame( void ) const { return lastFrame_; };
+
+ //! Take a channel of the StkFrames object as inputs to the filter and replace with corresponding outputs.
+ /*!
+ The StkFrames argument reference is returned. The \c channel
+ argument must be less than the number of channels in the
+ StkFrames argument (the first channel is specified by 0).
+ However, range checking is only performed if _STK_DEBUG_ is
+ defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ virtual StkFrames& tick( StkFrames& frames, unsigned int channel = 0 ) = 0;
+
+protected:
+
+ unsigned int channelsIn_;
+ StkFrames lastFrame_;
+
+ StkFloat gain_;
+ std::vector<StkFloat> b_;
+ std::vector<StkFloat> a_;
+ StkFrames outputs_;
+ StkFrames inputs_;
+
+};
+
+inline void Filter :: clear( void )
+{
+ unsigned int i;
+ for ( i=0; i<inputs_.size(); i++ )
+ inputs_[i] = 0.0;
+ for ( i=0; i<outputs_.size(); i++ )
+ outputs_[i] = 0.0;
+ for ( i=0; i<lastFrame_.size(); i++ )
+ lastFrame_[i] = 0.0;
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_FIR_H
+#define STK_FIR_H
+
+#include "Filter.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class Fir
+ \brief STK general finite impulse response filter class.
+
+ This class provides a generic digital filter structure that can be
+ used to implement FIR filters. For filters with feedback terms,
+ the Iir class should be used.
+
+ In particular, this class implements the standard difference
+ equation:
+
+ y[n] = b[0]*x[n] + ... + b[nb]*x[n-nb]
+
+ The \e gain parameter is applied at the filter input and does not
+ affect the coefficient values. The default gain value is 1.0.
+ This structure results in one extra multiply per computed sample,
+ but allows easy control of the overall filter gain.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class Fir : public Filter
+{
+public:
+ //! Default constructor creates a zero-order pass-through "filter".
+ Fir( void );
+
+ //! Overloaded constructor which takes filter coefficients.
+ /*!
+ An StkError can be thrown if the coefficient vector size is
+ zero.
+ */
+ Fir( std::vector<StkFloat> &coefficients );
+
+ //! Class destructor.
+ ~Fir( void );
+
+ //! Set filter coefficients.
+ /*!
+ An StkError can be thrown if the coefficient vector size is
+ zero. The internal state of the filter is not cleared unless the
+ \e clearState flag is \c true.
+ */
+ void setCoefficients( std::vector<StkFloat> &coefficients, bool clearState = false );
+
+ //! Return the last computed output value.
+ StkFloat lastOut( void ) const { return lastFrame_[0]; };
+
+ //! Input one sample to the filter and return one output.
+ StkFloat tick( StkFloat input );
+
+ //! Take a channel of the StkFrames object as inputs to the filter and replace with corresponding outputs.
+ /*!
+ The StkFrames argument reference is returned. The \c channel
+ argument must be less than the number of channels in the
+ StkFrames argument (the first channel is specified by 0).
+ However, range checking is only performed if _STK_DEBUG_ is
+ defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
+
+ //! Take a channel of the \c iFrames object as inputs to the filter and write outputs to the \c oFrames object.
+ /*!
+ The \c iFrames object reference is returned. Each channel
+ argument must be less than the number of channels in the
+ corresponding StkFrames argument (the first channel is specified
+ by 0). However, range checking is only performed if _STK_DEBUG_
+ is defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& iFrames, StkFrames &oFrames, unsigned int iChannel = 0, unsigned int oChannel = 0 );
+
+protected:
+
+};
+
+inline StkFloat Fir :: tick( StkFloat input )
+{
+ lastFrame_[0] = 0.0;
+ inputs_[0] = gain_ * input;
+
+ for ( unsigned int i=b_.size()-1; i>0; i-- ) {
+ lastFrame_[0] += b_[i] * inputs_[i];
+ inputs_[i] = inputs_[i-1];
+ }
+ lastFrame_[0] += b_[0] * inputs_[0];
+
+ return lastFrame_[0];
+}
+
+inline StkFrames& Fir :: tick( StkFrames& frames, unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel >= frames.channels() ) {
+ errorString_ << "Fir::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *samples = &frames[channel];
+ unsigned int i, hop = frames.channels();
+ for ( unsigned int j=0; j<frames.frames(); j++, samples += hop ) {
+ inputs_[0] = gain_ * *samples;
+ *samples = 0.0;
+
+ for ( i=b_.size()-1; i>0; i-- ) {
+ *samples += b_[i] * inputs_[i];
+ inputs_[i] = inputs_[i-1];
+ }
+ *samples += b_[0] * inputs_[0];
+ }
+
+ lastFrame_[0] = *(samples-hop);
+ return frames;
+}
+
+inline StkFrames& Fir :: tick( StkFrames& iFrames, StkFrames& oFrames, unsigned int iChannel, unsigned int oChannel )
+{
+#if defined(_STK_DEBUG_)
+ if ( iChannel >= iFrames.channels() || oChannel >= oFrames.channels() ) {
+ errorString_ << "Fir::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *iSamples = &iFrames[iChannel];
+ StkFloat *oSamples = &oFrames[oChannel];
+ unsigned int i, iHop = iFrames.channels(), oHop = oFrames.channels();
+ for ( unsigned int j=0; j<iFrames.frames(); j++, iSamples += iHop, oSamples += oHop ) {
+ inputs_[0] = gain_ * *iSamples;
+ *oSamples = 0.0;
+
+ for ( i=b_.size()-1; i>0; i-- ) {
+ *oSamples += b_[i] * inputs_[i];
+ inputs_[i] = inputs_[i-1];
+ }
+ *oSamples += b_[0] * inputs_[0];
+ }
+
+ lastFrame_[0] = *(oSamples-oHop);
+ return iFrames;
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_FLUTE_H
+#define STK_FLUTE_H
+
+#include "Instrmnt.h"
+#include "JetTable.h"
+#include "DelayL.h"
+#include "OnePole.h"
+#include "PoleZero.h"
+#include "Noise.h"
+#include "ADSR.h"
+#include "SineWave.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class Flute
+ \brief STK flute physical model class.
+
+ This class implements a simple flute
+ physical model, as discussed by Karjalainen,
+ Smith, Waryznyk, etc. The jet model uses
+ a polynomial, a la Cook.
+
+ This is a digital waveguide model, making its
+ use possibly subject to patents held by Stanford
+ University, Yamaha, and others.
+
+ Control Change Numbers:
+ - Jet Delay = 2
+ - Noise Gain = 4
+ - Vibrato Frequency = 11
+ - Vibrato Gain = 1
+ - Breath Pressure = 128
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class Flute : public Instrmnt
+{
+ public:
+ //! Class constructor, taking the lowest desired playing frequency.
+ /*!
+ An StkError will be thrown if the rawwave path is incorrectly set.
+ */
+ Flute( StkFloat lowestFrequency );
+
+ //! Class destructor.
+ ~Flute( void );
+
+ //! Reset and clear all internal state.
+ void clear( void );
+
+ //! Set instrument parameters for a particular frequency.
+ void setFrequency( StkFloat frequency );
+
+ //! Set the reflection coefficient for the jet delay (-1.0 - 1.0).
+ void setJetReflection( StkFloat coefficient );
+
+ //! Set the reflection coefficient for the air column delay (-1.0 - 1.0).
+ void setEndReflection( StkFloat coefficient );
+
+ //! Set the length of the jet delay in terms of a ratio of jet delay to air column delay lengths.
+ void setJetDelay( StkFloat aRatio );
+
+ //! Apply breath velocity to instrument with given amplitude and rate of increase.
+ void startBlowing( StkFloat amplitude, StkFloat rate );
+
+ //! Decrease breath velocity with given rate of decrease.
+ void stopBlowing( StkFloat rate );
+
+ //! Start a note with the given frequency and amplitude.
+ void noteOn( StkFloat frequency, StkFloat amplitude );
+
+ //! Stop a note with the given amplitude (speed of decay).
+ void noteOff( StkFloat amplitude );
+
+ //! Perform the control change specified by \e number and \e value (0.0 - 128.0).
+ void controlChange( int number, StkFloat value );
+
+ //! Compute and return one output sample.
+ StkFloat tick( unsigned int channel = 0 );
+
+ protected:
+
+ DelayL jetDelay_;
+ DelayL boreDelay_;
+ JetTable jetTable_;
+ OnePole filter_;
+ PoleZero dcBlock_;
+ Noise noise_;
+ ADSR adsr_;
+ SineWave vibrato_;
+ unsigned long length_;
+ StkFloat lastFrequency_;
+ StkFloat maxPressure_;
+ StkFloat jetReflection_;
+ StkFloat endReflection_;
+ StkFloat noiseGain_;
+ StkFloat vibratoGain_;
+ StkFloat outputGain_;
+ StkFloat jetRatio_;
+
+};
+
+inline StkFloat Flute :: tick( unsigned int )
+{
+ StkFloat pressureDiff;
+ StkFloat breathPressure;
+
+ // Calculate the breath pressure (envelope + noise + vibrato)
+ breathPressure = maxPressure_ * adsr_.tick();
+ breathPressure += breathPressure * ( noiseGain_ * noise_.tick() + vibratoGain_ * vibrato_.tick() );
+
+ StkFloat temp = filter_.tick( boreDelay_.lastOut() );
+ temp = dcBlock_.tick( temp ); // Block DC on reflection.
+
+ pressureDiff = breathPressure - (jetReflection_ * temp);
+ pressureDiff = jetDelay_.tick( pressureDiff );
+ pressureDiff = jetTable_.tick( pressureDiff ) + (endReflection_ * temp);
+ lastFrame_[0] = (StkFloat) 0.3 * boreDelay_.tick( pressureDiff );
+
+ lastFrame_[0] *= outputGain_;
+ return lastFrame_[0];
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_FORMSWEP_H
+#define STK_FORMSWEP_H
+
+#include "Filter.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class FormSwep
+ \brief STK sweepable formant filter class.
+
+ This class implements a formant (resonance) which can be "swept"
+ over time from one frequency setting to another. It provides
+ methods for controlling the sweep rate and target frequency.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class FormSwep : public Filter
+{
+ public:
+
+ //! Default constructor creates a second-order pass-through filter.
+ FormSwep( void );
+
+ //! Class destructor.
+ ~FormSwep();
+
+ //! A function to enable/disable the automatic updating of class data when the STK sample rate changes.
+ void ignoreSampleRateChange( bool ignore = true ) { ignoreSampleRateChange_ = ignore; };
+
+ //! Sets the filter coefficients for a resonance at \e frequency (in Hz).
+ /*!
+ This method determines the filter coefficients corresponding to
+ two complex-conjugate poles with the given \e frequency (in Hz)
+ and \e radius from the z-plane origin. The filter zeros are
+ placed at z = 1, z = -1, and the coefficients are then normalized to
+ produce a constant unity gain (independent of the filter \e gain
+ parameter). The resulting filter frequency response has a
+ resonance at the given \e frequency. The closer the poles are to
+ the unit-circle (\e radius close to one), the narrower the
+ resulting resonance width.
+ */
+ void setResonance( StkFloat frequency, StkFloat radius );
+
+ //! Set both the current and target resonance parameters.
+ void setStates( StkFloat frequency, StkFloat radius, StkFloat gain = 1.0 );
+
+ //! Set target resonance parameters.
+ void setTargets( StkFloat frequency, StkFloat radius, StkFloat gain = 1.0 );
+
+ //! Set the sweep rate (between 0.0 - 1.0).
+ /*!
+ The formant parameters are varied in increments of the
+ sweep rate between their current and target values.
+ A sweep rate of 1.0 will produce an immediate change in
+ resonance parameters from their current values to the
+ target values. A sweep rate of 0.0 will produce no
+ change in resonance parameters.
+ */
+ void setSweepRate( StkFloat rate );
+
+ //! Set the sweep rate in terms of a time value in seconds.
+ /*!
+ This method adjusts the sweep rate based on a
+ given time for the formant parameters to reach
+ their target values.
+ */
+ void setSweepTime( StkFloat time );
+
+ //! Return the last computed output value.
+ StkFloat lastOut( void ) const { return lastFrame_[0]; };
+
+ //! Input one sample to the filter and return a reference to one output.
+ StkFloat tick( StkFloat input );
+
+ //! Take a channel of the StkFrames object as inputs to the filter and replace with corresponding outputs.
+ /*!
+ The StkFrames argument reference is returned. The \c channel
+ argument must be less than the number of channels in the
+ StkFrames argument (the first channel is specified by 0).
+ However, range checking is only performed if _STK_DEBUG_ is
+ defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
+
+ //! Take a channel of the \c iFrames object as inputs to the filter and write outputs to the \c oFrames object.
+ /*!
+ The \c iFrames object reference is returned. Each channel
+ argument must be less than the number of channels in the
+ corresponding StkFrames argument (the first channel is specified
+ by 0). However, range checking is only performed if _STK_DEBUG_
+ is defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& iFrames, StkFrames &oFrames, unsigned int iChannel = 0, unsigned int oChannel = 0 );
+
+ protected:
+
+ virtual void sampleRateChanged( StkFloat newRate, StkFloat oldRate );
+
+ bool dirty_;
+ StkFloat frequency_;
+ StkFloat radius_;
+ StkFloat startFrequency_;
+ StkFloat startRadius_;
+ StkFloat startGain_;
+ StkFloat targetFrequency_;
+ StkFloat targetRadius_;
+ StkFloat targetGain_;
+ StkFloat deltaFrequency_;
+ StkFloat deltaRadius_;
+ StkFloat deltaGain_;
+ StkFloat sweepState_;
+ StkFloat sweepRate_;
+
+};
+
+inline StkFloat FormSwep :: tick( StkFloat input )
+{
+ if ( dirty_ ) {
+ sweepState_ += sweepRate_;
+ if ( sweepState_ >= 1.0 ) {
+ sweepState_ = 1.0;
+ dirty_ = false;
+ radius_ = targetRadius_;
+ frequency_ = targetFrequency_;
+ gain_ = targetGain_;
+ }
+ else {
+ radius_ = startRadius_ + (deltaRadius_ * sweepState_);
+ frequency_ = startFrequency_ + (deltaFrequency_ * sweepState_);
+ gain_ = startGain_ + (deltaGain_ * sweepState_);
+ }
+ this->setResonance( frequency_, radius_ );
+ }
+
+ inputs_[0] = gain_ * input;
+ lastFrame_[0] = b_[0] * inputs_[0] + b_[1] * inputs_[1] + b_[2] * inputs_[2];
+ lastFrame_[0] -= a_[2] * outputs_[2] + a_[1] * outputs_[1];
+ inputs_[2] = inputs_[1];
+ inputs_[1] = inputs_[0];
+ outputs_[2] = outputs_[1];
+ outputs_[1] = lastFrame_[0];
+
+ return lastFrame_[0];
+}
+
+inline StkFrames& FormSwep :: tick( StkFrames& frames, unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel >= frames.channels() ) {
+ errorString_ << "FormSwep::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *samples = &frames[channel];
+ unsigned int hop = frames.channels();
+ for ( unsigned int i=0; i<frames.frames(); i++, samples += hop )
+ *samples = tick( *samples );
+
+ return frames;
+}
+
+inline StkFrames& FormSwep :: tick( StkFrames& iFrames, StkFrames& oFrames, unsigned int iChannel, unsigned int oChannel )
+{
+#if defined(_STK_DEBUG_)
+ if ( iChannel >= iFrames.channels() || oChannel >= oFrames.channels() ) {
+ errorString_ << "FormSwep::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *iSamples = &iFrames[iChannel];
+ StkFloat *oSamples = &oFrames[oChannel];
+ unsigned int iHop = iFrames.channels(), oHop = oFrames.channels();
+ for ( unsigned int i=0; i<iFrames.frames(); i++, iSamples += iHop, oSamples += oHop )
+ *oSamples = tick( *iSamples );
+
+ return iFrames;
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_FUNCTION_H
+#define STK_FUNCTION_H
+
+#include "Stk.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class Function
+ \brief STK abstract function parent class.
+
+ This class provides common functionality for STK classes that
+ implement tables or other types of input to output function
+ mappings.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class Function : public Stk
+{
+ public:
+ //! Class constructor.
+ Function( void ) { lastFrame_.resize( 1, 1, 0.0 ); };
+
+ //! Return the last computed output sample.
+ StkFloat lastOut( void ) const { return lastFrame_[0]; };
+
+ //! Take one sample input and compute one sample of output.
+ virtual StkFloat tick( StkFloat input ) = 0;
+
+ protected:
+
+ StkFrames lastFrame_;
+
+};
+
+} // stk namespace
+
+#endif
+
--- /dev/null
+#ifndef STK_GENERATOR_H
+#define STK_GENERATOR_H
+
+#include "Stk.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class Generator
+ \brief STK abstract unit generator parent class.
+
+ This class provides limited common functionality for STK unit
+ generator sample-source subclasses. It is general enough to
+ support both monophonic and polyphonic output classes.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class Generator : public Stk
+{
+ public:
+
+ //! Class constructor.
+ Generator( void ) { lastFrame_.resize( 1, 1, 0.0 ); };
+
+ //! Return the number of output channels for the class.
+ unsigned int channelsOut( void ) const { return lastFrame_.channels(); };
+
+ //! Return an StkFrames reference to the last output sample frame.
+ const StkFrames& lastFrame( void ) const { return lastFrame_; };
+
+ //! Fill the StkFrames object with computed sample frames, starting at the specified channel.
+ /*!
+ The \c channel argument plus the number of output channels must
+ be less than the number of channels in the StkFrames argument (the
+ first channel is specified by 0). However, range checking is only
+ performed if _STK_DEBUG_ is defined during compilation, in which
+ case an out-of-range value will trigger an StkError exception.
+ */
+ virtual StkFrames& tick( StkFrames& frames, unsigned int channel = 0 ) = 0;
+
+ protected:
+
+ StkFrames lastFrame_;
+};
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_GRANULATE_H
+#define STK_GRANULATE_H
+
+#include <vector>
+#include "Generator.h"
+#include "Envelope.h"
+#include "Noise.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class Granulate
+ \brief STK granular synthesis class.
+
+ This class implements a real-time granular synthesis algorithm
+ that operates on an input soundfile. Multi-channel files are
+ supported. Various functions are provided to allow control over
+ voice and grain parameters.
+
+ The functionality of this class is based on the program MacPod by
+ Chris Rolfe and Damian Keller, though there are likely to be a
+ number of differences in the actual implementation.
+
+ by Gary Scavone, 2005 - 2010.
+*/
+/***************************************************/
+
+class Granulate: public Generator
+{
+ public:
+ //! Default constructor.
+ Granulate( void );
+
+ //! Constructor taking input audio file and number of voices arguments.
+ Granulate( unsigned int nVoices, std::string fileName, bool typeRaw = false );
+
+ //! Class destructor.
+ ~Granulate( void );
+
+ //! Load a monophonic soundfile to be "granulated".
+ /*!
+ An StkError will be thrown if the file is not found, its format
+ is unknown or unsupported, or the file has more than one channel.
+ */
+ void openFile( std::string fileName, bool typeRaw = false );
+
+ //! Reset the file pointer and all existing grains to the file start.
+ /*!
+ Multiple grains are offset from one another in time by grain
+ duration / nVoices.
+ */
+ void reset( void );
+
+ //! Set the number of simultaneous grain "voices" to use.
+ /*!
+ Multiple grains are offset from one another in time by grain
+ duration / nVoices. For this reason, it is best to set the grain
+ parameters before calling this function (during initialization).
+ */
+ void setVoices( unsigned int nVoices = 1 );
+
+ //! Set the stretch factor used for grain playback (1 - 1000).
+ /*!
+ Granular synthesis allows for time-stetching without affecting
+ the original pitch of a sound. A stretch factor of 4 will produce
+ a resulting sound of length 4 times the orignal sound. The
+ default parameter of 1 produces no stretching.
+ */
+ void setStretch( unsigned int stretchFactor = 1 );
+
+ //! Set global grain parameters used to determine individual grain settings.
+ /*!
+ Each grain is defined as having a length of \e duration
+ milliseconds which must be greater than zero. For values of \e
+ rampPercent (0 - 100) greater than zero, a linear envelope will be
+ applied to each grain. If \e rampPercent = 100, the resultant
+ grain "window" is triangular while \e rampPercent = 50 produces a
+ trapezoidal window. In addition, each grain can have a time delay
+ of length \e delay and a grain pointer increment of length \e
+ offset, which can be negative, before the next ramp onset (in
+ milliseconds). The \e offset parameter controls grain pointer
+ jumps between enveloped grain segments, while the \e delay
+ parameter causes grain calculations to pause between grains. The
+ actual values calculated for each grain will be randomized by a
+ factor set using the setRandomFactor() function.
+ */
+ void setGrainParameters( unsigned int duration = 30, unsigned int rampPercent = 50,
+ int offset = 0, unsigned int delay = 0 );
+
+ //! This factor is used when setting individual grain parameters (0.0 - 1.0).
+ /*!
+ This random factor is applied when all grain state durations
+ are calculated. If set to 0.0, no randomness occurs. When
+ randomness = 1.0, a grain segment of length \e duration will be
+ randomly augmented by up to +- \e duration seconds (i.e., a 30
+ millisecond length will be augmented by an extra length of up to
+ +30 or -30 milliseconds).
+ */
+ void setRandomFactor( StkFloat randomness = 0.1 );
+
+ //! Return the specified channel value of the last computed frame.
+ /*!
+ The \c channel argument must be less than the number of output
+ channels, which can be determined with the channelsOut() function
+ (the first channel is specified by 0). However, range checking is
+ only performed if _STK_DEBUG_ is defined during compilation, in
+ which case an out-of-range value will trigger an StkError
+ exception. \sa lastFrame()
+ */
+ StkFloat lastOut( unsigned int channel = 0 );
+
+ //! Compute one sample frame and return the specified \c channel value.
+ StkFloat tick( unsigned int channel = 0 );
+
+ //! Fill the StkFrames object with computed sample frames, starting at the specified channel.
+ /*!
+ The \c channel argument plus the number of output channels must
+ be less than the number of channels in the StkFrames argument (the
+ first channel is specified by 0). However, range checking is only
+ performed if _STK_DEBUG_ is defined during compilation, in which
+ case an out-of-range value will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
+
+ enum GrainState {
+ GRAIN_STOPPED,
+ GRAIN_FADEIN,
+ GRAIN_SUSTAIN,
+ GRAIN_FADEOUT
+ };
+
+ protected:
+
+ struct Grain {
+ StkFloat eScaler;
+ StkFloat eRate;
+ unsigned long attackCount;
+ unsigned long sustainCount;
+ unsigned long decayCount;
+ unsigned long delayCount;
+ unsigned long counter;
+ //unsigned long pointer;
+ StkFloat pointer;
+ unsigned long startPointer;
+ unsigned int repeats;
+ GrainState state;
+
+ // Default constructor.
+ Grain()
+ :eScaler(0.0), eRate(0.0), attackCount(0), sustainCount(0), decayCount(0),
+ delayCount(0), counter(0), pointer(0), startPointer(0), repeats(0), state(GRAIN_STOPPED) {}
+ };
+
+ void calculateGrain( Granulate::Grain& grain );
+
+ StkFrames data_;
+ std::vector<Grain> grains_;
+ Noise noise;
+ //long gPointer_;
+ StkFloat gPointer_;
+
+ // Global grain parameters.
+ unsigned int gDuration_;
+ unsigned int gRampPercent_;
+ unsigned int gDelay_;
+ unsigned int gStretch_;
+ unsigned int stretchCounter_;
+ int gOffset_;
+ StkFloat gRandomFactor_;
+ StkFloat gain_;
+
+};
+
+inline StkFloat Granulate :: lastOut( unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel >= lastFrame_.channels() ) {
+ errorString_ << "Granulate::lastOut(): channel argument is invalid!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ return lastFrame_[channel];
+}
+
+inline StkFrames& Granulate :: tick( StkFrames& frames, unsigned int channel )
+{
+ unsigned int nChannels = lastFrame_.channels();
+#if defined(_STK_DEBUG_)
+ if ( channel > frames.channels() - nChannels ) {
+ errorString_ << "Granulate::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *samples = &frames[channel];
+ unsigned int j, hop = frames.channels() - nChannels;
+ for ( unsigned int i=0; i<frames.frames(); i++, samples += hop ) {
+ *samples++ = tick();
+ for ( j=1; j<nChannels; j++ )
+ *samples++ = lastFrame_[j];
+ }
+
+ return frames;
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_HEVYMETL_H
+#define STK_HEVYMETL_H
+
+#include "FM.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class HevyMetl
+ \brief STK heavy metal FM synthesis instrument.
+
+ This class implements 3 cascade operators with
+ feedback modulation, also referred to as
+ algorithm 3 of the TX81Z.
+
+ \code
+ Algorithm 3 is : 4--\
+ 3-->2-- + -->1-->Out
+ \endcode
+
+ Control Change Numbers:
+ - Total Modulator Index = 2
+ - Modulator Crossfade = 4
+ - LFO Speed = 11
+ - LFO Depth = 1
+ - ADSR 2 & 4 Target = 128
+
+ The basic Chowning/Stanford FM patent expired
+ in 1995, but there exist follow-on patents,
+ mostly assigned to Yamaha. If you are of the
+ type who should worry about this (making
+ money) worry away.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class HevyMetl : public FM
+{
+ public:
+ //! Class constructor.
+ /*!
+ An StkError will be thrown if the rawwave path is incorrectly set.
+ */
+ HevyMetl( void );
+
+ //! Class destructor.
+ ~HevyMetl( void );
+
+ //! Start a note with the given frequency and amplitude.
+ void noteOn( StkFloat frequency, StkFloat amplitude );
+
+ //! Compute and return one output sample.
+ StkFloat tick( unsigned int channel = 0 );
+
+ protected:
+
+};
+
+inline StkFloat HevyMetl :: tick( unsigned int )
+{
+ register StkFloat temp;
+
+ temp = vibrato_.tick() * modDepth_ * 0.2;
+ waves_[0]->setFrequency(baseFrequency_ * (1.0 + temp) * ratios_[0]);
+ waves_[1]->setFrequency(baseFrequency_ * (1.0 + temp) * ratios_[1]);
+ waves_[2]->setFrequency(baseFrequency_ * (1.0 + temp) * ratios_[2]);
+ waves_[3]->setFrequency(baseFrequency_ * (1.0 + temp) * ratios_[3]);
+
+ temp = gains_[2] * adsr_[2]->tick() * waves_[2]->tick();
+ waves_[1]->addPhaseOffset( temp );
+
+ waves_[3]->addPhaseOffset( twozero_.lastOut() );
+ temp = (1.0 - (control2_ * 0.5)) * gains_[3] * adsr_[3]->tick() * waves_[3]->tick();
+ twozero_.tick(temp);
+
+ temp += control2_ * 0.5 * gains_[1] * adsr_[1]->tick() * waves_[1]->tick();
+ temp = temp * control1_;
+
+ waves_[0]->addPhaseOffset( temp );
+ temp = gains_[0] * adsr_[0]->tick() * waves_[0]->tick();
+
+ lastFrame_[0] = temp * 0.5;
+ return lastFrame_[0];
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_IIR_H
+#define STK_IIR_H
+
+#include "Filter.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class Iir
+ \brief STK general infinite impulse response filter class.
+
+ This class provides a generic digital filter structure that can be
+ used to implement IIR filters. For filters containing only
+ feedforward terms, the Fir class is slightly more efficient.
+
+ In particular, this class implements the standard difference
+ equation:
+
+ a[0]*y[n] = b[0]*x[n] + ... + b[nb]*x[n-nb] -
+ a[1]*y[n-1] - ... - a[na]*y[n-na]
+
+ If a[0] is not equal to 1, the filter coeffcients are normalized
+ by a[0].
+
+ The \e gain parameter is applied at the filter input and does not
+ affect the coefficient values. The default gain value is 1.0.
+ This structure results in one extra multiply per computed sample,
+ but allows easy control of the overall filter gain.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class Iir : public Filter
+{
+public:
+ //! Default constructor creates a zero-order pass-through "filter".
+ Iir( void );
+
+ //! Overloaded constructor which takes filter coefficients.
+ /*!
+ An StkError can be thrown if either of the coefficient vector
+ sizes is zero, or if the a[0] coefficient is equal to zero.
+ */
+ Iir( std::vector<StkFloat> &bCoefficients, std::vector<StkFloat> &aCoefficients );
+
+ //! Class destructor.
+ ~Iir( void );
+
+ //! Set filter coefficients.
+ /*!
+ An StkError can be thrown if either of the coefficient vector
+ sizes is zero, or if the a[0] coefficient is equal to zero. If
+ a[0] is not equal to 1, the filter coeffcients are normalized by
+ a[0]. The internal state of the filter is not cleared unless the
+ \e clearState flag is \c true.
+ */
+ void setCoefficients( std::vector<StkFloat> &bCoefficients, std::vector<StkFloat> &aCoefficients, bool clearState = false );
+
+ //! Set numerator coefficients.
+ /*!
+ An StkError can be thrown if coefficient vector is empty. Any
+ previously set denominator coefficients are left unaffected. Note
+ that the default constructor sets the single denominator
+ coefficient a[0] to 1.0. The internal state of the filter is not
+ cleared unless the \e clearState flag is \c true.
+ */
+ void setNumerator( std::vector<StkFloat> &bCoefficients, bool clearState = false );
+
+ //! Set denominator coefficients.
+ /*!
+ An StkError can be thrown if the coefficient vector is empty or
+ if the a[0] coefficient is equal to zero. Previously set
+ numerator coefficients are unaffected unless a[0] is not equal to
+ 1, in which case all coeffcients are normalized by a[0]. Note
+ that the default constructor sets the single numerator coefficient
+ b[0] to 1.0. The internal state of the filter is not cleared
+ unless the \e clearState flag is \c true.
+ */
+ void setDenominator( std::vector<StkFloat> &aCoefficients, bool clearState = false );
+
+ //! Return the last computed output value.
+ StkFloat lastOut( void ) const { return lastFrame_[0]; };
+
+ //! Input one sample to the filter and return one output.
+ StkFloat tick( StkFloat input );
+
+ //! Take a channel of the StkFrames object as inputs to the filter and replace with corresponding outputs.
+ /*!
+ The StkFrames argument reference is returned. The \c channel
+ argument must be less than the number of channels in the
+ StkFrames argument (the first channel is specified by 0).
+ However, range checking is only performed if _STK_DEBUG_ is
+ defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
+
+ //! Take a channel of the \c iFrames object as inputs to the filter and write outputs to the \c oFrames object.
+ /*!
+ The \c iFrames object reference is returned. Each channel
+ argument must be less than the number of channels in the
+ corresponding StkFrames argument (the first channel is specified
+ by 0). However, range checking is only performed if _STK_DEBUG_
+ is defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& iFrames, StkFrames &oFrames, unsigned int iChannel = 0, unsigned int oChannel = 0 );
+
+protected:
+
+};
+
+inline StkFloat Iir :: tick( StkFloat input )
+{
+ unsigned int i;
+
+ outputs_[0] = 0.0;
+ inputs_[0] = gain_ * input;
+ for ( i=b_.size()-1; i>0; i-- ) {
+ outputs_[0] += b_[i] * inputs_[i];
+ inputs_[i] = inputs_[i-1];
+ }
+ outputs_[0] += b_[0] * inputs_[0];
+
+ for ( i=a_.size()-1; i>0; i-- ) {
+ outputs_[0] += -a_[i] * outputs_[i];
+ outputs_[i] = outputs_[i-1];
+ }
+
+ lastFrame_[0] = outputs_[0];
+ return lastFrame_[0];
+}
+
+inline StkFrames& Iir :: tick( StkFrames& frames, unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel >= frames.channels() ) {
+ errorString_ << "Iir::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *samples = &frames[channel];
+ unsigned int i, hop = frames.channels();
+ for ( unsigned int j=0; j<frames.frames(); j++, samples += hop ) {
+ outputs_[0] = 0.0;
+ inputs_[0] = gain_ * *samples;
+ for ( i=b_.size()-1; i>0; i-- ) {
+ outputs_[0] += b_[i] * inputs_[i];
+ inputs_[i] = inputs_[i-1];
+ }
+ outputs_[0] += b_[0] * inputs_[0];
+
+ for ( i=a_.size()-1; i>0; i-- ) {
+ outputs_[0] += -a_[i] * outputs_[i];
+ outputs_[i] = outputs_[i-1];
+ }
+
+ *samples = outputs_[0];
+ }
+
+ lastFrame_[0] = *(samples-hop);
+ return frames;
+}
+
+inline StkFrames& Iir :: tick( StkFrames& iFrames, StkFrames& oFrames, unsigned int iChannel, unsigned int oChannel )
+{
+#if defined(_STK_DEBUG_)
+ if ( iChannel >= iFrames.channels() || oChannel >= oFrames.channels() ) {
+ errorString_ << "Iir::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *iSamples = &iFrames[iChannel];
+ StkFloat *oSamples = &oFrames[oChannel];
+ unsigned int i, iHop = iFrames.channels(), oHop = oFrames.channels();
+ for ( unsigned int j=0; j<iFrames.frames(); j++, iSamples += iHop, oSamples += oHop ) {
+ outputs_[0] = 0.0;
+ inputs_[0] = gain_ * *iSamples;
+ for ( i=b_.size()-1; i>0; i-- ) {
+ outputs_[0] += b_[i] * inputs_[i];
+ inputs_[i] = inputs_[i-1];
+ }
+ outputs_[0] += b_[0] * inputs_[0];
+
+ for ( i=a_.size()-1; i>0; i-- ) {
+ outputs_[0] += -a_[i] * outputs_[i];
+ outputs_[i] = outputs_[i-1];
+ }
+
+ *oSamples = outputs_[0];
+ }
+
+ lastFrame_[0] = *(oSamples-oHop);
+ return iFrames;
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_INETWVIN_H
+#define STK_INETWVIN_H
+
+#include "WvIn.h"
+#include "TcpServer.h"
+#include "StkUdpSocket.h"
+#include "Thread.h"
+#include "Mutex.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class InetWvIn
+ \brief STK internet streaming input class.
+
+ This Wvin subclass reads streamed audio data over a network via a
+ TCP or UDP socket connection. The data is assumed in big-endian,
+ or network, byte order. Only a single socket connection is
+ supported.
+
+ InetWvIn supports multi-channel data. It is important to
+ distinguish the tick() method that computes a single frame (and
+ returns only the specified sample of a multi-channel frame) from
+ the overloaded one that takes an StkFrames object for
+ multi-channel and/or multi-frame data.
+
+ This class implements a socket server. When using the TCP
+ protocol, the server "listens" for a single remote connection
+ within the InetWvIn::start() function. For the UDP protocol, no
+ attempt is made to verify packet delivery or order. The default
+ data type for the incoming stream is signed 16-bit integers,
+ though any of the defined StkFormats are permissible.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+typedef struct {
+ bool finished;
+ void *object;
+} ThreadInfo;
+
+class InetWvIn : public WvIn
+{
+public:
+ //! Default constructor.
+ /*!
+ An StkError will be thrown if an error occurs while initializing the input thread.
+ */
+ InetWvIn( unsigned long bufferFrames = 1024, unsigned int nBuffers = 8 );
+
+ //! Class destructor.
+ ~InetWvIn();
+
+ //! Wait for a (new) socket connection with specified protocol, port, data channels and format.
+ /*!
+ For the UDP protocol, this function will create a socket
+ instance and return. For the TCP protocol, this function will
+ block until a connection is established. An StkError will be
+ thrown if a socket error occurs or an invalid function argument is
+ provided.
+ */
+ void listen( int port = 2006, unsigned int nChannels = 1,
+ Stk::StkFormat format = STK_SINT16,
+ Socket::ProtocolType protocol = Socket::PROTO_TCP );
+
+ //! Returns true is an input connection exists or input data remains in the queue.
+ /*!
+ This method will not return false after an input connection has been closed until
+ all buffered input data has been read out.
+ */
+ bool isConnected( void );
+
+ //! Return the specified channel value of the last computed frame.
+ /*!
+ For multi-channel files, use the lastFrame() function to get
+ all values from the last computed frame. If no connection exists,
+ the returned value is 0.0. The \c channel argument must be less
+ than the number of channels in the data stream (the first channel
+ is specified by 0). However, range checking is only performed if
+ _STK_DEBUG_ is defined during compilation, in which case an
+ out-of-range value will trigger an StkError exception.
+ */
+ StkFloat lastOut( unsigned int channel = 0 );
+
+ //! Compute a sample frame and return the specified \c channel value.
+ /*!
+ For multi-channel files, use the lastFrame() function to get
+ all values from the computed frame. If no connection exists, the
+ returned value is 0.0 (and a warning will be issued if _STK_DEBUG_
+ is defined during compilation). The \c channel argument must be
+ less than the number of channels in the data stream (the first
+ channel is specified by 0). However, range checking is only
+ performed if _STK_DEBUG_ is defined during compilation, in which
+ case an out-of-range value will trigger an StkError exception.
+ */
+ StkFloat tick( unsigned int channel = 0 );
+
+ //! Fill the StkFrames argument with computed frames and return the same reference.
+ /*!
+ The number of channels in the StkFrames argument must equal the
+ number of channels specified in the listen() function. However,
+ this is only checked if _STK_DEBUG_ is defined during compilation,
+ in which case an incompatibility will trigger an StkError
+ exception. If no connection exists, the function does
+ nothing (a warning will be issued if _STK_DEBUG_ is defined during
+ compilation).
+ */
+ StkFrames& tick( StkFrames& frames );
+
+ // Called by the thread routine to receive data via the socket connection
+ // and fill the socket buffer. This is not intended for general use but
+ // must be public for access from the thread.
+ void receive( void );
+
+protected:
+
+ // Read buffered socket data into the data buffer ... will block if none available.
+ int readData( void );
+
+ Socket *soket_;
+ Thread thread_;
+ Mutex mutex_;
+ char *buffer_;
+ unsigned long bufferFrames_;
+ unsigned long bufferBytes_;
+ unsigned long bytesFilled_;
+ unsigned int nBuffers_;
+ unsigned long writePoint_;
+ unsigned long readPoint_;
+ long bufferCounter_;
+ int dataBytes_;
+ bool connected_;
+ int fd_;
+ ThreadInfo threadInfo_;
+ Stk::StkFormat dataType_;
+
+};
+
+inline StkFloat InetWvIn :: lastOut( unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel >= data_.channels() ) {
+ errorString_ << "InetWvIn::lastOut(): channel argument and data stream are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ // If no connection and we've output all samples in the queue, return.
+ if ( !connected_ && bytesFilled_ == 0 && bufferCounter_ == 0 ) return 0.0;
+
+ return lastFrame_[channel];
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_INETWVOUT_H
+#define STK_INETWVOUT_H
+
+#include "WvOut.h"
+#include "Socket.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class InetWvOut
+ \brief STK internet streaming output class.
+
+ This WvOut subclass can stream data over a network via a TCP or
+ UDP socket connection. The data is converted to big-endian byte
+ order, if necessary, before being transmitted.
+
+ InetWvOut supports multi-channel data. It is important to
+ distinguish the tick() method that outputs a single sample to all
+ channels in a sample frame from the overloaded one that takes a
+ reference to an StkFrames object for multi-channel and/or
+ multi-frame data.
+
+ This class connects to a socket server, the port and IP address of
+ which must be specified as constructor arguments. The default
+ data type is signed 16-bit integers but any of the defined
+ StkFormats are permissible.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class InetWvOut : public WvOut
+{
+ public:
+ //! Default constructor ... the socket is not instantiated.
+ InetWvOut( unsigned long packetFrames = 1024 );
+
+ //! Overloaded constructor which opens a network connection during instantiation.
+ /*!
+ An StkError is thrown if a socket error occurs or an invalid argument is specified.
+ */
+ InetWvOut( int port, Socket::ProtocolType protocol = Socket::PROTO_TCP,
+ std::string hostname = "localhost", unsigned int nChannels = 1, Stk::StkFormat format = STK_SINT16,
+ unsigned long packetFrames = 1024 );
+
+ //! Class destructor.
+ ~InetWvOut();
+
+ //! Connect to the specified host and port and prepare to stream \e nChannels of data in the given data format.
+ /*!
+ An StkError is thrown if a socket error occurs or an invalid argument is specified.
+ */
+ void connect( int port, Socket::ProtocolType protocol = Socket::PROTO_TCP,
+ std::string hostname = "localhost", unsigned int nChannels = 1, Stk::StkFormat format = STK_SINT16 );
+
+ //! If a connection is open, write out remaining samples in the queue and then disconnect.
+ void disconnect( void );
+
+ //! Output a single sample to all channels in a sample frame.
+ /*!
+ An StkError is thrown if an output error occurs. If a socket
+ connection does not exist, the function does nothing (a warning
+ will be issued if _STK_DEBUG_ is defined during compilation).
+ */
+ void tick( const StkFloat sample );
+
+ //! Output the StkFrames data.
+ /*!
+ An StkError will be thrown if an output error occurs. An
+ StkError will also be thrown if _STK_DEBUG_ is defined during
+ compilation and there is an incompatability between the number of
+ channels in the FileWvOut object and that in the StkFrames object.
+ If a socket connection does not exist, the function does nothing
+ (a warning will be issued if _STK_DEBUG_ is defined during
+ compilation).
+ */
+ void tick( const StkFrames& frames );
+
+ protected:
+
+ void incrementFrame( void );
+
+ // Write a buffer of length frames via the socket connection.
+ void writeData( unsigned long frames );
+
+ char *buffer_;
+ Socket *soket_;
+ unsigned long bufferFrames_;
+ unsigned long bufferBytes_;
+ unsigned long bufferIndex_;
+ unsigned long iData_;
+ unsigned int dataBytes_;
+ Stk::StkFormat dataType_;
+};
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_INSTRMNT_H
+#define STK_INSTRMNT_H
+
+#include "Stk.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class Instrmnt
+ \brief STK instrument abstract base class.
+
+ This class provides a common interface for
+ all STK instruments.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class Instrmnt : public Stk
+{
+ public:
+ //! Class constructor.
+ Instrmnt( void ) { lastFrame_.resize( 1, 1, 0.0 ); };
+
+ //! Start a note with the given frequency and amplitude.
+ virtual void noteOn( StkFloat frequency, StkFloat amplitude ) = 0;
+
+ //! Stop a note with the given amplitude (speed of decay).
+ virtual void noteOff( StkFloat amplitude ) = 0;
+
+ //! Set instrument parameters for a particular frequency.
+ virtual void setFrequency( StkFloat frequency );
+
+ //! Perform the control change specified by \e number and \e value (0.0 - 128.0).
+ virtual void controlChange(int number, StkFloat value);
+
+ //! Return the number of output channels for the class.
+ unsigned int channelsOut( void ) const { return lastFrame_.channels(); };
+
+ //! Return an StkFrames reference to the last output sample frame.
+ const StkFrames& lastFrame( void ) const { return lastFrame_; };
+
+ //! Return the specified channel value of the last computed frame.
+ /*!
+ The \c channel argument must be less than the number of output
+ channels, which can be determined with the channelsOut() function
+ (the first channel is specified by 0). However, range checking is
+ only performed if _STK_DEBUG_ is defined during compilation, in
+ which case an out-of-range value will trigger an StkError
+ exception. \sa lastFrame()
+ */
+ StkFloat lastOut( unsigned int channel = 0 );
+
+ //! Compute one sample frame and return the specified \c channel value.
+ /*!
+ For monophonic instruments, the \c channel argument is ignored.
+ */
+ virtual StkFloat tick( unsigned int channel = 0 ) = 0;
+
+ //! Fill the StkFrames object with computed sample frames, starting at the specified channel.
+ /*!
+ The \c channel argument plus the number of output channels must
+ be less than the number of channels in the StkFrames argument (the
+ first channel is specified by 0). However, range checking is only
+ performed if _STK_DEBUG_ is defined during compilation, in which
+ case an out-of-range value will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
+
+ protected:
+
+ StkFrames lastFrame_;
+
+};
+
+inline void Instrmnt :: setFrequency(StkFloat frequency)
+{
+ errorString_ << "Instrmnt::setFrequency: virtual setFrequency function call!";
+ handleError( StkError::WARNING );
+}
+
+inline StkFloat Instrmnt :: lastOut( unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel >= lastFrame_.channels() ) {
+ errorString_ << "Instrmnt::lastOut(): channel argument is invalid!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ return lastFrame_[channel];
+}
+
+inline StkFrames& Instrmnt :: tick( StkFrames& frames, unsigned int channel )
+{
+ unsigned int nChannels = lastFrame_.channels();
+#if defined(_STK_DEBUG_)
+ if ( channel > frames.channels() - nChannels ) {
+ errorString_ << "Instrmnt::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *samples = &frames[channel];
+ unsigned int j, hop = frames.channels() - nChannels;
+ if ( nChannels == 1 ) {
+ for ( unsigned int i=0; i<frames.frames(); i++, samples += hop )
+ *samples++ = tick();
+ }
+ else {
+ for ( unsigned int i=0; i<frames.frames(); i++, samples += hop ) {
+ *samples++ = tick();
+ for ( j=1; j<nChannels; j++ )
+ *samples++ = lastFrame_[j];
+ }
+ }
+
+ return frames;
+}
+
+inline void Instrmnt :: controlChange( int number, StkFloat value )
+{
+ errorString_ << "Instrmnt::controlChange: virtual function call!";
+ handleError( StkError::WARNING );
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_JCREV_H
+#define STK_JCREV_H
+
+#include "Effect.h"
+#include "Delay.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class JCRev
+ \brief John Chowning's reverberator class.
+
+ This class takes a monophonic input signal and produces a stereo
+ output signal. It is derived from the CLM JCRev function, which
+ is based on the use of networks of simple allpass and comb delay
+ filters. This class implements three series allpass units,
+ followed by four parallel comb filters, and two decorrelation
+ delay lines in parallel at the output.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class JCRev : public Effect
+{
+ public:
+ //! Class constructor taking a T60 decay time argument (one second default value).
+ JCRev( StkFloat T60 = 1.0 );
+
+ //! Reset and clear all internal state.
+ void clear( void );
+
+ //! Set the reverberation T60 decay time.
+ void setT60( StkFloat T60 );
+
+ //! Return the specified channel value of the last computed stereo frame.
+ /*!
+ Use the lastFrame() function to get both values of the last
+ computed stereo frame. The \c channel argument must be 0 or 1
+ (the first channel is specified by 0). However, range checking is
+ only performed if _STK_DEBUG_ is defined during compilation, in
+ which case an out-of-range value will trigger an StkError
+ exception.
+ */
+ StkFloat lastOut( unsigned int channel = 0 );
+
+ //! Input one sample to the effect and return the specified \c channel value of the computed stereo frame.
+ /*!
+ Use the lastFrame() function to get both values of the computed
+ stereo output frame. The \c channel argument must be 0 or 1 (the
+ first channel is specified by 0). However, range checking is only
+ performed if _STK_DEBUG_ is defined during compilation, in which
+ case an out-of-range value will trigger an StkError exception.
+ */
+ StkFloat tick( StkFloat input, unsigned int channel = 0 );
+
+ //! Take a channel of the StkFrames object as inputs to the effect and replace with stereo outputs.
+ /*!
+ The StkFrames argument reference is returned. The stereo
+ outputs are written to the StkFrames argument starting at the
+ specified \c channel. Therefore, the \c channel argument must be
+ less than ( channels() - 1 ) of the StkFrames argument (the first
+ channel is specified by 0). However, range checking is only
+ performed if _STK_DEBUG_ is defined during compilation, in which
+ case an out-of-range value will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
+
+ //! Take a channel of the \c iFrames object as inputs to the effect and write stereo outputs to the \c oFrames object.
+ /*!
+ The \c iFrames object reference is returned. The \c iChannel
+ argument must be less than the number of channels in the \c
+ iFrames argument (the first channel is specified by 0). The \c
+ oChannel argument must be less than ( channels() - 1 ) of the \c
+ oFrames argument. However, range checking is only performed if
+ _STK_DEBUG_ is defined during compilation, in which case an
+ out-of-range value will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& iFrames, StkFrames &oFrames, unsigned int iChannel = 0, unsigned int oChannel = 0 );
+
+ protected:
+
+ Delay allpassDelays_[3];
+ Delay combDelays_[4];
+ Delay outLeftDelay_;
+ Delay outRightDelay_;
+ StkFloat allpassCoefficient_;
+ StkFloat combCoefficient_[4];
+
+};
+
+inline StkFloat JCRev :: lastOut( unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel > 1 ) {
+ errorString_ << "JCRev::lastOut(): channel argument must be less than 2!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ return lastFrame_[channel];
+}
+
+inline StkFloat JCRev :: tick( StkFloat input, unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel > 1 ) {
+ errorString_ << "JCRev::tick(): channel argument must be less than 2!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat temp, temp0, temp1, temp2, temp3, temp4, temp5, temp6;
+ StkFloat filtout;
+
+ temp = allpassDelays_[0].lastOut();
+ temp0 = allpassCoefficient_ * temp;
+ temp0 += input;
+ allpassDelays_[0].tick(temp0);
+ temp0 = -(allpassCoefficient_ * temp0) + temp;
+
+ temp = allpassDelays_[1].lastOut();
+ temp1 = allpassCoefficient_ * temp;
+ temp1 += temp0;
+ allpassDelays_[1].tick(temp1);
+ temp1 = -(allpassCoefficient_ * temp1) + temp;
+
+ temp = allpassDelays_[2].lastOut();
+ temp2 = allpassCoefficient_ * temp;
+ temp2 += temp1;
+ allpassDelays_[2].tick(temp2);
+ temp2 = -(allpassCoefficient_ * temp2) + temp;
+
+ temp3 = temp2 + (combCoefficient_[0] * combDelays_[0].lastOut());
+ temp4 = temp2 + (combCoefficient_[1] * combDelays_[1].lastOut());
+ temp5 = temp2 + (combCoefficient_[2] * combDelays_[2].lastOut());
+ temp6 = temp2 + (combCoefficient_[3] * combDelays_[3].lastOut());
+
+ combDelays_[0].tick(temp3);
+ combDelays_[1].tick(temp4);
+ combDelays_[2].tick(temp5);
+ combDelays_[3].tick(temp6);
+
+ filtout = temp3 + temp4 + temp5 + temp6;
+
+ lastFrame_[0] = effectMix_ * (outLeftDelay_.tick(filtout));
+ lastFrame_[1] = effectMix_ * (outRightDelay_.tick(filtout));
+ temp = (1.0 - effectMix_) * input;
+ lastFrame_[0] += temp;
+ lastFrame_[1] += temp;
+
+ return lastFrame_[channel];
+}
+
+} // stk namespace
+
+#endif
+
--- /dev/null
+#ifndef STK_JETTABL_H
+#define STK_JETTABL_H
+
+#include "Function.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class JetTable
+ \brief STK jet table class.
+
+ This class implements a flue jet non-linear
+ function, computed by a polynomial calculation.
+ Contrary to the name, this is not a "table".
+
+ Consult Fletcher and Rossing, Karjalainen,
+ Cook, and others for more information.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class JetTable : public Function
+{
+public:
+
+ //! Take one sample input and map to one sample of output.
+ StkFloat tick( StkFloat input );
+
+ //! Take a channel of the StkFrames object as inputs to the table and replace with corresponding outputs.
+ /*!
+ The StkFrames argument reference is returned. The \c channel
+ argument must be less than the number of channels in the
+ StkFrames argument (the first channel is specified by 0).
+ However, range checking is only performed if _STK_DEBUG_ is
+ defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
+
+ //! Take a channel of the \c iFrames object as inputs to the table and write outputs to the \c oFrames object.
+ /*!
+ The \c iFrames object reference is returned. Each channel
+ argument must be less than the number of channels in the
+ corresponding StkFrames argument (the first channel is specified
+ by 0). However, range checking is only performed if _STK_DEBUG_
+ is defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& iFrames, StkFrames &oFrames, unsigned int iChannel = 0, unsigned int oChannel = 0 );
+
+};
+
+inline StkFloat JetTable :: tick( StkFloat input )
+{
+ // Perform "table lookup" using a polynomial
+ // calculation (x^3 - x), which approximates
+ // the jet sigmoid behavior.
+ lastFrame_[0] = input * (input * input - 1.0);
+
+ // Saturate at +/- 1.0.
+ if ( lastFrame_[0] > 1.0 ) lastFrame_[0] = 1.0;
+ if ( lastFrame_[0] < -1.0 ) lastFrame_[0] = -1.0;
+ return lastFrame_[0];
+}
+
+inline StkFrames& JetTable :: tick( StkFrames& frames, unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel >= frames.channels() ) {
+ errorString_ << "JetTable::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *samples = &frames[channel];
+ unsigned int hop = frames.channels();
+ for ( unsigned int i=0; i<frames.frames(); i++, samples += hop ) {
+ *samples = *samples * (*samples * *samples - 1.0);
+ if ( *samples > 1.0) *samples = 1.0;
+ if ( *samples < -1.0) *samples = -1.0;
+ }
+
+ lastFrame_[0] = *(samples-hop);
+ return frames;
+}
+
+inline StkFrames& JetTable :: tick( StkFrames& iFrames, StkFrames& oFrames, unsigned int iChannel, unsigned int oChannel )
+{
+#if defined(_STK_DEBUG_)
+ if ( iChannel >= iFrames.channels() || oChannel >= oFrames.channels() ) {
+ errorString_ << "JetTable::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *iSamples = &iFrames[iChannel];
+ StkFloat *oSamples = &oFrames[oChannel];
+ unsigned int iHop = iFrames.channels(), oHop = oFrames.channels();
+ for ( unsigned int i=0; i<iFrames.frames(); i++, iSamples += iHop, oSamples += oHop ) {
+ *oSamples = *oSamples * (*oSamples * *oSamples - 1.0);
+ if ( *oSamples > 1.0) *oSamples = 1.0;
+ if ( *oSamples < -1.0) *oSamples = -1.0;
+ }
+
+ lastFrame_[0] = *(oSamples-oHop);
+ return iFrames;
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_LENLentPitShift_H
+#define STK_LENLentPitShift_H
+
+#include "Effect.h"
+#include "Delay.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class LentPitShift
+ \brief Pitch shifter effect class based on the Lent algorithm.
+
+ This class implements a pitch shifter using pitch
+ tracking and sample windowing and shifting.
+
+ by Francois Germain, 2009.
+*/
+/***************************************************/
+
+class LentPitShift : public Effect
+{
+ public:
+ //! Class constructor.
+ LentPitShift( StkFloat periodRatio = 1.0, int tMax = RT_BUFFER_SIZE );
+
+ ~LentPitShift( void ) {
+ delete window;
+ window = NULL;
+ delete dt;
+ dt = NULL;
+ delete dpt;
+ dpt = NULL;
+ delete cumDt;
+ cumDt = NULL;
+ }
+
+ //! Reset and clear all internal state.
+ void clear( void );
+
+ //! Set the pitch shift factor (1.0 produces no shift).
+ void setShift( StkFloat shift );
+
+ //! Input one sample to the filter and return one output.
+ StkFloat tick( StkFloat input );
+
+ //! Take a channel of the StkFrames object as inputs to the filter and replace with corresponding outputs.
+ /*!
+ The StkFrames argument reference is returned. The \c channel
+ argument must be less than the number of channels in the
+ StkFrames argument (the first channel is specified by 0).
+ However, range checking is only performed if _STK_DEBUG_ is
+ defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
+
+ //! Take a channel of the \c iFrames object as inputs to the filter and write outputs to the \c oFrames object.
+ /*!
+ The \c iFrames object reference is returned. Each channel
+ argument must be less than the number of channels in the
+ corresponding StkFrames argument (the first channel is specified
+ by 0). However, range checking is only performed if _STK_DEBUG_
+ is defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& iFrames, StkFrames &oFrames, unsigned int iChannel = 0, unsigned int oChannel = 0 );
+
+ protected:
+
+ //! Apply the effect on the input samples and store it.
+ /*!
+ The samples stored in the input frame vector are processed
+ and the delayed result are stored in the output frame vector
+ */
+ void process( );
+
+ // Frame storage vectors for process function
+ StkFrames inputFrames;
+ StkFrames outputFrames;
+ int ptrFrames; // writing pointer
+
+ // Input delay line
+ Delay inputLine_;
+ int inputPtr;
+
+ // Output delay line
+ Delay outputLine_;
+ double outputPtr;
+
+ // Pitch tracker variables
+ unsigned long tMax_; // Maximal period measurable by the pitch tracker.
+ // It is also the size of the window used by the pitch tracker and
+ // the size of the frames that can be computed by the tick function
+
+ StkFloat threshold_; // Threshold of detection for the pitch tracker
+ unsigned long lastPeriod_; // Result of the last pitch tracking loop
+ StkFloat* dt; // Array containing the euclidian distance coefficients
+ StkFloat* cumDt; // Array containing the cumulative sum of the coefficients in dt
+ StkFloat* dpt; // Array containing the pitch tracking function coefficients
+
+ // Pitch shifter variables
+ StkFloat env[2]; // Coefficients for the linear interpolation when modifying the output samples
+ StkFloat* window; // Hamming window used for the input portion extraction
+ double periodRatio_; // Ratio of modification of the signal period
+ StkFrames zeroFrame; // Frame of tMax_ zero samples
+
+
+ // Coefficient delay line that could be used for a dynamic calculation of the pitch
+ //Delay* coeffLine_;
+
+};
+
+inline void LentPitShift::process()
+{
+ StkFloat x_t; // input coefficient
+ StkFloat x_t_T; // previous input coefficient at T samples
+ StkFloat coeff; // new coefficient for the difference function
+
+ int alternativePitch = tMax_; // Global minimum storage
+ lastPeriod_ = tMax_+1; // Storage of the lowest local minimum under the threshold
+
+ // Loop variables
+ unsigned long delay_;
+ unsigned int n;
+
+ // Initialization of the dt coefficients. Since the
+ // frames are of tMax_ length, there is no overlapping
+ // between the successive windows where pitch tracking
+ // is performed.
+ for ( delay_=1; delay_<=tMax_; delay_++ )
+ dt[delay_] = 0.;
+
+ // Calculation of the dt coefficients and update of the input delay line.
+ for ( n=0; n<inputFrames.size(); n++ ) {
+ x_t = inputLine_.tick( inputFrames[ n ] );
+ for ( delay_=1; delay_<= tMax_; delay_++ ) {
+ x_t_T = inputLine_.contentsAt( delay_ );
+ coeff = x_t - x_t_T;
+ dt[delay_] += coeff * coeff;
+ }
+ }
+
+ // Calculation of the pitch tracking function and test for the minima.
+ for ( delay_=1; delay_<=tMax_; delay_++ ) {
+ cumDt[delay_] = dt[delay_] + cumDt[delay_-1];
+ dpt[delay_] = dt[delay_] * delay_ / cumDt[delay_];
+
+ // Look for a minimum
+ if ( dpt[delay_-1]-dpt[delay_-2] < 0 && dpt[delay_]-dpt[delay_-1] > 0 ) {
+ // Check if the minimum is under the threshold
+ if ( dpt[delay_-1] < threshold_ ){
+ lastPeriod_ = delay_-1;
+ // If a minimum is found, we can stop the loop
+ break;
+ }
+ else if ( dpt[alternativePitch] > dpt[delay_-1] )
+ // Otherwise we store it if it is the current global minimum
+ alternativePitch = delay_-1;
+ }
+ }
+
+ // Test for the last period length.
+ if ( dpt[delay_]-dpt[delay_-1] < 0 ) {
+ if ( dpt[delay_] < threshold_ )
+ lastPeriod_ = delay_;
+ else if ( dpt[alternativePitch] > dpt[delay_] )
+ alternativePitch = delay_;
+ }
+
+ if ( lastPeriod_ == tMax_+1 )
+ // No period has been under the threshold so we used the global minimum
+ lastPeriod_ = alternativePitch;
+
+ // We put the new zero output coefficients in the output delay line and
+ // we get the previous calculated coefficients
+ outputLine_.tick( zeroFrame, outputFrames );
+
+ // Initialization of the Hamming window used in the algorithm
+ for ( int n=-(int)lastPeriod_; n<(int)lastPeriod_; n++ )
+ window[n+lastPeriod_] = (1 + cos(PI*n/lastPeriod_)) / 2 ;
+
+ int M; // Index of reading in the input delay line
+ int N; // Index of writing in the output delay line
+ double sample; // Temporary storage for the new coefficient
+
+ // We loop for all the frames of length lastPeriod_ presents between inputPtr and tMax_
+ for ( ; inputPtr<(int)(tMax_-lastPeriod_); inputPtr+=lastPeriod_ ) {
+ // Test for the decision of compression/expansion
+ while ( outputPtr < inputPtr ) {
+ // Coefficients for the linear interpolation
+ env[1] = fmod( outputPtr + tMax_, 1.0 );
+ env[0] = 1.0 - env[1];
+ M = tMax_ - inputPtr + lastPeriod_ - 1; // New reading pointer
+ N = 2*tMax_ - (unsigned long)floor(outputPtr + tMax_) + lastPeriod_ - 1; // New writing pointer
+ for ( unsigned int j=0; j<2*lastPeriod_; j++,M--,N-- ) {
+ sample = inputLine_.contentsAt(M) * window[j] / 2.;
+ // Linear interpolation
+ outputLine_.addTo(N, env[0] * sample);
+ outputLine_.addTo(N-1, env[1] * sample);
+ }
+ outputPtr = outputPtr + lastPeriod_ * periodRatio_; // new output pointer
+ }
+ }
+ // Shifting of the pointers waiting for the new frame of length tMax_.
+ outputPtr -= tMax_;
+ inputPtr -= tMax_;
+}
+
+
+inline StkFloat LentPitShift :: tick( StkFloat input )
+{
+ StkFloat sample;
+
+ inputFrames[ptrFrames] = input;
+
+ sample = outputFrames[ptrFrames++];
+
+ // Check for end condition
+ if ( ptrFrames == (int) inputFrames.size() ){
+ ptrFrames = 0;
+ process( );
+ }
+
+ return sample;
+}
+
+inline StkFrames& LentPitShift :: tick( StkFrames& frames, unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel >= frames.channels() ) {
+ errorString_ << "LentPitShift::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *samples = &frames[channel];
+ unsigned int hop = frames.channels();
+ for ( unsigned int i=0; i<frames.frames(); i++, samples += hop ) {
+ *samples = tick( *samples );
+ }
+
+ return frames;
+}
+
+inline StkFrames& LentPitShift :: tick( StkFrames& iFrames, StkFrames& oFrames, unsigned int iChannel, unsigned int oChannel )
+{
+#if defined(_STK_DEBUG_)
+ if ( iChannel >= iFrames.channels() || oChannel >= oFrames.channels() ) {
+ errorString_ << "LentPitShift::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *iSamples = &iFrames[iChannel];
+ StkFloat *oSamples = &oFrames[oChannel];
+ unsigned int iHop = iFrames.channels(), oHop = oFrames.channels();
+ for ( unsigned int i=0; i<iFrames.frames(); i++, iSamples += iHop, oSamples += oHop ) {
+ *oSamples = tick( *iSamples );
+ }
+
+ return iFrames;
+}
+
+} // stk namespace
+
+#endif
+
--- /dev/null
+#ifndef STK_MANDOLIN_H
+#define STK_MANDOLIN_H
+
+#include "PluckTwo.h"
+#include "FileWvIn.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class Mandolin
+ \brief STK mandolin instrument model class.
+
+ This class inherits from PluckTwo and uses
+ "commuted synthesis" techniques to model a
+ mandolin instrument.
+
+ This is a digital waveguide model, making its
+ use possibly subject to patents held by
+ Stanford University, Yamaha, and others.
+ Commuted Synthesis, in particular, is covered
+ by patents, granted, pending, and/or
+ applied-for. All are assigned to the Board of
+ Trustees, Stanford University. For
+ information, contact the Office of Technology
+ Licensing, Stanford University.
+
+ Control Change Numbers:
+ - Body Size = 2
+ - Pluck Position = 4
+ - String Sustain = 11
+ - String Detuning = 1
+ - Microphone Position = 128
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class Mandolin : public PluckTwo
+{
+ public:
+ //! Class constructor, taking the lowest desired playing frequency.
+ Mandolin( StkFloat lowestFrequency );
+
+ //! Class destructor.
+ ~Mandolin( void );
+
+ //! Pluck the strings with the given amplitude (0.0 - 1.0) using the current frequency.
+ void pluck( StkFloat amplitude );
+
+ //! Pluck the strings with the given amplitude (0.0 - 1.0) and position (0.0 - 1.0).
+ void pluck( StkFloat amplitude,StkFloat position );
+
+ //! Start a note with the given frequency and amplitude (0.0 - 1.0).
+ void noteOn( StkFloat frequency, StkFloat amplitude );
+
+ //! Set the body size (a value of 1.0 produces the "default" size).
+ void setBodySize( StkFloat size );
+
+ //! Perform the control change specified by \e number and \e value (0.0 - 128.0).
+ void controlChange( int number, StkFloat value );
+
+ //! Compute and return one output sample.
+ StkFloat tick( unsigned int channel = 0 );
+
+ protected:
+
+ FileWvIn *soundfile_[12];
+ int mic_;
+ long dampTime_;
+ bool waveDone_;
+};
+
+inline StkFloat Mandolin :: tick( unsigned int )
+{
+ StkFloat temp = 0.0;
+ if ( !waveDone_ ) {
+ // Scale the pluck excitation with comb
+ // filtering for the duration of the file.
+ temp = soundfile_[mic_]->tick() * pluckAmplitude_;
+ temp = temp - combDelay_.tick(temp);
+ waveDone_ = soundfile_[mic_]->isFinished();
+ }
+
+ // Damping hack to help avoid overflow on re-plucking.
+ if ( dampTime_ >=0 ) {
+ dampTime_ -= 1;
+ // Calculate 1st delay filtered reflection plus pluck excitation.
+ lastFrame_[0] = delayLine_.tick( filter_.tick( temp + (delayLine_.lastOut() * 0.7) ) );
+ // Calculate 2nd delay just like the 1st.
+ lastFrame_[0] += delayLine2_.tick( filter2_.tick( temp + (delayLine2_.lastOut() * 0.7) ) );
+ }
+ else { // No damping hack after 1 period.
+ // Calculate 1st delay filtered reflection plus pluck excitation.
+ lastFrame_[0] = delayLine_.tick( filter_.tick( temp + (delayLine_.lastOut() * loopGain_) ) );
+ // Calculate 2nd delay just like the 1st.
+ lastFrame_[0] += delayLine2_.tick( filter2_.tick( temp + (delayLine2_.lastOut() * loopGain_) ) );
+ }
+
+ lastFrame_[0] *= 0.3;
+ return lastFrame_[0];
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_MESH2D_H
+#define STK_MESH2D_H
+
+#include "Instrmnt.h"
+#include "OnePole.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class Mesh2D
+ \brief Two-dimensional rectilinear waveguide mesh class.
+
+ This class implements a rectilinear,
+ two-dimensional digital waveguide mesh
+ structure. For details, see Van Duyne and
+ Smith, "Physical Modeling with the 2-D Digital
+ Waveguide Mesh", Proceedings of the 1993
+ International Computer Music Conference.
+
+ This is a digital waveguide model, making its
+ use possibly subject to patents held by Stanford
+ University, Yamaha, and others.
+
+ Control Change Numbers:
+ - X Dimension = 2
+ - Y Dimension = 4
+ - Mesh Decay = 11
+ - X-Y Input Position = 1
+
+ by Julius Smith, 2000 - 2002.
+ Revised by Gary Scavone for STK, 2002.
+*/
+/***************************************************/
+
+const short NXMAX = 12;
+const short NYMAX = 12;
+
+class Mesh2D : public Instrmnt
+{
+ public:
+ //! Class constructor, taking the x and y dimensions in samples.
+ Mesh2D( short nX, short nY );
+
+ //! Class destructor.
+ ~Mesh2D( void );
+
+ //! Reset and clear all internal state.
+ void clear( void );
+
+ //! Set the x dimension size in samples.
+ void setNX( short lenX );
+
+ //! Set the y dimension size in samples.
+ void setNY( short lenY );
+
+ //! Set the x, y input position on a 0.0 - 1.0 scale.
+ void setInputPosition( StkFloat xFactor, StkFloat yFactor );
+
+ //! Set the loss filters gains (0.0 - 1.0).
+ void setDecay( StkFloat decayFactor );
+
+ //! Impulse the mesh with the given amplitude (frequency ignored).
+ void noteOn( StkFloat frequency, StkFloat amplitude );
+
+ //! Stop a note with the given amplitude (speed of decay) ... currently ignored.
+ void noteOff( StkFloat amplitude );
+
+ //! Calculate and return the signal energy stored in the mesh.
+ StkFloat energy( void );
+
+ //! Input a sample to the mesh and compute one output sample.
+ StkFloat inputTick( StkFloat input );
+
+ //! Perform the control change specified by \e number and \e value (0.0 - 128.0).
+ void controlChange( int number, StkFloat value );
+
+ //! Compute and return one output sample.
+ StkFloat tick( unsigned int channel = 0 );
+
+ protected:
+
+ StkFloat tick0();
+ StkFloat tick1();
+ void clearMesh();
+
+ short NX_, NY_;
+ short xInput_, yInput_;
+ OnePole filterX_[NXMAX];
+ OnePole filterY_[NYMAX];
+ StkFloat v_[NXMAX-1][NYMAX-1]; // junction velocities
+ StkFloat vxp_[NXMAX][NYMAX]; // positive-x velocity wave
+ StkFloat vxm_[NXMAX][NYMAX]; // negative-x velocity wave
+ StkFloat vyp_[NXMAX][NYMAX]; // positive-y velocity wave
+ StkFloat vym_[NXMAX][NYMAX]; // negative-y velocity wave
+
+ // Alternate buffers
+ StkFloat vxp1_[NXMAX][NYMAX]; // positive-x velocity wave
+ StkFloat vxm1_[NXMAX][NYMAX]; // negative-x velocity wave
+ StkFloat vyp1_[NXMAX][NYMAX]; // positive-y velocity wave
+ StkFloat vym1_[NXMAX][NYMAX]; // negative-y velocity wave
+
+ int counter_; // time in samples
+};
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_MESSAGER_H
+#define STK_MESSAGER_H
+
+#include "Stk.h"
+#include "Skini.h"
+#include <queue>
+
+#if defined(__STK_REALTIME__)
+
+#include "Mutex.h"
+#include "Thread.h"
+#include "TcpServer.h"
+#include "RtMidi.h"
+
+#endif // __STK_REALTIME__
+
+namespace stk {
+
+/***************************************************/
+/*! \class Messager
+ \brief STK input control message parser.
+
+ This class reads and parses control messages from a variety of
+ sources, such as a scorefile, MIDI port, socket connection, or
+ stdin. MIDI messages are retrieved using the RtMidi class. All
+ other input sources (scorefile, socket, or stdin) are assumed to
+ provide SKINI formatted messages. This class can be compiled with
+ generic, non-realtime support, in which case only scorefile
+ reading is possible.
+
+ The various \e realtime message acquisition mechanisms (from MIDI,
+ socket, or stdin) take place asynchronously, filling the message
+ queue. A call to popMessage() will pop the next available control
+ message from the queue and return it via the referenced Message
+ structure. When a \e non-realtime scorefile is set, it is not
+ possible to start reading realtime input messages (from MIDI,
+ socket, or stdin). Likewise, it is not possible to read from a
+ scorefile when a realtime input mechanism is running.
+
+ When MIDI input is started, input is also automatically read from
+ stdin. This allows for program termination via the terminal
+ window. An __SK_Exit_ message is pushed onto the stack whenever
+ an "exit" or "Exit" message is received from stdin or when all
+ socket connections close and no stdin thread is running.
+
+ This class is primarily for use in STK example programs but it is
+ generic enough to work in many other contexts.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+const int DEFAULT_QUEUE_LIMIT = 200;
+
+class Messager : public Stk
+{
+ public:
+
+ // This structure is used to share data among the various realtime
+ // messager threads. It must be public.
+ struct MessagerData {
+ Skini skini;
+ std::queue<Skini::Message> queue;
+ unsigned int queueLimit;
+ int sources;
+
+#if defined(__STK_REALTIME__)
+ Mutex mutex;
+ RtMidiIn *midi;
+ TcpServer *socket;
+ std::vector<int> fd;
+ fd_set mask;
+#endif
+
+ // Default constructor.
+ MessagerData()
+ :queueLimit(0), sources(0) {}
+ };
+
+ //! Default constructor.
+ Messager();
+
+ //! Class destructor.
+ ~Messager();
+
+ //! Pop the next message from the queue and write it to the referenced message structure.
+ /*!
+ Invalid messages (or an empty queue) are indicated by type
+ values of zero, in which case all other message structure values
+ are undefined. The user MUST verify the returned message type is
+ valid before reading other message values.
+ */
+ void popMessage( Skini::Message& message );
+
+ //! Push the referenced message onto the message stack.
+ void pushMessage( Skini::Message& message );
+
+ //! Specify a SKINI formatted scorefile from which messages should be read.
+ /*!
+ A return value of \c true indicates the call was successful. A
+ return value of \c false can occur if the file is not found,
+ cannot be opened, another file is currently still open, or if a
+ realtime input mechanism is running. Scorefile input is
+ considered to be a non-realtime control mechanism that cannot run
+ concurrently with realtime input.
+ */
+ bool setScoreFile( const char* filename );
+
+#if defined(__STK_REALTIME__)
+ //! Initiate the "realtime" retreival from stdin of control messages into the queue.
+ /*!
+ This function initiates a thread for asynchronous retrieval of
+ SKINI formatted messages from stdin. A return value of \c true
+ indicates the call was successful. A return value of \c false can
+ occur if a scorefile is being read, a stdin thread is already
+ running, or a thread error occurs during startup. Stdin input is
+ considered to be a realtime control mechanism that cannot run
+ concurrently with non-realtime scorefile input.
+ */
+ bool startStdInput();
+
+ //! Start a socket server, accept connections, and read "realtime" control messages into the message queue.
+ /*!
+ This function creates a socket server on the optional port
+ (default = 2001) and starts a thread for asynchronous retrieval of
+ SKINI formatted messages from socket connections. A return value
+ of \c true indicates the call was successful. A return value of
+ \c false can occur if a scorefile is being read, a socket thread
+ is already running, or an error occurs during the socket server
+ or thread initialization stages. Socket input is considered to be
+ a realtime control mechanism that cannot run concurrently with
+ non-realtime scorefile input.
+ */
+ bool startSocketInput( int port=2001 );
+
+ //! Start MIDI input, with optional device and port identifiers.
+ /*!
+ This function creates an RtMidiIn instance for MIDI input. The
+ RtMidiIn class invokes a local callback function to read incoming
+ messages into the queue. If \c port = -1, RtMidiIn will open a
+ virtual port to which other software applications can connect (OS
+ X and Linux only). A return value of \c true indicates the call
+ was successful. A return value of \c false can occur if a
+ scorefile is being read, MIDI input is already running, or an
+ error occurs during RtMidiIn construction. Midi input is
+ considered to be a realtime control mechanism that cannot run
+ concurrently with non-realtime scorefile input.
+ */
+ bool startMidiInput( int port=0 );
+
+#endif
+
+ protected:
+
+ MessagerData data_;
+
+#if defined(__STK_REALTIME__)
+ Thread stdinThread_;
+ Thread socketThread_;
+#endif
+
+};
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_MIDIFILEIN_H
+#define STK_MIDIFILEIN_H
+
+#include "Stk.h"
+#include <string>
+#include <vector>
+#include <fstream>
+#include <sstream>
+
+namespace stk {
+
+/**********************************************************************/
+/*! \class MidiFileIn
+ \brief A standard MIDI file reading/parsing class.
+
+ This class can be used to read events from a standard MIDI file.
+ Event bytes are copied to a C++ vector and must be subsequently
+ interpreted by the user. The function getNextMidiEvent() skips
+ meta and sysex events, returning only MIDI channel messages.
+ Event delta-times are returned in the form of "ticks" and a
+ function is provided to determine the current "seconds per tick".
+ Tempo changes are internally tracked by the class and reflected in
+ the values returned by the function getTickSeconds().
+
+ by Gary P. Scavone, 2003 - 2010.
+*/
+/**********************************************************************/
+
+class MidiFileIn : public Stk
+{
+ public:
+ //! Default constructor.
+ /*!
+ If an error occurs while opening or parsing the file header, an
+ StkError exception will be thrown.
+ */
+ MidiFileIn( std::string fileName );
+
+ //! Class destructor.
+ ~MidiFileIn();
+
+ //! Return the MIDI file format (0, 1, or 2).
+ int getFileFormat() const;
+
+ //! Return the number of tracks in the MIDI file.
+ unsigned int getNumberOfTracks() const;
+
+ //! Return the MIDI file division value from the file header.
+ /*!
+ Note that this value must be "parsed" in accordance with the
+ MIDI File Specification. In particular, if the MSB is set, the
+ file uses time-code representations for delta-time values.
+ */
+ int getDivision() const;
+
+ //! Move the specified track event reader to the beginning of its track.
+ /*!
+ The relevant track tempo value is reset as well. If an invalid
+ track number is specified, an StkError exception will be thrown.
+ */
+ void rewindTrack( unsigned int track = 0 );
+
+ //! Get the current value, in seconds, of delta-time ticks for the specified track.
+ /*!
+ This value can change as events are read (via "Set Tempo"
+ Meta-Events). Therefore, one should call this function after
+ every call to getNextEvent() or getNextMidiEvent(). If an
+ invalid track number is specified, an StkError exception will be
+ thrown.
+ */
+ double getTickSeconds( unsigned int track = 0 );
+
+ //! Fill the user-provided vector with the next event in the specified track and return the event delta-time in ticks.
+ /*!
+ MIDI File events consist of a delta time and a sequence of event
+ bytes. This function returns the delta-time value and writes
+ the subsequent event bytes directly to the event vector. The
+ user must parse the event bytes in accordance with the MIDI File
+ Specification. All returned MIDI channel events are complete
+ ... a status byte is provided even when running status is used
+ in the file. If the track has reached its end, no bytes will be
+ written and the event vector size will be zero. If an invalid
+ track number is specified or an error occurs while reading the
+ file, an StkError exception will be thrown.
+ */
+ unsigned long getNextEvent( std::vector<unsigned char> *event, unsigned int track = 0 );
+
+ //! Fill the user-provided vector with the next MIDI channel event in the specified track and return the event delta time in ticks.
+ /*!
+ All returned MIDI events are complete ... a status byte is
+ provided even when running status is used in the file. Meta and
+ sysex events in the track are skipped though "Set Tempo" events
+ are properly parsed for use by the getTickSeconds() function.
+ If the track has reached its end, no bytes will be written and
+ the event vector size will be zero. If an invalid track number
+ is specified or an error occurs while reading the file, an
+ StkError exception will be thrown.
+ */
+ unsigned long getNextMidiEvent( std::vector<unsigned char> *midiEvent, unsigned int track = 0 );
+
+ protected:
+
+ // This protected class function is used for reading variable-length
+ // MIDI file values. It is assumed that this function is called with
+ // the file read pointer positioned at the start of a
+ // variable-length value. The function returns true if the value is
+ // successfully parsed. Otherwise, it returns false.
+ bool readVariableLength( unsigned long *value );
+
+ std::ifstream file_;
+ unsigned int nTracks_;
+ int format_;
+ int division_;
+ bool usingTimeCode_;
+ std::vector<double> tickSeconds_;
+ std::vector<long> trackPointers_;
+ std::vector<long> trackOffsets_;
+ std::vector<long> trackLengths_;
+ std::vector<char> trackStatus_;
+
+ // This structure and the following variables are used to save and
+ // keep track of a format 1 tempo map (and the initial tickSeconds
+ // parameter for formats 0 and 2).
+ struct TempoChange {
+ unsigned long count;
+ double tickSeconds;
+ };
+ std::vector<TempoChange> tempoEvents_;
+ std::vector<unsigned long> trackCounters_;
+ std::vector<unsigned int> trackTempoIndex_;
+};
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_MODAL_H
+#define STK_MODAL_H
+
+#include "Instrmnt.h"
+#include "Envelope.h"
+#include "FileLoop.h"
+#include "SineWave.h"
+#include "BiQuad.h"
+#include "OnePole.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class Modal
+ \brief STK resonance model abstract base class.
+
+ This class contains an excitation wavetable,
+ an envelope, an oscillator, and N resonances
+ (non-sweeping BiQuad filters), where N is set
+ during instantiation.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class Modal : public Instrmnt
+{
+public:
+ //! Class constructor, taking the desired number of modes to create.
+ /*!
+ An StkError will be thrown if the rawwave path is incorrectly set.
+ */
+ Modal( unsigned int modes = 4 );
+
+ //! Class destructor.
+ virtual ~Modal( void );
+
+ //! Reset and clear all internal state.
+ void clear( void );
+
+ //! Set instrument parameters for a particular frequency.
+ virtual void setFrequency( StkFloat frequency );
+
+ //! Set the ratio and radius for a specified mode filter.
+ void setRatioAndRadius( unsigned int modeIndex, StkFloat ratio, StkFloat radius );
+
+ //! Set the master gain.
+ void setMasterGain( StkFloat aGain ) { masterGain_ = aGain; };
+
+ //! Set the direct gain.
+ void setDirectGain( StkFloat aGain ) { directGain_ = aGain; };
+
+ //! Set the gain for a specified mode filter.
+ void setModeGain( unsigned int modeIndex, StkFloat gain );
+
+ //! Initiate a strike with the given amplitude (0.0 - 1.0).
+ virtual void strike( StkFloat amplitude );
+
+ //! Damp modes with a given decay factor (0.0 - 1.0).
+ void damp( StkFloat amplitude );
+
+ //! Start a note with the given frequency and amplitude.
+ void noteOn( StkFloat frequency, StkFloat amplitude );
+
+ //! Stop a note with the given amplitude (speed of decay).
+ void noteOff( StkFloat amplitude );
+
+ //! Perform the control change specified by \e number and \e value (0.0 - 128.0).
+ virtual void controlChange( int number, StkFloat value ) = 0;
+
+ //! Compute and return one output sample.
+ StkFloat tick( unsigned int channel = 0 );
+
+protected:
+
+ Envelope envelope_;
+ FileWvIn *wave_;
+ BiQuad **filters_;
+ OnePole onepole_;
+ SineWave vibrato_;
+
+ unsigned int nModes_;
+ std::vector<StkFloat> ratios_;
+ std::vector<StkFloat> radii_;
+
+ StkFloat vibratoGain_;
+ StkFloat masterGain_;
+ StkFloat directGain_;
+ StkFloat stickHardness_;
+ StkFloat strikePosition_;
+ StkFloat baseFrequency_;
+};
+
+inline StkFloat Modal :: tick( unsigned int )
+{
+ StkFloat temp = masterGain_ * onepole_.tick( wave_->tick() * envelope_.tick() );
+
+ StkFloat temp2 = 0.0;
+ for ( unsigned int i=0; i<nModes_; i++ )
+ temp2 += filters_[i]->tick(temp);
+
+ temp2 -= temp2 * directGain_;
+ temp2 += directGain_ * temp;
+
+ if ( vibratoGain_ != 0.0 ) {
+ // Calculate AM and apply to master out
+ temp = 1.0 + ( vibrato_.tick() * vibratoGain_ );
+ temp2 = temp * temp2;
+ }
+
+ lastFrame_[0] = temp2;
+ return lastFrame_[0];
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_MODALBAR_H
+#define STK_MODALBAR_H
+
+#include "Modal.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class ModalBar
+ \brief STK resonant bar instrument class.
+
+ This class implements a number of different
+ struck bar instruments. It inherits from the
+ Modal class.
+
+ Control Change Numbers:
+ - Stick Hardness = 2
+ - Stick Position = 4
+ - Vibrato Gain = 1
+ - Vibrato Frequency = 11
+ - Direct Stick Mix = 8
+ - Volume = 128
+ - Modal Presets = 16
+ - Marimba = 0
+ - Vibraphone = 1
+ - Agogo = 2
+ - Wood1 = 3
+ - Reso = 4
+ - Wood2 = 5
+ - Beats = 6
+ - Two Fixed = 7
+ - Clump = 8
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class ModalBar : public Modal
+{
+public:
+ //! Class constructor.
+ ModalBar( void );
+
+ //! Class destructor.
+ ~ModalBar( void );
+
+ //! Set stick hardness (0.0 - 1.0).
+ void setStickHardness( StkFloat hardness );
+
+ //! Set stick position (0.0 - 1.0).
+ void setStrikePosition( StkFloat position );
+
+ //! Select a bar preset (currently modulo 9).
+ void setPreset( int preset );
+
+ //! Set the modulation (vibrato) depth.
+ void setModulationDepth( StkFloat mDepth );
+
+ //! Perform the control change specified by \e number and \e value (0.0 - 128.0).
+ void controlChange( int number, StkFloat value );
+};
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_MODULATE_H
+#define STK_MODULATE_H
+
+#include "Generator.h"
+#include "SineWave.h"
+#include "Noise.h"
+#include "OnePole.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class Modulate
+ \brief STK periodic/random modulator.
+
+ This class combines random and periodic
+ modulations to give a nice, natural human
+ modulation function.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class Modulate : public Generator
+{
+ public:
+ //! Class constructor.
+ /*!
+ An StkError can be thrown if the rawwave path is incorrect.
+ */
+ Modulate( void );
+
+ //! Class destructor.
+ ~Modulate( void );
+
+ //! Reset internal state.
+ void reset( void ) { lastFrame_[0] = 0.0; };
+
+ //! Set the periodic (vibrato) rate or frequency in Hz.
+ void setVibratoRate( StkFloat rate ) { vibrato_.setFrequency( rate ); };
+
+ //! Set the periodic (vibrato) gain.
+ void setVibratoGain( StkFloat gain ) { vibratoGain_ = gain; };
+
+ //! Set the random modulation gain.
+ void setRandomGain( StkFloat gain );
+
+ //! Return the last computed output value.
+ StkFloat lastOut( void ) const { return lastFrame_[0]; };
+
+ //! Compute and return one output sample.
+ StkFloat tick( void );
+
+ //! Fill a channel of the StkFrames object with computed outputs.
+ /*!
+ The \c channel argument must be less than the number of
+ channels in the StkFrames argument (the first channel is specified
+ by 0). However, range checking is only performed if _STK_DEBUG_
+ is defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
+
+ protected:
+
+ void sampleRateChanged( StkFloat newRate, StkFloat oldRate );
+
+ SineWave vibrato_;
+ Noise noise_;
+ OnePole filter_;
+ StkFloat vibratoGain_;
+ StkFloat randomGain_;
+ unsigned int noiseRate_;
+ unsigned int noiseCounter_;
+
+};
+
+inline StkFloat Modulate :: tick( void )
+{
+ // Compute periodic and random modulations.
+ lastFrame_[0] = vibratoGain_ * vibrato_.tick();
+ if ( noiseCounter_++ >= noiseRate_ ) {
+ noise_.tick();
+ noiseCounter_ = 0;
+ }
+ lastFrame_[0] += filter_.tick( noise_.lastOut() );
+ return lastFrame_[0];
+}
+
+inline StkFrames& Modulate :: tick( StkFrames& frames, unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel >= frames.channels() ) {
+ errorString_ << "Modulate::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *samples = &frames[channel];
+ unsigned int hop = frames.channels();
+ for ( unsigned int i=0; i<frames.frames(); i++, samples += hop )
+ *samples = Modulate::tick();
+
+ return frames;
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_MOOG_H
+#define STK_MOOG_H
+
+#include "Sampler.h"
+#include "FormSwep.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class Moog
+ \brief STK moog-like swept filter sampling synthesis class.
+
+ This instrument uses one attack wave, one
+ looped wave, and an ADSR envelope (inherited
+ from the Sampler class) and adds two sweepable
+ formant (FormSwep) filters.
+
+ Control Change Numbers:
+ - Filter Q = 2
+ - Filter Sweep Rate = 4
+ - Vibrato Frequency = 11
+ - Vibrato Gain = 1
+ - Gain = 128
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class Moog : public Sampler
+{
+ public:
+ //! Class constructor.
+ /*!
+ An StkError will be thrown if the rawwave path is incorrectly set.
+ */
+ Moog( void );
+
+ //! Class destructor.
+ ~Moog( void );
+
+ //! Set instrument parameters for a particular frequency.
+ void setFrequency( StkFloat frequency );
+
+ //! Start a note with the given frequency and amplitude.
+ void noteOn( StkFloat frequency, StkFloat amplitude );
+
+ //! Set the modulation (vibrato) speed in Hz.
+ void setModulationSpeed( StkFloat mSpeed ) { loops_[1]->setFrequency( mSpeed ); };
+
+ //! Set the modulation (vibrato) depth.
+ void setModulationDepth( StkFloat mDepth ) { modDepth_ = mDepth * 0.5; };
+
+ //! Perform the control change specified by \e number and \e value (0.0 - 128.0).
+ void controlChange( int number, StkFloat value );
+
+ //! Compute and return one output sample.
+ StkFloat tick( unsigned int channel = 0 );
+
+ protected:
+
+ FormSwep filters_[2];
+ StkFloat modDepth_;
+ StkFloat filterQ_;
+ StkFloat filterRate_;
+
+};
+
+inline StkFloat Moog :: tick( unsigned int )
+{
+ StkFloat temp;
+
+ if ( modDepth_ != 0.0 ) {
+ temp = loops_[1]->tick() * modDepth_;
+ loops_[0]->setFrequency( baseFrequency_ * (1.0 + temp) );
+ }
+
+ temp = attackGain_ * attacks_[0]->tick();
+ temp += loopGain_ * loops_[0]->tick();
+ temp = filter_.tick( temp );
+ temp *= adsr_.tick();
+ temp = filters_[0].tick( temp );
+ lastFrame_[0] = filters_[1].tick( temp );
+ return lastFrame_[0] * 6.0;
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_MUTEX_H
+#define STK_MUTEX_H
+
+#include "Stk.h"
+
+#if (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__))
+
+ #include <pthread.h>
+ typedef pthread_mutex_t MUTEX;
+ typedef pthread_cond_t CONDITION;
+
+#elif defined(__OS_WINDOWS__)
+
+ #include <windows.h>
+ #include <process.h>
+ typedef CRITICAL_SECTION MUTEX;
+ typedef HANDLE CONDITION;
+
+#endif
+
+namespace stk {
+
+/***************************************************/
+/*! \class Mutex
+ \brief STK mutex class.
+
+ This class provides a uniform interface for
+ cross-platform mutex use. On Linux and IRIX
+ systems, the pthread library is used. Under
+ Windows, critical sections are used.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class Mutex : public Stk
+{
+ public:
+ //! Default constructor.
+ Mutex();
+
+ //! Class destructor.
+ ~Mutex();
+
+ //! Lock the mutex.
+ void lock(void);
+
+ //! Unlock the mutex.
+ void unlock(void);
+
+ //! Wait indefinitely on the mutex condition variable.
+ /*!
+ The mutex must be locked before calling this function, and then
+ subsequently unlocked after this function returns.
+ */
+ void wait(void);
+
+ //! Signal the condition variable.
+ /*!
+ The mutex must be locked before calling this function, and then
+ subsequently unlocked after this function returns.
+ */
+ void signal(void);
+
+ protected:
+
+ MUTEX mutex_;
+ CONDITION condition_;
+
+};
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_NREV_H
+#define STK_NREV_H
+
+#include "Effect.h"
+#include "Delay.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class NRev
+ \brief CCRMA's NRev reverberator class.
+
+ This class takes a monophonic input signal and produces a stereo
+ output signal. It is derived from the CLM NRev function, which is
+ based on the use of networks of simple allpass and comb delay
+ filters. This particular arrangement consists of 6 comb filters
+ in parallel, followed by 3 allpass filters, a lowpass filter, and
+ another allpass in series, followed by two allpass filters in
+ parallel with corresponding right and left outputs.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class NRev : public Effect
+{
+ public:
+ //! Class constructor taking a T60 decay time argument (one second default value).
+ NRev( StkFloat T60 = 1.0 );
+
+ //! Reset and clear all internal state.
+ void clear( void );
+
+ //! Set the reverberation T60 decay time.
+ void setT60( StkFloat T60 );
+
+ //! Return the specified channel value of the last computed stereo frame.
+ /*!
+ Use the lastFrame() function to get both values of the last
+ computed stereo frame. The \c channel argument must be 0 or 1
+ (the first channel is specified by 0). However, range checking is
+ only performed if _STK_DEBUG_ is defined during compilation, in
+ which case an out-of-range value will trigger an StkError
+ exception.
+ */
+ StkFloat lastOut( unsigned int channel = 0 );
+
+ //! Input one sample to the effect and return the specified \c channel value of the computed stereo frame.
+ /*!
+ Use the lastFrame() function to get both values of the computed
+ stereo output frame. The \c channel argument must be 0 or 1 (the
+ first channel is specified by 0). However, range checking is only
+ performed if _STK_DEBUG_ is defined during compilation, in which
+ case an out-of-range value will trigger an StkError exception.
+ */
+ StkFloat tick( StkFloat input, unsigned int channel = 0 );
+
+ //! Take a channel of the StkFrames object as inputs to the effect and replace with stereo outputs.
+ /*!
+ The StkFrames argument reference is returned. The stereo
+ outputs are written to the StkFrames argument starting at the
+ specified \c channel. Therefore, the \c channel argument must be
+ less than ( channels() - 1 ) of the StkFrames argument (the first
+ channel is specified by 0). However, range checking is only
+ performed if _STK_DEBUG_ is defined during compilation, in which
+ case an out-of-range value will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
+
+ //! Take a channel of the \c iFrames object as inputs to the effect and write stereo outputs to the \c oFrames object.
+ /*!
+ The \c iFrames object reference is returned. The \c iChannel
+ argument must be less than the number of channels in the \c
+ iFrames argument (the first channel is specified by 0). The \c
+ oChannel argument must be less than ( channels() - 1 ) of the \c
+ oFrames argument. However, range checking is only performed if
+ _STK_DEBUG_ is defined during compilation, in which case an
+ out-of-range value will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& iFrames, StkFrames &oFrames, unsigned int iChannel = 0, unsigned int oChannel = 0 );
+
+ protected:
+
+ Delay allpassDelays_[8];
+ Delay combDelays_[6];
+ StkFloat allpassCoefficient_;
+ StkFloat combCoefficient_[6];
+ StkFloat lowpassState_;
+
+};
+
+inline StkFloat NRev :: lastOut( unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel > 1 ) {
+ errorString_ << "NRev::lastOut(): channel argument must be less than 2!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ return lastFrame_[channel];
+}
+
+inline StkFloat NRev :: tick( StkFloat input, unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel > 1 ) {
+ errorString_ << "NRev::tick(): channel argument must be less than 2!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat temp, temp0, temp1, temp2, temp3;
+ int i;
+
+ temp0 = 0.0;
+ for ( i=0; i<6; i++ ) {
+ temp = input + (combCoefficient_[i] * combDelays_[i].lastOut());
+ temp0 += combDelays_[i].tick(temp);
+ }
+
+ for ( i=0; i<3; i++ ) {
+ temp = allpassDelays_[i].lastOut();
+ temp1 = allpassCoefficient_ * temp;
+ temp1 += temp0;
+ allpassDelays_[i].tick(temp1);
+ temp0 = -(allpassCoefficient_ * temp1) + temp;
+ }
+
+ // One-pole lowpass filter.
+ lowpassState_ = 0.7 * lowpassState_ + 0.3 * temp0;
+ temp = allpassDelays_[3].lastOut();
+ temp1 = allpassCoefficient_ * temp;
+ temp1 += lowpassState_;
+ allpassDelays_[3].tick( temp1 );
+ temp1 = -( allpassCoefficient_ * temp1 ) + temp;
+
+ temp = allpassDelays_[4].lastOut();
+ temp2 = allpassCoefficient_ * temp;
+ temp2 += temp1;
+ allpassDelays_[4].tick( temp2 );
+ lastFrame_[0] = effectMix_*( -( allpassCoefficient_ * temp2 ) + temp );
+
+ temp = allpassDelays_[5].lastOut();
+ temp3 = allpassCoefficient_ * temp;
+ temp3 += temp1;
+ allpassDelays_[5].tick( temp3 );
+ lastFrame_[1] = effectMix_*( - ( allpassCoefficient_ * temp3 ) + temp );
+
+ temp = ( 1.0 - effectMix_ ) * input;
+ lastFrame_[0] += temp;
+ lastFrame_[1] += temp;
+
+ return lastFrame_[channel];
+}
+
+} // stk namespace
+
+#endif
+
--- /dev/null
+#ifndef STK_NOISE_H
+#define STK_NOISE_H
+
+#include "Generator.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class Noise
+ \brief STK noise generator.
+
+ Generic random number generation using the
+ C rand() function. The quality of the rand()
+ function varies from one OS to another.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class Noise : public Generator
+{
+public:
+
+ //! Default constructor that can also take a specific seed value.
+ /*!
+ If the seed value is zero (the default value), the random number generator is
+ seeded with the system time.
+ */
+ Noise( unsigned int seed = 0 );
+
+ //! Seed the random number generator with a specific seed value.
+ /*!
+ If no seed is provided or the seed value is zero, the random
+ number generator is seeded with the current system time.
+ */
+ void setSeed( unsigned int seed = 0 );
+
+ //! Return the last computed output value.
+ StkFloat lastOut( void ) const { return lastFrame_[0]; };
+
+ //! Compute and return one output sample.
+ StkFloat tick( void );
+
+ //! Fill a channel of the StkFrames object with computed outputs.
+ /*!
+ The \c channel argument must be less than the number of
+ channels in the StkFrames argument (the first channel is specified
+ by 0). However, range checking is only performed if _STK_DEBUG_
+ is defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
+
+protected:
+
+};
+
+inline StkFloat Noise :: tick( void )
+{
+ return lastFrame_[0] = (StkFloat) ( 2.0 * rand() / (RAND_MAX + 1.0) - 1.0 );
+}
+
+inline StkFrames& Noise :: tick( StkFrames& frames, unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel >= frames.channels() ) {
+ errorString_ << "Noise::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *samples = &frames[channel];
+ unsigned int hop = frames.channels();
+ for ( unsigned int i=0; i<frames.frames(); i++, samples += hop )
+ *samples = (StkFloat) ( 2.0 * rand() / (RAND_MAX + 1.0) - 1.0 );
+
+ lastFrame_[0] = *(samples-hop);
+ return frames;
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_ONEPOLE_H
+#define STK_ONEPOLE_H
+
+#include "Filter.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class OnePole
+ \brief STK one-pole filter class.
+
+ This class implements a one-pole digital filter. A method is
+ provided for setting the pole position along the real axis of the
+ z-plane while maintaining a constant peak filter gain.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class OnePole : public Filter
+{
+public:
+
+ //! The default constructor creates a low-pass filter (pole at z = 0.9).
+ OnePole( StkFloat thePole = 0.9 );
+
+ //! Class destructor.
+ ~OnePole();
+
+ //! Set the b[0] coefficient value.
+ void setB0( StkFloat b0 ) { b_[0] = b0; };
+
+ //! Set the a[1] coefficient value.
+ void setA1( StkFloat a1 ) { a_[1] = a1; };
+
+ //! Set all filter coefficients.
+ void setCoefficients( StkFloat b0, StkFloat a1, bool clearState = false );
+
+ //! Set the pole position in the z-plane.
+ /*!
+ This method sets the pole position along the real-axis of the
+ z-plane and normalizes the coefficients for a maximum gain of one.
+ A positive pole value produces a low-pass filter, while a negative
+ pole value produces a high-pass filter. This method does not
+ affect the filter \e gain value.
+ */
+ void setPole( StkFloat thePole );
+
+ //! Return the last computed output value.
+ StkFloat lastOut( void ) const { return lastFrame_[0]; };
+
+ //! Input one sample to the filter and return one output.
+ StkFloat tick( StkFloat input );
+
+ //! Take a channel of the StkFrames object as inputs to the filter and replace with corresponding outputs.
+ /*!
+ The StkFrames argument reference is returned. The \c channel
+ argument must be less than the number of channels in the
+ StkFrames argument (the first channel is specified by 0).
+ However, range checking is only performed if _STK_DEBUG_ is
+ defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
+
+ //! Take a channel of the \c iFrames object as inputs to the filter and write outputs to the \c oFrames object.
+ /*!
+ The \c iFrames object reference is returned. Each channel
+ argument must be less than the number of channels in the
+ corresponding StkFrames argument (the first channel is specified
+ by 0). However, range checking is only performed if _STK_DEBUG_
+ is defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& iFrames, StkFrames &oFrames, unsigned int iChannel = 0, unsigned int oChannel = 0 );
+
+};
+
+inline StkFloat OnePole :: tick( StkFloat input )
+{
+ inputs_[0] = gain_ * input;
+ lastFrame_[0] = b_[0] * inputs_[0] - a_[1] * outputs_[1];
+ outputs_[1] = lastFrame_[0];
+
+ return lastFrame_[0];
+}
+
+inline StkFrames& OnePole :: tick( StkFrames& frames, unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel >= frames.channels() ) {
+ errorString_ << "OnePole::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *samples = &frames[channel];
+ unsigned int hop = frames.channels();
+ for ( unsigned int i=0; i<frames.frames(); i++, samples += hop ) {
+ inputs_[0] = gain_ * *samples;
+ *samples = b_[0] * inputs_[0] - a_[1] * outputs_[1];
+ outputs_[1] = *samples;
+ }
+
+ lastFrame_[0] = outputs_[1];
+ return frames;
+}
+
+inline StkFrames& OnePole :: tick( StkFrames& iFrames, StkFrames& oFrames, unsigned int iChannel, unsigned int oChannel )
+{
+#if defined(_STK_DEBUG_)
+ if ( iChannel >= iFrames.channels() || oChannel >= oFrames.channels() ) {
+ errorString_ << "OnePole::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *iSamples = &iFrames[iChannel];
+ StkFloat *oSamples = &oFrames[oChannel];
+ unsigned int iHop = iFrames.channels(), oHop = oFrames.channels();
+ for ( unsigned int i=0; i<iFrames.frames(); i++, iSamples += iHop, oSamples += oHop ) {
+ inputs_[0] = gain_ * *iSamples;
+ *oSamples = b_[0] * inputs_[0] - a_[1] * outputs_[1];
+ outputs_[1] = *oSamples;
+ }
+
+ lastFrame_[0] = outputs_[1];
+ return iFrames;
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_ONEZERO_H
+#define STK_ONEZERO_H
+
+#include "Filter.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class OneZero
+ \brief STK one-zero filter class.
+
+ This class implements a one-zero digital filter. A method is
+ provided for setting the zero position along the real axis of the
+ z-plane while maintaining a constant filter gain.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class OneZero : public Filter
+{
+ public:
+
+ //! The default constructor creates a low-pass filter (zero at z = -1.0).
+ OneZero( StkFloat theZero = -1.0 );
+
+ //! Class destructor.
+ ~OneZero();
+
+ //! Set the b[0] coefficient value.
+ void setB0( StkFloat b0 ) { b_[0] = b0; };
+
+ //! Set the b[1] coefficient value.
+ void setB1( StkFloat b1 ) { b_[1] = b1; };
+
+ //! Set all filter coefficients.
+ void setCoefficients( StkFloat b0, StkFloat b1, bool clearState = false );
+
+ //! Set the zero position in the z-plane.
+ /*!
+ This method sets the zero position along the real-axis of the
+ z-plane and normalizes the coefficients for a maximum gain of one.
+ A positive zero value produces a high-pass filter, while a
+ negative zero value produces a low-pass filter. This method does
+ not affect the filter \e gain value.
+ */
+ void setZero( StkFloat theZero );
+
+ //! Return the last computed output value.
+ StkFloat lastOut( void ) const { return lastFrame_[0]; };
+
+ //! Input one sample to the filter and return one output.
+ StkFloat tick( StkFloat input );
+
+ //! Take a channel of the StkFrames object as inputs to the filter and replace with corresponding outputs.
+ /*!
+ The StkFrames argument reference is returned. The \c channel
+ argument must be less than the number of channels in the
+ StkFrames argument (the first channel is specified by 0).
+ However, range checking is only performed if _STK_DEBUG_ is
+ defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
+
+ //! Take a channel of the \c iFrames object as inputs to the filter and write outputs to the \c oFrames object.
+ /*!
+ The \c iFrames object reference is returned. Each channel
+ argument must be less than the number of channels in the
+ corresponding StkFrames argument (the first channel is specified
+ by 0). However, range checking is only performed if _STK_DEBUG_
+ is defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& iFrames, StkFrames &oFrames, unsigned int iChannel = 0, unsigned int oChannel = 0 );
+
+};
+
+inline StkFloat OneZero :: tick( StkFloat input )
+{
+ inputs_[0] = gain_ * input;
+ lastFrame_[0] = b_[1] * inputs_[1] + b_[0] * inputs_[0];
+ inputs_[1] = inputs_[0];
+
+ return lastFrame_[0];
+}
+
+inline StkFrames& OneZero :: tick( StkFrames& frames, unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel >= frames.channels() ) {
+ errorString_ << "OneZero::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *samples = &frames[channel];
+ unsigned int hop = frames.channels();
+ for ( unsigned int i=0; i<frames.frames(); i++, samples += hop ) {
+ inputs_[0] = gain_ * *samples;
+ *samples = b_[1] * inputs_[1] + b_[0] * inputs_[0];
+ inputs_[1] = inputs_[0];
+ }
+
+ lastFrame_[0] = *(samples-hop);
+ return frames;
+}
+
+inline StkFrames& OneZero :: tick( StkFrames& iFrames, StkFrames& oFrames, unsigned int iChannel, unsigned int oChannel )
+{
+#if defined(_STK_DEBUG_)
+ if ( iChannel >= iFrames.channels() || oChannel >= oFrames.channels() ) {
+ errorString_ << "OneZero::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *iSamples = &iFrames[iChannel];
+ StkFloat *oSamples = &oFrames[oChannel];
+ unsigned int iHop = iFrames.channels(), oHop = oFrames.channels();
+ for ( unsigned int i=0; i<iFrames.frames(); i++, iSamples += iHop, oSamples += oHop ) {
+ inputs_[0] = gain_ * *iSamples;
+ *oSamples = b_[1] * inputs_[1] + b_[0] * inputs_[0];
+ inputs_[1] = inputs_[0];
+ }
+
+ lastFrame_[0] = *(oSamples-oHop);
+ return iFrames;
+}
+
+} // stk namespace
+
+#endif
+
--- /dev/null
+#ifndef STK_PRCREV_H
+#define STK_PRCREV_H
+
+#include "Effect.h"
+#include "Delay.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class PRCRev
+ \brief Perry's simple reverberator class.
+
+ This class takes a monophonic input signal and produces a stereo
+ output signal. It is based on some of the famous Stanford/CCRMA
+ reverbs (NRev, KipRev), which were based on the
+ Chowning/Moorer/Schroeder reverberators using networks of simple
+ allpass and comb delay filters. This class implements two series
+ allpass units and two parallel comb filters.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class PRCRev : public Effect
+{
+public:
+ //! Class constructor taking a T60 decay time argument (one second default value).
+ PRCRev( StkFloat T60 = 1.0 );
+
+ //! Reset and clear all internal state.
+ void clear( void );
+
+ //! Set the reverberation T60 decay time.
+ void setT60( StkFloat T60 );
+
+ //! Return the specified channel value of the last computed stereo frame.
+ /*!
+ Use the lastFrame() function to get both values of the last
+ computed stereo frame. The \c channel argument must be 0 or 1
+ (the first channel is specified by 0). However, range checking is
+ only performed if _STK_DEBUG_ is defined during compilation, in
+ which case an out-of-range value will trigger an StkError
+ exception.
+ */
+ StkFloat lastOut( unsigned int channel = 0 );
+
+ //! Input one sample to the effect and return the specified \c channel value of the computed stereo frame.
+ /*!
+ Use the lastFrame() function to get both values of the computed
+ stereo output frame. The \c channel argument must be 0 or 1 (the
+ first channel is specified by 0). However, range checking is only
+ performed if _STK_DEBUG_ is defined during compilation, in which
+ case an out-of-range value will trigger an StkError exception.
+ */
+ StkFloat tick( StkFloat input, unsigned int channel = 0 );
+
+ //! Take a channel of the StkFrames object as inputs to the effect and replace with stereo outputs.
+ /*!
+ The StkFrames argument reference is returned. The stereo
+ outputs are written to the StkFrames argument starting at the
+ specified \c channel. Therefore, the \c channel argument must be
+ less than ( channels() - 1 ) of the StkFrames argument (the first
+ channel is specified by 0). However, range checking is only
+ performed if _STK_DEBUG_ is defined during compilation, in which
+ case an out-of-range value will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
+
+ //! Take a channel of the \c iFrames object as inputs to the effect and write stereo outputs to the \c oFrames object.
+ /*!
+ The \c iFrames object reference is returned. The \c iChannel
+ argument must be less than the number of channels in the \c
+ iFrames argument (the first channel is specified by 0). The \c
+ oChannel argument must be less than ( channels() - 1 ) of the \c
+ oFrames argument. However, range checking is only performed if
+ _STK_DEBUG_ is defined during compilation, in which case an
+ out-of-range value will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& iFrames, StkFrames &oFrames, unsigned int iChannel = 0, unsigned int oChannel = 0 );
+
+protected:
+
+ Delay allpassDelays_[2];
+ Delay combDelays_[2];
+ StkFloat allpassCoefficient_;
+ StkFloat combCoefficient_[2];
+
+};
+
+inline StkFloat PRCRev :: lastOut( unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel > 1 ) {
+ errorString_ << "PRCRev::lastOut(): channel argument must be less than 2!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ return lastFrame_[channel];
+}
+
+ inline StkFloat PRCRev :: tick( StkFloat input, unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel > 1 ) {
+ errorString_ << "PRCRev::tick(): channel argument must be less than 2!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat temp, temp0, temp1, temp2, temp3;
+
+ temp = allpassDelays_[0].lastOut();
+ temp0 = allpassCoefficient_ * temp;
+ temp0 += input;
+ allpassDelays_[0].tick(temp0);
+ temp0 = -(allpassCoefficient_ * temp0) + temp;
+
+ temp = allpassDelays_[1].lastOut();
+ temp1 = allpassCoefficient_ * temp;
+ temp1 += temp0;
+ allpassDelays_[1].tick(temp1);
+ temp1 = -(allpassCoefficient_ * temp1) + temp;
+
+ temp2 = temp1 + (combCoefficient_[0] * combDelays_[0].lastOut());
+ temp3 = temp1 + (combCoefficient_[1] * combDelays_[1].lastOut());
+
+ lastFrame_[0] = effectMix_ * (combDelays_[0].tick(temp2));
+ lastFrame_[1] = effectMix_ * (combDelays_[1].tick(temp3));
+ temp = (1.0 - effectMix_) * input;
+ lastFrame_[0] += temp;
+ lastFrame_[1] += temp;
+
+ return lastFrame_[channel];
+}
+
+} // stk namespace
+
+#endif
+
--- /dev/null
+#ifndef STK_PERCFLUT_H
+#define STK_PERCFLUT_H
+
+#include "FM.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class PercFlut
+ \brief STK percussive flute FM synthesis instrument.
+
+ This class implements algorithm 4 of the TX81Z.
+
+ \code
+ Algorithm 4 is : 4->3--\
+ 2-- + -->1-->Out
+ \endcode
+
+ Control Change Numbers:
+ - Total Modulator Index = 2
+ - Modulator Crossfade = 4
+ - LFO Speed = 11
+ - LFO Depth = 1
+ - ADSR 2 & 4 Target = 128
+
+ The basic Chowning/Stanford FM patent expired
+ in 1995, but there exist follow-on patents,
+ mostly assigned to Yamaha. If you are of the
+ type who should worry about this (making
+ money) worry away.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class PercFlut : public FM
+{
+ public:
+ //! Class constructor.
+ /*!
+ An StkError will be thrown if the rawwave path is incorrectly set.
+ */
+ PercFlut( void );
+
+ //! Class destructor.
+ ~PercFlut( void );
+
+ //! Set instrument parameters for a particular frequency.
+ void setFrequency( StkFloat frequency );
+
+ //! Start a note with the given frequency and amplitude.
+ void noteOn( StkFloat frequency, StkFloat amplitude );
+
+ //! Compute and return one output sample.
+ StkFloat tick( unsigned int channel = 0 );
+
+ protected:
+
+};
+
+inline StkFloat PercFlut :: tick( unsigned int )
+{
+ register StkFloat temp;
+
+ temp = vibrato_.tick() * modDepth_ * 0.2;
+ waves_[0]->setFrequency(baseFrequency_ * (1.0 + temp) * ratios_[0]);
+ waves_[1]->setFrequency(baseFrequency_ * (1.0 + temp) * ratios_[1]);
+ waves_[2]->setFrequency(baseFrequency_ * (1.0 + temp) * ratios_[2]);
+ waves_[3]->setFrequency(baseFrequency_ * (1.0 + temp) * ratios_[3]);
+
+ waves_[3]->addPhaseOffset( twozero_.lastOut() );
+ temp = gains_[3] * adsr_[3]->tick() * waves_[3]->tick();
+
+ twozero_.tick(temp);
+ waves_[2]->addPhaseOffset( temp );
+ temp = (1.0 - (control2_ * 0.5)) * gains_[2] * adsr_[2]->tick() * waves_[2]->tick();
+
+ temp += control2_ * 0.5 * gains_[1] * adsr_[1]->tick() * waves_[1]->tick();
+ temp = temp * control1_;
+
+ waves_[0]->addPhaseOffset(temp);
+ temp = gains_[0] * adsr_[0]->tick() * waves_[0]->tick();
+
+ lastFrame_[0] = temp * 0.5;
+ return lastFrame_[0];
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_PHONEMES_H
+#define STK_PHONEMES_H
+
+#include "Stk.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class Phonemes
+ \brief STK phonemes table.
+
+ This class does nothing other than declare a
+ set of 32 static phoneme formant parameters
+ and provide access to those values.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class Phonemes : public Stk
+{
+public:
+
+ Phonemes(void);
+ ~Phonemes(void);
+
+ //! Returns the phoneme name for the given index (0-31).
+ static const char *name( unsigned int index );
+
+ //! Returns the voiced component gain for the given phoneme index (0-31).
+ static StkFloat voiceGain( unsigned int index );
+
+ //! Returns the unvoiced component gain for the given phoneme index (0-31).
+ static StkFloat noiseGain( unsigned int index );
+
+ //! Returns the formant frequency for the given phoneme index (0-31) and partial (0-3).
+ static StkFloat formantFrequency( unsigned int index, unsigned int partial );
+
+ //! Returns the formant radius for the given phoneme index (0-31) and partial (0-3).
+ static StkFloat formantRadius( unsigned int index, unsigned int partial );
+
+ //! Returns the formant gain for the given phoneme index (0-31) and partial (0-3).
+ static StkFloat formantGain( unsigned int index, unsigned int partial );
+
+private:
+
+ static const char phonemeNames[][4];
+ static const StkFloat phonemeGains[][2];
+ static const StkFloat phonemeParameters[][4][3];
+};
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_PITSHIFT_H
+#define STK_PITSHIFT_H
+
+#include "Effect.h"
+#include "DelayL.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class PitShift
+ \brief STK simple pitch shifter effect class.
+
+ This class implements a simple pitch shifter
+ using delay lines.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+const int maxDelay = 5024;
+
+class PitShift : public Effect
+{
+ public:
+ //! Class constructor.
+ PitShift( void );
+
+ //! Reset and clear all internal state.
+ void clear( void );
+
+ //! Set the pitch shift factor (1.0 produces no shift).
+ void setShift( StkFloat shift );
+
+ //! Return the last computed output value.
+ StkFloat lastOut( void ) const { return lastFrame_[0]; };
+
+ //! Input one sample to the effect and return one output.
+ StkFloat tick( StkFloat input );
+
+ //! Take a channel of the StkFrames object as inputs to the effect and replace with corresponding outputs.
+ /*!
+ The StkFrames argument reference is returned. The \c channel
+ argument must be less than the number of channels in the
+ StkFrames argument (the first channel is specified by 0).
+ However, range checking is only performed if _STK_DEBUG_ is
+ defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
+
+ //! Take a channel of the \c iFrames object as inputs to the effect and write outputs to the \c oFrames object.
+ /*!
+ The \c iFrames object reference is returned. Each channel
+ argument must be less than the number of channels in the
+ corresponding StkFrames argument (the first channel is specified
+ by 0). However, range checking is only performed if _STK_DEBUG_
+ is defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& iFrames, StkFrames &oFrames, unsigned int iChannel = 0, unsigned int oChannel = 0 );
+
+ protected:
+
+ DelayL delayLine_[2];
+ StkFloat delay_[2];
+ StkFloat env_[2];
+ StkFloat rate_;
+ unsigned long delayLength_;
+ unsigned long halfLength_;
+
+};
+
+inline StkFloat PitShift :: tick( StkFloat input )
+{
+ // Calculate the two delay length values, keeping them within the
+ // range 12 to maxDelay-12.
+ delay_[0] += rate_;
+ while ( delay_[0] > maxDelay-12 ) delay_[0] -= delayLength_;
+ while ( delay_[0] < 12 ) delay_[0] += delayLength_;
+
+ delay_[1] = delay_[0] + halfLength_;
+ while ( delay_[1] > maxDelay-12 ) delay_[1] -= delayLength_;
+ while ( delay_[1] < 12 ) delay_[1] += delayLength_;
+
+ // Set the new delay line lengths.
+ delayLine_[0].setDelay( delay_[0] );
+ delayLine_[1].setDelay( delay_[1] );
+
+ // Calculate a triangular envelope.
+ env_[1] = fabs( ( delay_[0] - halfLength_ + 12 ) * ( 1.0 / (halfLength_ + 12 ) ) );
+ env_[0] = 1.0 - env_[1];
+
+ // Delay input and apply envelope.
+ lastFrame_[0] = env_[0] * delayLine_[0].tick( input );
+ lastFrame_[0] += env_[1] * delayLine_[1].tick( input );
+
+ // Compute effect mix and output.
+ lastFrame_[0] *= effectMix_;
+ lastFrame_[0] += ( 1.0 - effectMix_ ) * input;
+
+ return lastFrame_[0];
+}
+
+} // stk namespace
+
+#endif
+
--- /dev/null
+#ifndef STK_PLUCKTWO_H
+#define STK_PLUCKTWO_H
+
+#include "Instrmnt.h"
+#include "DelayL.h"
+#include "DelayA.h"
+#include "OneZero.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class PluckTwo
+ \brief STK enhanced plucked string model class.
+
+ This class implements an enhanced two-string,
+ plucked physical model, a la Jaffe-Smith,
+ Smith, and others.
+
+ PluckTwo is an abstract class, with no excitation
+ specified. Therefore, it can't be directly
+ instantiated.
+
+ This is a digital waveguide model, making its
+ use possibly subject to patents held by
+ Stanford University, Yamaha, and others.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class PluckTwo : public Instrmnt
+{
+ public:
+ //! Class constructor, taking the lowest desired playing frequency.
+ PluckTwo( StkFloat lowestFrequency );
+
+ //! Class destructor.
+ virtual ~PluckTwo( void );
+
+ //! Reset and clear all internal state.
+ void clear( void );
+
+ //! Set instrument parameters for a particular frequency.
+ virtual void setFrequency( StkFloat frequency );
+
+ //! Detune the two strings by the given factor. A value of 1.0 produces unison strings.
+ void setDetune( StkFloat detune );
+
+ //! Efficient combined setting of frequency and detuning.
+ void setFreqAndDetune( StkFloat frequency, StkFloat detune );
+
+ //! Set the pluck or "excitation" position along the string (0.0 - 1.0).
+ void setPluckPosition( StkFloat position );
+
+ //! Set the base loop gain.
+ /*!
+ The actual loop gain is set according to the frequency.
+ Because of high-frequency loop filter roll-off, higher
+ frequency settings have greater loop gains.
+ */
+ void setBaseLoopGain( StkFloat aGain );
+
+ //! Stop a note with the given amplitude (speed of decay).
+ virtual void noteOff( StkFloat amplitude );
+
+ virtual StkFloat tick( unsigned int channel = 0 ) = 0;
+
+ protected:
+
+ DelayA delayLine_;
+ DelayA delayLine2_;
+ DelayL combDelay_;
+ OneZero filter_;
+ OneZero filter2_;
+
+ unsigned long length_;
+ StkFloat loopGain_;
+ StkFloat baseLoopGain_;
+ StkFloat lastFrequency_;
+ StkFloat lastLength_;
+ StkFloat detuning_;
+ StkFloat pluckAmplitude_;
+ StkFloat pluckPosition_;
+
+};
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_PLUCKED_H
+#define STK_PLUCKED_H
+
+#include "Instrmnt.h"
+#include "DelayA.h"
+#include "OneZero.h"
+#include "OnePole.h"
+#include "Noise.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class Plucked
+ \brief STK plucked string model class.
+
+ This class implements a simple plucked string
+ physical model based on the Karplus-Strong
+ algorithm.
+
+ This is a digital waveguide model, making its
+ use possibly subject to patents held by
+ Stanford University, Yamaha, and others.
+ There exist at least two patents, assigned to
+ Stanford, bearing the names of Karplus and/or
+ Strong.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class Plucked : public Instrmnt
+{
+ public:
+ //! Class constructor, taking the lowest desired playing frequency.
+ Plucked( StkFloat lowestFrequency );
+
+ //! Class destructor.
+ ~Plucked( void );
+
+ //! Reset and clear all internal state.
+ void clear( void );
+
+ //! Set instrument parameters for a particular frequency.
+ void setFrequency( StkFloat frequency );
+
+ //! Pluck the string with the given amplitude using the current frequency.
+ void pluck( StkFloat amplitude );
+
+ //! Start a note with the given frequency and amplitude.
+ void noteOn( StkFloat frequency, StkFloat amplitude );
+
+ //! Stop a note with the given amplitude (speed of decay).
+ void noteOff( StkFloat amplitude );
+
+ //! Compute and return one output sample.
+ StkFloat tick( unsigned int channel = 0 );
+
+ protected:
+
+ DelayA delayLine_;
+ OneZero loopFilter_;
+ OnePole pickFilter_;
+ Noise noise_;
+ StkFloat loopGain_;
+ unsigned long length_;
+
+};
+
+inline StkFloat Plucked :: tick( unsigned int )
+{
+ // Here's the whole inner loop of the instrument!!
+ return lastFrame_[0] = 3.0 * delayLine_.tick( loopFilter_.tick( delayLine_.lastOut() * loopGain_ ) );
+}
+
+} // stk namespace
+
+#endif
+
--- /dev/null
+#ifndef STK_POLEZERO_H\r
+#define STK_POLEZERO_H\r
+\r
+#include "Filter.h"\r
+\r
+namespace stk {\r
+\r
+/***************************************************/\r
+/*! \class PoleZero\r
+ \brief STK one-pole, one-zero filter class.\r
+\r
+ This class implements a one-pole, one-zero digital filter. A\r
+ method is provided for creating an allpass filter with a given\r
+ coefficient. Another method is provided to create a DC blocking\r
+ filter.\r
+\r
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.\r
+*/\r
+/***************************************************/\r
+\r
+class PoleZero : public Filter\r
+{\r
+ public:\r
+\r
+ //! Default constructor creates a first-order pass-through filter.\r
+ PoleZero();\r
+\r
+ //! Class destructor.\r
+ ~PoleZero();\r
+\r
+ //! Set the b[0] coefficient value.\r
+ void setB0( StkFloat b0 ) { b_[0] = b0; };\r
+\r
+ //! Set the b[1] coefficient value.\r
+ void setB1( StkFloat b1 ) { b_[1] = b1; };\r
+\r
+ //! Set the a[1] coefficient value.\r
+ void setA1( StkFloat a1 ) { a_[1] = a1; };\r
+\r
+ //! Set all filter coefficients.\r
+ void setCoefficients( StkFloat b0, StkFloat b1, StkFloat a1, bool clearState = false );\r
+\r
+ //! Set the filter for allpass behavior using \e coefficient.\r
+ /*!\r
+ This method uses \e coefficient to create an allpass filter,\r
+ which has unity gain at all frequencies. Note that the \e\r
+ coefficient magnitude must be less than one to maintain stability.\r
+ */\r
+ void setAllpass( StkFloat coefficient );\r
+\r
+ //! Create a DC blocking filter with the given pole position in the z-plane.\r
+ /*!\r
+ This method sets the given pole position, together with a zero\r
+ at z=1, to create a DC blocking filter. \e thePole should be\r
+ close to one to minimize low-frequency attenuation.\r
+\r
+ */\r
+ void setBlockZero( StkFloat thePole = 0.99 );\r
+\r
+ //! Return the last computed output value.\r
+ StkFloat lastOut( void ) const { return lastFrame_[0]; };\r
+\r
+ //! Input one sample to the filter and return one output.\r
+ StkFloat tick( StkFloat input );\r
+\r
+ //! Take a channel of the StkFrames object as inputs to the filter and replace with corresponding outputs.\r
+ /*!\r
+ The \c channel argument must be less than the number of\r
+ channels in the StkFrames argument (the first channel is specified\r
+ by 0). However, range checking is only performed if _STK_DEBUG_\r
+ is defined during compilation, in which case an out-of-range value\r
+ will trigger an StkError exception.\r
+ */\r
+ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );\r
+\r
+};\r
+\r
+inline StkFloat PoleZero :: tick( StkFloat input )\r
+{\r
+ inputs_[0] = gain_ * input;\r
+ lastFrame_[0] = b_[0] * inputs_[0] + b_[1] * inputs_[1] - a_[1] * outputs_[1];\r
+ inputs_[1] = inputs_[0];\r
+ outputs_[1] = lastFrame_[0];\r
+\r
+ return lastFrame_[0];\r
+}\r
+\r
+inline StkFrames& PoleZero :: tick( StkFrames& frames, unsigned int channel )\r
+{\r
+#if defined(_STK_DEBUG_)\r
+ if ( channel >= frames.channels() ) {\r
+ errorString_ << "PoleZero::tick(): channel and StkFrames arguments are incompatible!";\r
+ handleError( StkError::FUNCTION_ARGUMENT );\r
+ }\r
+#endif\r
+\r
+ StkFloat *samples = &frames[channel];\r
+ unsigned int hop = frames.channels();\r
+ for ( unsigned int i=0; i<frames.frames(); i++, samples += hop ) {\r
+ inputs_[0] = gain_ * *samples;\r
+ *samples = b_[0] * inputs_[0] + b_[1] * inputs_[1] - a_[1] * outputs_[1];\r
+ inputs_[1] = inputs_[0];\r
+ outputs_[1] = *samples;\r
+ }\r
+\r
+ lastFrame_[0] = outputs_[1];\r
+ return frames;\r
+}\r
+\r
+} // stk namespace\r
+\r
+#endif\r
--- /dev/null
+#ifndef STK_REEDTABLE_H
+#define STK_REEDTABLE_H
+
+#include "Function.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class ReedTable
+ \brief STK reed table class.
+
+ This class implements a simple one breakpoint,
+ non-linear reed function, as described by
+ Smith (1986). This function is based on a
+ memoryless non-linear spring model of the reed
+ (the reed mass is ignored) which saturates when
+ the reed collides with the mouthpiece facing.
+
+ See McIntyre, Schumacher, & Woodhouse (1983),
+ Smith (1986), Hirschman, Cook, Scavone, and
+ others for more information.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class ReedTable : public Function
+{
+public:
+ //! Default constructor.
+ ReedTable( void ) : offset_(0.6), slope_(-0.8) {};
+
+ //! Set the table offset value.
+ /*!
+ The table offset roughly corresponds to the size
+ of the initial reed tip opening (a greater offset
+ represents a smaller opening).
+ */
+ void setOffset( StkFloat offset ) { offset_ = offset; };
+
+ //! Set the table slope value.
+ /*!
+ The table slope roughly corresponds to the reed
+ stiffness (a greater slope represents a harder
+ reed).
+ */
+ void setSlope( StkFloat slope ) { slope_ = slope; };
+
+ //! Take one sample input and map to one sample of output.
+ StkFloat tick( StkFloat input );
+
+ //! Take a channel of the StkFrames object as inputs to the table and replace with corresponding outputs.
+ /*!
+ The StkFrames argument reference is returned. The \c channel
+ argument must be less than the number of channels in the
+ StkFrames argument (the first channel is specified by 0).
+ However, range checking is only performed if _STK_DEBUG_ is
+ defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
+
+ //! Take a channel of the \c iFrames object as inputs to the table and write outputs to the \c oFrames object.
+ /*!
+ The \c iFrames object reference is returned. Each channel
+ argument must be less than the number of channels in the
+ corresponding StkFrames argument (the first channel is specified
+ by 0). However, range checking is only performed if _STK_DEBUG_
+ is defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& iFrames, StkFrames &oFrames, unsigned int iChannel = 0, unsigned int oChannel = 0 );
+
+protected:
+
+ StkFloat offset_;
+ StkFloat slope_;
+
+};
+
+inline StkFloat ReedTable :: tick( StkFloat input )
+{
+ // The input is differential pressure across the reed.
+ lastFrame_[0] = offset_ + (slope_ * input);
+
+ // If output is > 1, the reed has slammed shut and the
+ // reflection function value saturates at 1.0.
+ if ( lastFrame_[0] > 1.0) lastFrame_[0] = (StkFloat) 1.0;
+
+ // This is nearly impossible in a physical system, but
+ // a reflection function value of -1.0 corresponds to
+ // an open end (and no discontinuity in bore profile).
+ if ( lastFrame_[0] < -1.0) lastFrame_[0] = (StkFloat) -1.0;
+
+ return lastFrame_[0];
+}
+
+inline StkFrames& ReedTable :: tick( StkFrames& frames, unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel >= frames.channels() ) {
+ errorString_ << "ReedTable::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *samples = &frames[channel];
+ unsigned int hop = frames.channels();
+ for ( unsigned int i=0; i<frames.frames(); i++, samples += hop ) {
+ *samples = offset_ + (slope_ * *samples);
+ if ( *samples > 1.0) *samples = 1.0;
+ if ( *samples < -1.0) *samples = -1.0;
+ }
+
+ lastFrame_[0] = *(samples-hop);
+ return frames;
+}
+
+inline StkFrames& ReedTable :: tick( StkFrames& iFrames, StkFrames& oFrames, unsigned int iChannel, unsigned int oChannel )
+{
+#if defined(_STK_DEBUG_)
+ if ( iChannel >= iFrames.channels() || oChannel >= oFrames.channels() ) {
+ errorString_ << "ReedTable::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *iSamples = &iFrames[iChannel];
+ StkFloat *oSamples = &oFrames[oChannel];
+ unsigned int iHop = iFrames.channels(), oHop = oFrames.channels();
+ for ( unsigned int i=0; i<iFrames.frames(); i++, iSamples += iHop, oSamples += oHop ) {
+ *oSamples = offset_ + (slope_ * *iSamples);
+ if ( *oSamples > 1.0) *oSamples = 1.0;
+ if ( *oSamples < -1.0) *oSamples = -1.0;
+ }
+
+ lastFrame_[0] = *(oSamples-oHop);
+ return iFrames;
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_RESONATE_H
+#define STK_RESONATE_H
+
+#include "Instrmnt.h"
+#include "ADSR.h"
+#include "BiQuad.h"
+#include "Noise.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class Resonate
+ \brief STK noise driven formant filter.
+
+ This instrument contains a noise source, which
+ excites a biquad resonance filter, with volume
+ controlled by an ADSR.
+
+ Control Change Numbers:
+ - Resonance Frequency (0-Nyquist) = 2
+ - Pole Radii = 4
+ - Notch Frequency (0-Nyquist) = 11
+ - Zero Radii = 1
+ - Envelope Gain = 128
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class Resonate : public Instrmnt
+{
+ public:
+ //! Class constructor.
+ Resonate( void );
+
+ //! Class destructor.
+ ~Resonate( void );
+
+ //! Reset and clear all internal state.
+ void clear( void );
+
+ //! Set the filter for a resonance at the given frequency (Hz) and radius.
+ void setResonance( StkFloat frequency, StkFloat radius );
+
+ //! Set the filter for a notch at the given frequency (Hz) and radius.
+ void setNotch( StkFloat frequency, StkFloat radius );
+
+ //! Set the filter zero coefficients for contant resonance gain.
+ void setEqualGainZeroes( void ) { filter_.setEqualGainZeroes(); };
+
+ //! Initiate the envelope with a key-on event.
+ void keyOn( void ) { adsr_.keyOn(); };
+
+ //! Signal a key-off event to the envelope.
+ void keyOff( void ) { adsr_.keyOff(); };
+
+ //! Start a note with the given frequency and amplitude.
+ void noteOn( StkFloat frequency, StkFloat amplitude );
+
+ //! Stop a note with the given amplitude (speed of decay).
+ void noteOff( StkFloat amplitude );
+
+ //! Perform the control change specified by \e number and \e value (0.0 - 128.0).
+ void controlChange( int number, StkFloat value );
+
+ //! Compute and return one output sample.
+ StkFloat tick( unsigned int channel = 0 );
+
+ protected:
+
+ ADSR adsr_;
+ BiQuad filter_;
+ Noise noise_;
+ StkFloat poleFrequency_;
+ StkFloat poleRadius_;
+ StkFloat zeroFrequency_;
+ StkFloat zeroRadius_;
+
+};
+
+inline StkFloat Resonate :: tick( unsigned int )
+{
+ lastFrame_[0] = filter_.tick( noise_.tick() );
+ lastFrame_[0] *= adsr_.tick();
+ return lastFrame_[0];
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_RHODEY_H
+#define STK_RHODEY_H
+
+#include "FM.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class Rhodey
+ \brief STK Fender Rhodes electric piano FM
+ synthesis instrument.
+
+ This class implements two simple FM Pairs
+ summed together, also referred to as algorithm
+ 5 of the TX81Z.
+
+ \code
+ Algorithm 5 is : 4->3--\
+ + --> Out
+ 2->1--/
+ \endcode
+
+ Control Change Numbers:
+ - Modulator Index One = 2
+ - Crossfade of Outputs = 4
+ - LFO Speed = 11
+ - LFO Depth = 1
+ - ADSR 2 & 4 Target = 128
+
+ The basic Chowning/Stanford FM patent expired
+ in 1995, but there exist follow-on patents,
+ mostly assigned to Yamaha. If you are of the
+ type who should worry about this (making
+ money) worry away.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class Rhodey : public FM
+{
+ public:
+ //! Class constructor.
+ /*!
+ An StkError will be thrown if the rawwave path is incorrectly set.
+ */
+ Rhodey( void );
+
+ //! Class destructor.
+ ~Rhodey( void );
+
+ //! Set instrument parameters for a particular frequency.
+ void setFrequency( StkFloat frequency );
+
+ //! Start a note with the given frequency and amplitude.
+ void noteOn( StkFloat frequency, StkFloat amplitude );
+
+ //! Compute and return one output sample.
+ StkFloat tick( unsigned int channel = 0 );
+
+ protected:
+
+};
+
+inline StkFloat Rhodey :: tick( unsigned int )
+{
+ StkFloat temp, temp2;
+
+ temp = gains_[1] * adsr_[1]->tick() * waves_[1]->tick();
+ temp = temp * control1_;
+
+ waves_[0]->addPhaseOffset( temp );
+ waves_[3]->addPhaseOffset( twozero_.lastOut() );
+ temp = gains_[3] * adsr_[3]->tick() * waves_[3]->tick();
+ twozero_.tick(temp);
+
+ waves_[2]->addPhaseOffset( temp );
+ temp = ( 1.0 - (control2_ * 0.5)) * gains_[0] * adsr_[0]->tick() * waves_[0]->tick();
+ temp += control2_ * 0.5 * gains_[2] * adsr_[2]->tick() * waves_[2]->tick();
+
+ // Calculate amplitude modulation and apply it to output.
+ temp2 = vibrato_.tick() * modDepth_;
+ temp = temp * (1.0 + temp2);
+
+ lastFrame_[0] = temp * 0.5;
+ return lastFrame_[0];
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_SAMPLER_H
+#define STK_SAMPLER_H
+
+#include "Instrmnt.h"
+#include "ADSR.h"
+#include "FileLoop.h"
+#include "OnePole.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class Sampler
+ \brief STK sampling synthesis abstract base class.
+
+ This instrument provides an ADSR envelope, a one-pole filter, and
+ structures for an arbitrary number of attack and looped files.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class Sampler : public Instrmnt
+{
+ public:
+ //! Default constructor.
+ Sampler( void );
+
+ //! Class destructor.
+ virtual ~Sampler( void );
+
+ //! Reset and clear all internal state.
+ void clear( void );
+
+ //! Set instrument parameters for a particular frequency.
+ virtual void setFrequency( StkFloat frequency ) = 0;
+
+ //! Initiate the envelopes with a key-on event and reset the attack waves.
+ void keyOn( void );
+
+ //! Signal a key-off event to the envelopes.
+ void keyOff( void );
+
+ //! Stop a note with the given amplitude (speed of decay).
+ virtual void noteOff( StkFloat amplitude );
+
+ //! Perform the control change specified by \e number and \e value (0.0 - 128.0).
+ virtual void controlChange( int number, StkFloat value ) = 0;
+
+ //! Compute and return one output sample.
+ virtual StkFloat tick( unsigned int channel = 0 ) = 0;
+
+ protected:
+
+ ADSR adsr_;
+ std::vector<FileWvIn *> attacks_;
+ std::vector<FileLoop *> loops_;
+ OnePole filter_;
+ StkFloat baseFrequency_;
+ std::vector<StkFloat> attackRatios_;
+ std::vector<StkFloat> loopRatios_;
+ StkFloat attackGain_;
+ StkFloat loopGain_;
+
+};
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_SAXOFONY_H
+#define STK_SAXOFONY_H
+
+#include "Instrmnt.h"
+#include "DelayL.h"
+#include "ReedTable.h"
+#include "OneZero.h"
+#include "Envelope.h"
+#include "Noise.h"
+#include "SineWave.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class Saxofony
+ \brief STK faux conical bore reed instrument class.
+
+ This class implements a "hybrid" digital
+ waveguide instrument that can generate a
+ variety of wind-like sounds. It has also been
+ referred to as the "blowed string" model. The
+ waveguide section is essentially that of a
+ string, with one rigid and one lossy
+ termination. The non-linear function is a
+ reed table. The string can be "blown" at any
+ point between the terminations, though just as
+ with strings, it is impossible to excite the
+ system at either end. If the excitation is
+ placed at the string mid-point, the sound is
+ that of a clarinet. At points closer to the
+ "bridge", the sound is closer to that of a
+ saxophone. See Scavone (2002) for more details.
+
+ This is a digital waveguide model, making its
+ use possibly subject to patents held by Stanford
+ University, Yamaha, and others.
+
+ Control Change Numbers:
+ - Reed Stiffness = 2
+ - Reed Aperture = 26
+ - Noise Gain = 4
+ - Blow Position = 11
+ - Vibrato Frequency = 29
+ - Vibrato Gain = 1
+ - Breath Pressure = 128
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class Saxofony : public Instrmnt
+{
+ public:
+ //! Class constructor, taking the lowest desired playing frequency.
+ /*!
+ An StkError will be thrown if the rawwave path is incorrectly set.
+ */
+ Saxofony( StkFloat lowestFrequency );
+
+ //! Class destructor.
+ ~Saxofony( void );
+
+ //! Reset and clear all internal state.
+ void clear( void );
+
+ //! Set instrument parameters for a particular frequency.
+ void setFrequency( StkFloat frequency );
+
+ //! Set the "blowing" position between the air column terminations (0.0 - 1.0).
+ void setBlowPosition( StkFloat aPosition );
+
+ //! Apply breath pressure to instrument with given amplitude and rate of increase.
+ void startBlowing( StkFloat amplitude, StkFloat rate );
+
+ //! Decrease breath pressure with given rate of decrease.
+ void stopBlowing( StkFloat rate );
+
+ //! Start a note with the given frequency and amplitude.
+ void noteOn( StkFloat frequency, StkFloat amplitude );
+
+ //! Stop a note with the given amplitude (speed of decay).
+ void noteOff( StkFloat amplitude );
+
+ //! Perform the control change specified by \e number and \e value (0.0 - 128.0).
+ void controlChange( int number, StkFloat value );
+
+ //! Compute and return one output sample.
+ StkFloat tick( unsigned int channel = 0 );
+
+ protected:
+
+ DelayL delays_[2];
+ ReedTable reedTable_;
+ OneZero filter_;
+ Envelope envelope_;
+ Noise noise_;
+ SineWave vibrato_;
+ unsigned long length_;
+ StkFloat outputGain_;
+ StkFloat noiseGain_;
+ StkFloat vibratoGain_;
+ StkFloat position_;
+
+};
+
+inline StkFloat Saxofony :: tick( unsigned int )
+{
+ StkFloat pressureDiff;
+ StkFloat breathPressure;
+ StkFloat temp;
+
+ // Calculate the breath pressure (envelope + noise + vibrato)
+ breathPressure = envelope_.tick();
+ breathPressure += breathPressure * noiseGain_ * noise_.tick();
+ breathPressure += breathPressure * vibratoGain_ * vibrato_.tick();
+
+ temp = -0.95 * filter_.tick( delays_[0].lastOut() );
+ lastFrame_[0] = temp - delays_[1].lastOut();
+ pressureDiff = breathPressure - lastFrame_[0];
+ delays_[1].tick( temp );
+ delays_[0].tick( breathPressure - (pressureDiff * reedTable_.tick(pressureDiff)) - temp );
+
+ lastFrame_[0] *= outputGain_;
+ return lastFrame_[0];
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_SHAKERS_H
+#define STK_SHAKERS_H
+
+#include "Instrmnt.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class Shakers
+ \brief PhISEM and PhOLIES class.
+
+ PhISEM (Physically Informed Stochastic Event
+ Modeling) is an algorithmic approach for
+ simulating collisions of multiple independent
+ sound producing objects. This class is a
+ meta-model that can simulate a Maraca, Sekere,
+ Cabasa, Bamboo Wind Chimes, Water Drops,
+ Tambourine, Sleighbells, and a Guiro.
+
+ PhOLIES (Physically-Oriented Library of
+ Imitated Environmental Sounds) is a similar
+ approach for the synthesis of environmental
+ sounds. This class implements simulations of
+ breaking sticks, crunchy snow (or not), a
+ wrench, sandpaper, and more.
+
+ Control Change Numbers:
+ - Shake Energy = 2
+ - System Decay = 4
+ - Number Of Objects = 11
+ - Resonance Frequency = 1
+ - Shake Energy = 128
+ - Instrument Selection = 1071
+ - Maraca = 0
+ - Cabasa = 1
+ - Sekere = 2
+ - Guiro = 3
+ - Water Drops = 4
+ - Bamboo Chimes = 5
+ - Tambourine = 6
+ - Sleigh Bells = 7
+ - Sticks = 8
+ - Crunch = 9
+ - Wrench = 10
+ - Sand Paper = 11
+ - Coke Can = 12
+ - Next Mug = 13
+ - Penny + Mug = 14
+ - Nickle + Mug = 15
+ - Dime + Mug = 16
+ - Quarter + Mug = 17
+ - Franc + Mug = 18
+ - Peso + Mug = 19
+ - Big Rocks = 20
+ - Little Rocks = 21
+ - Tuned Bamboo Chimes = 22
+
+ by Perry R. Cook, 1996 - 2010.
+*/
+/***************************************************/
+
+const int MAX_FREQS = 8;
+const int NUM_INSTR = 24;
+
+class Shakers : public Instrmnt
+{
+ public:
+ //! Class constructor.
+ Shakers( void );
+
+ //! Class destructor.
+ ~Shakers( void );
+
+ //! Start a note with the given instrument and amplitude.
+ /*!
+ Use the instrument numbers above, converted to frequency values
+ as if MIDI note numbers, to select a particular instrument.
+ */
+ void noteOn( StkFloat instrument, StkFloat amplitude );
+
+ //! Stop a note with the given amplitude (speed of decay).
+ void noteOff( StkFloat amplitude );
+
+ //! Perform the control change specified by \e number and \e value (0.0 - 128.0).
+ void controlChange( int number, StkFloat value );
+
+ //! Compute and return one output sample.
+ StkFloat tick( unsigned int channel = 0 );
+
+ protected:
+
+ int setupName( char* instr );
+ int setupNum( int inst );
+ int setFreqAndReson( int which, StkFloat freq, StkFloat reson );
+ void setDecays( StkFloat sndDecay, StkFloat sysDecay );
+ void setFinalZs( StkFloat z0, StkFloat z1, StkFloat z2 );
+ StkFloat wuter_tick( void );
+ StkFloat tbamb_tick( void );
+ StkFloat ratchet_tick( void );
+
+ int instType_;
+ int ratchetPos_, lastRatchetPos_;
+ StkFloat shakeEnergy_;
+ StkFloat inputs_[MAX_FREQS];
+ StkFloat outputs_[MAX_FREQS][2];
+ StkFloat coeffs_[MAX_FREQS][2];
+ StkFloat sndLevel_;
+ StkFloat baseGain_;
+ StkFloat gains_[MAX_FREQS];
+ int nFreqs_;
+ StkFloat t_center_freqs_[MAX_FREQS];
+ StkFloat center_freqs_[MAX_FREQS];
+ StkFloat resons_[MAX_FREQS];
+ StkFloat freq_rand_[MAX_FREQS];
+ int freqalloc_[MAX_FREQS];
+ StkFloat soundDecay_;
+ StkFloat systemDecay_;
+ StkFloat nObjects_;
+ StkFloat totalEnergy_;
+ StkFloat ratchet_, ratchetDelta_;
+ StkFloat finalZ_[3];
+ StkFloat finalZCoeffs_[3];
+ StkFloat defObjs_[NUM_INSTR];
+ StkFloat defDecays_[NUM_INSTR];
+ StkFloat decayScale_[NUM_INSTR];
+
+};
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_SIMPLE_H
+#define STK_SIMPLE_H
+
+#include "Instrmnt.h"
+#include "ADSR.h"
+#include "FileLoop.h"
+#include "OnePole.h"
+#include "BiQuad.h"
+#include "Noise.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class Simple
+ \brief STK wavetable/noise instrument.
+
+ This class combines a looped wave, a
+ noise source, a biquad resonance filter,
+ a one-pole filter, and an ADSR envelope
+ to create some interesting sounds.
+
+ Control Change Numbers:
+ - Filter Pole Position = 2
+ - Noise/Pitched Cross-Fade = 4
+ - Envelope Rate = 11
+ - Gain = 128
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class Simple : public Instrmnt
+{
+ public:
+ //! Class constructor.
+ /*!
+ An StkError will be thrown if the rawwave path is incorrectly set.
+ */
+ Simple( void );
+
+ //! Class destructor.
+ ~Simple( void );
+
+ //! Clear internal states.
+ void clear( void );
+
+ //! Set instrument parameters for a particular frequency.
+ void setFrequency( StkFloat frequency );
+
+ //! Start envelope toward "on" target.
+ void keyOn( void );
+
+ //! Start envelope toward "off" target.
+ void keyOff( void );
+
+ //! Start a note with the given frequency and amplitude.
+ void noteOn( StkFloat frequency, StkFloat amplitude );
+
+ //! Stop a note with the given amplitude (speed of decay).
+ void noteOff( StkFloat amplitude );
+
+ //! Perform the control change specified by \e number and \e value (0.0 - 128.0).
+ void controlChange( int number, StkFloat value );
+
+ //! Compute and return one output sample.
+ StkFloat tick( unsigned int channel = 0 );
+
+ protected:
+
+ ADSR adsr_;
+ FileLoop *loop_;
+ OnePole filter_;
+ BiQuad biquad_;
+ Noise noise_;
+ StkFloat baseFrequency_;
+ StkFloat loopGain_;
+
+};
+
+inline StkFloat Simple :: tick( unsigned int )
+{
+ lastFrame_[0] = loopGain_ * loop_->tick();
+ biquad_.tick( noise_.tick() );
+ lastFrame_[0] += (1.0 - loopGain_) * biquad_.lastOut();
+ lastFrame_[0] = filter_.tick( lastFrame_[0] );
+ lastFrame_[0] *= adsr_.tick();
+ return lastFrame_[0];
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_SINEWAVE_H
+#define STK_SINEWAVE_H
+
+const unsigned long TABLE_SIZE = 2048;
+
+#include "Generator.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class SineWave
+ \brief STK sinusoid oscillator class.
+
+ This class computes and saves a static sine "table" that can be
+ shared by multiple instances. It has an interface similar to the
+ WaveLoop class but inherits from the Generator class. Output
+ values are computed using linear interpolation.
+
+ The "table" length, set in SineWave.h, is 2048 samples by default.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
+*/
+/***************************************************/
+
+class SineWave : public Generator
+{
+public:
+ //! Default constructor.
+ SineWave( void );
+
+ //! Class destructor.
+ ~SineWave( void );
+
+ //! Clear output and reset time pointer to zero.
+ void reset( void );
+
+ //! Set the data read rate in samples. The rate can be negative.
+ /*!
+ If the rate value is negative, the data is read in reverse order.
+ */
+ void setRate( StkFloat rate ) { rate_ = rate; };
+
+ //! Set the data interpolation rate based on a looping frequency.
+ /*!
+ This function determines the interpolation rate based on the file
+ size and the current Stk::sampleRate. The \e frequency value
+ corresponds to file cycles per second. The frequency can be
+ negative, in which case the loop is read in reverse order.
+ */
+ void setFrequency( StkFloat frequency );
+
+ //! Increment the read pointer by \e time in samples, modulo the table size.
+ void addTime( StkFloat time );
+
+ //! Increment the read pointer by a normalized \e phase value.
+ /*!
+ This function increments the read pointer by a normalized phase
+ value, such that \e phase = 1.0 corresponds to a 360 degree phase
+ shift. Positive or negative values are possible.
+ */
+ void addPhase( StkFloat phase );
+
+ //! Add a normalized phase offset to the read pointer.
+ /*!
+ A \e phaseOffset = 1.0 corresponds to a 360 degree phase
+ offset. Positive or negative values are possible.
+ */
+ void addPhaseOffset( StkFloat phaseOffset );
+
+ //! Return the last computed output value.
+ StkFloat lastOut( void ) const { return lastFrame_[0]; };
+
+ //! Compute and return one output sample.
+ StkFloat tick( void );
+
+ //! Fill a channel of the StkFrames object with computed outputs.
+ /*!
+ The \c channel argument must be less than the number of
+ channels in the StkFrames argument (the first channel is specified
+ by 0). However, range checking is only performed if _STK_DEBUG_
+ is defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
+
+protected:
+
+ void sampleRateChanged( StkFloat newRate, StkFloat oldRate );
+
+ static StkFrames table_;
+ StkFloat time_;
+ StkFloat rate_;
+ StkFloat phaseOffset_;
+ unsigned int iIndex_;
+ StkFloat alpha_;
+
+};
+
+inline StkFloat SineWave :: tick( void )
+{
+ // Check limits of time address ... if necessary, recalculate modulo
+ // TABLE_SIZE.
+ while ( time_ < 0.0 )
+ time_ += TABLE_SIZE;
+ while ( time_ >= TABLE_SIZE )
+ time_ -= TABLE_SIZE;
+
+ iIndex_ = (unsigned int) time_;
+ alpha_ = time_ - iIndex_;
+ StkFloat tmp = table_[ iIndex_ ];
+ tmp += ( alpha_ * ( table_[ iIndex_ + 1 ] - tmp ) );
+
+ // Increment time, which can be negative.
+ time_ += rate_;
+
+ lastFrame_[0] = tmp;
+ return lastFrame_[0];
+}
+
+inline StkFrames& SineWave :: tick( StkFrames& frames, unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel >= frames.channels() ) {
+ errorString_ << "SineWave::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *samples = &frames[channel];
+ StkFloat tmp = 0.0;
+
+ unsigned int hop = frames.channels();
+ for ( unsigned int i=0; i<frames.frames(); i++, samples += hop ) {
+
+ // Check limits of time address ... if necessary, recalculate modulo
+ // TABLE_SIZE.
+ while ( time_ < 0.0 )
+ time_ += TABLE_SIZE;
+ while ( time_ >= TABLE_SIZE )
+ time_ -= TABLE_SIZE;
+
+ iIndex_ = (unsigned int) time_;
+ alpha_ = time_ - iIndex_;
+ tmp = table_[ iIndex_ ];
+ tmp += ( alpha_ * ( table_[ iIndex_ + 1 ] - tmp ) );
+ *samples = tmp;
+
+ // Increment time, which can be negative.
+ time_ += rate_;
+ }
+
+ lastFrame_[0] = tmp;
+ return frames;
+}
+
+} // stk namespace
+
+#endif
+
--- /dev/null
+#ifndef STK_SINGWAVE_H
+#define STK_SINGWAVE_H
+
+#include "FileLoop.h"
+#include "Modulate.h"
+#include "Envelope.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class SingWave
+ \brief STK "singing" looped soundfile class.
+
+ This class loops a specified soundfile and modulates it both
+ periodically and randomly to produce a pitched musical sound, like
+ a simple voice or violin. In general, it is not be used alone
+ because of "munchkinification" effects from pitch shifting.
+ Within STK, it is used as an excitation source for other
+ instruments.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class SingWave : public Generator
+{
+ public:
+ //! Class constructor taking filename argument.
+ /*!
+ An StkError will be thrown if the file is not found, its format
+ is unknown, or a read error occurs. If the soundfile has no
+ header, the second argument should be \e true and the file data
+ will be assumed to consist of 16-bit signed integers in big-endian
+ byte order at a sample rate of 22050 Hz.
+ */
+ SingWave( std::string fileName, bool raw = false );
+
+ //! Class destructor.
+ ~SingWave( void );
+
+ //! Reset file to beginning.
+ void reset( void ) { wave_.reset(); lastFrame_[0] = 0.0; };
+
+ //! Normalize the file to a maximum of +-1.0.
+ void normalize( void ) { wave_.normalize(); };
+
+ //! Normalize the file to a maximum of \e +- peak.
+ void normalize( StkFloat peak ) { wave_.normalize( peak ); };
+
+ //! Set looping parameters for a particular frequency.
+ void setFrequency( StkFloat frequency );
+
+ //! Set the vibrato frequency in Hz.
+ void setVibratoRate( StkFloat rate ) { modulator_.setVibratoRate( rate ); };
+
+ //! Set the vibrato gain.
+ void setVibratoGain( StkFloat gain ) { modulator_.setVibratoGain( gain ); };
+
+ //! Set the random-ness amount.
+ void setRandomGain( StkFloat gain ) { modulator_.setRandomGain( gain ); };
+
+ //! Set the sweep rate.
+ void setSweepRate( StkFloat rate ) { sweepRate_ = rate; };
+
+ //! Set the gain rate.
+ void setGainRate( StkFloat rate ) { envelope_.setRate( rate ); };
+
+ //! Set the gain target value.
+ void setGainTarget( StkFloat target ) { envelope_.setTarget( target ); };
+
+ //! Start a note.
+ void noteOn( void ) { envelope_.keyOn(); };
+
+ //! Stop a note.
+ void noteOff( void ) { envelope_.keyOff(); };
+
+ //! Return the last computed output value.
+ StkFloat lastOut( void ) const { return lastFrame_[0]; };
+
+ //! Compute and return one output sample.
+ StkFloat tick( void );
+
+ //! Fill a channel of the StkFrames object with computed outputs.
+ /*!
+ The \c channel argument must be less than the number of
+ channels in the StkFrames argument (the first channel is specified
+ by 0). However, range checking is only performed if _STK_DEBUG_
+ is defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
+
+ protected:
+
+ FileLoop wave_;
+ Modulate modulator_;
+ Envelope envelope_;
+ Envelope pitchEnvelope_;
+ StkFloat rate_;
+ StkFloat sweepRate_;
+
+};
+
+inline StkFloat SingWave :: tick( void )
+{
+ // Set the wave rate.
+ StkFloat newRate = pitchEnvelope_.tick();
+ newRate += newRate * modulator_.tick();
+ wave_.setRate( newRate );
+
+ lastFrame_[0] = wave_.tick();
+ lastFrame_[0] *= envelope_.tick();
+
+ return lastFrame_[0];
+}
+
+inline StkFrames& SingWave :: tick( StkFrames& frames, unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel >= frames.channels() ) {
+ errorString_ << "SingWave::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *samples = &frames[channel];
+ unsigned int hop = frames.channels();
+ for ( unsigned int i=0; i<frames.frames(); i++, samples += hop )
+ *samples = SingWave::tick();
+
+ return frames;
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_SITAR_H
+#define STK_SITAR_H
+
+#include "Instrmnt.h"
+#include "DelayA.h"
+#include "OneZero.h"
+#include "Noise.h"
+#include "ADSR.h"
+#include <cmath>
+
+namespace stk {
+
+/***************************************************/
+/*! \class Sitar
+ \brief STK sitar string model class.
+
+ This class implements a sitar plucked string
+ physical model based on the Karplus-Strong
+ algorithm.
+
+ This is a digital waveguide model, making its
+ use possibly subject to patents held by
+ Stanford University, Yamaha, and others.
+ There exist at least two patents, assigned to
+ Stanford, bearing the names of Karplus and/or
+ Strong.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class Sitar : public Instrmnt
+{
+ public:
+ //! Class constructor, taking the lowest desired playing frequency.
+ Sitar( StkFloat lowestFrequency = 20 );
+
+ //! Class destructor.
+ ~Sitar( void );
+
+ //! Reset and clear all internal state.
+ void clear( void );
+
+ //! Set instrument parameters for a particular frequency.
+ void setFrequency( StkFloat frequency );
+
+ //! Pluck the string with the given amplitude using the current frequency.
+ void pluck( StkFloat amplitude );
+
+ //! Start a note with the given frequency and amplitude.
+ void noteOn( StkFloat frequency, StkFloat amplitude );
+
+ //! Stop a note with the given amplitude (speed of decay).
+ void noteOff( StkFloat amplitude );
+
+ //! Compute and return one output sample.
+ StkFloat tick( unsigned int channel = 0 );
+
+ protected:
+
+ DelayA delayLine_;
+ OneZero loopFilter_;
+ Noise noise_;
+ ADSR envelope_;
+
+ StkFloat loopGain_;
+ StkFloat amGain_;
+ StkFloat delay_;
+ StkFloat targetDelay_;
+
+};
+
+inline StkFloat Sitar :: tick( unsigned int )
+{
+ if ( fabs(targetDelay_ - delay_) > 0.001 ) {
+ if ( targetDelay_ < delay_ )
+ delay_ *= 0.99999;
+ else
+ delay_ *= 1.00001;
+ delayLine_.setDelay( delay_ );
+ }
+
+ lastFrame_[0] = delayLine_.tick( loopFilter_.tick( delayLine_.lastOut() * loopGain_ ) +
+ (amGain_ * envelope_.tick() * noise_.tick()));
+
+ return lastFrame_[0];
+}
+
+} // stk namespace
+
+#endif
+
--- /dev/null
+#ifndef STK_SKINI_H
+#define STK_SKINI_H
+
+#include "Stk.h"
+#include <vector>
+#include <string>
+#include <fstream>
+
+namespace stk {
+
+/***************************************************/
+/*! \class Skini
+ \brief STK SKINI parsing class
+
+ This class parses SKINI formatted text
+ messages. It can be used to parse individual
+ messages or it can be passed an entire file.
+ The SKINI specification is Perry's and his
+ alone, but it's all text so it shouldn't be too
+ hard to figure out.
+
+ SKINI (Synthesis toolKit Instrument Network
+ Interface) is like MIDI, but allows for
+ floating-point control changes, note numbers,
+ etc. The following example causes a sharp
+ middle C to be played with a velocity of 111.132:
+
+ \code
+ noteOn 60.01 111.132
+ \endcode
+
+ \sa \ref skini
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class Skini : public Stk
+{
+ public:
+
+ //! A message structure to store and pass parsed SKINI messages.
+ struct Message {
+ long type; /*!< The message type, as defined in SKINI.msg. */
+ long channel; /*!< The message channel (not limited to 16!). */
+ StkFloat time; /*!< The message time stamp in seconds (delta or absolute). */
+ std::vector<StkFloat> floatValues; /*!< The message values read as floats (values are type-specific). */
+ std::vector<long> intValues; /*!< The message values read as ints (number and values are type-specific). */
+ std::string remainder; /*!< Any remaining message data, read as ascii text. */
+
+ // Default constructor.
+ Message()
+ :type(0), channel(0), time(0.0), floatValues(2), intValues(2) {}
+ };
+
+ //! Default constructor.
+ Skini();
+
+ //! Class destructor
+ ~Skini();
+
+ //! Set a SKINI formatted file for reading.
+ /*!
+ If the file is successfully opened, this function returns \e
+ true. Otherwise, \e false is returned.
+ */
+ bool setFile( std::string fileName );
+
+ //! Parse the next file message (if a file is loaded) and return the message type.
+ /*!
+ This function skips over lines in a file which cannot be
+ parsed. A type value equal to zero in the referenced message
+ structure (and the returned value) indicates the file end is
+ reached or no file is open for reading.
+ */
+ long nextMessage( Skini::Message& message );
+
+ //! Attempt to parse the given string and returning the message type.
+ /*!
+ A type value equal to zero in the referenced message structure
+ indicates an invalid message.
+ */
+ long parseString( std::string& line, Skini::Message& message );
+
+ //! Return the SKINI type string for the given type value.
+ static std::string whatsThisType(long type);
+
+ //! Return the SKINI controller string for the given controller number.
+ static std::string whatsThisController(long number);
+
+ protected:
+
+ void tokenize( const std::string& str, std::vector<std::string>& tokens, const std::string& delimiters );
+
+ std::ifstream file_;
+};
+
+static const double Midi2Pitch[129] = {
+8.18,8.66,9.18,9.72,10.30,10.91,11.56,12.25,
+12.98,13.75,14.57,15.43,16.35,17.32,18.35,19.45,
+20.60,21.83,23.12,24.50,25.96,27.50,29.14,30.87,
+32.70,34.65,36.71,38.89,41.20,43.65,46.25,49.00,
+51.91,55.00,58.27,61.74,65.41,69.30,73.42,77.78,
+82.41,87.31,92.50,98.00,103.83,110.00,116.54,123.47,
+130.81,138.59,146.83,155.56,164.81,174.61,185.00,196.00,
+207.65,220.00,233.08,246.94,261.63,277.18,293.66,311.13,
+329.63,349.23,369.99,392.00,415.30,440.00,466.16,493.88,
+523.25,554.37,587.33,622.25,659.26,698.46,739.99,783.99,
+830.61,880.00,932.33,987.77,1046.50,1108.73,1174.66,1244.51,
+1318.51,1396.91,1479.98,1567.98,1661.22,1760.00,1864.66,1975.53,
+2093.00,2217.46,2349.32,2489.02,2637.02,2793.83,2959.96,3135.96,
+3322.44,3520.00,3729.31,3951.07,4186.01,4434.92,4698.64,4978.03,
+5274.04,5587.65,5919.91,6271.93,6644.88,7040.00,7458.62,7902.13,
+8372.02,8869.84,9397.27,9956.06,10548.08,11175.30,11839.82,12543.85,
+13289.75};
+
+} // stk namespace
+
+#endif
+
+
--- /dev/null
+#ifndef STK_SKINI_MSG_H
+#define STK_SKINI_MSG_H
+
+// MoMu Modified
+
+/*********************************************************/
+/*
+ Definition of SKINI Message Types and Special Symbols
+ Synthesis toolKit Instrument Network Interface
+
+ These symbols should have the form:
+
+ \c __SK_<name>_
+
+ where <name> is the string used in the SKINI stream.
+
+ by Perry R. Cook, 1995 - 2009.
+*/
+/*********************************************************/
+
+namespace stk {
+
+#define NOPE -32767
+#define YEP 1
+#define SK_DBL -32766
+#define SK_INT -32765
+#define SK_STR -32764
+#define __SK_Exit_ 999
+
+/***** MIDI COMPATIBLE MESSAGES *****/
+/*** (Status bytes for channel=0) ***/
+
+#define __SK_NoteOff_ 128
+#define __SK_NoteOn_ 144
+#define __SK_PolyPressure_ 160
+#define __SK_ControlChange_ 176
+#define __SK_ProgramChange_ 192
+#define __SK_AfterTouch_ 208
+#define __SK_ChannelPressure_ __SK_AfterTouch_
+#define __SK_PitchWheel_ 224
+#define __SK_PitchBend_ __SK_PitchWheel_
+#define __SK_PitchChange_ 49
+
+#define __SK_Clock_ 248
+#define __SK_SongStart_ 250
+#define __SK_Continue_ 251
+#define __SK_SongStop_ 252
+#define __SK_ActiveSensing_ 254
+#define __SK_SystemReset_ 255
+
+#define __SK_Volume_ 7
+#define __SK_ModWheel_ 1
+#define __SK_Modulation_ __SK_ModWheel_
+#define __SK_Breath_ 2
+#define __SK_FootControl_ 4
+#define __SK_Portamento_ 65
+#define __SK_Balance_ 8
+#define __SK_Pan_ 10
+#define __SK_Sustain_ 64
+#define __SK_Damper_ __SK_Sustain_
+#define __SK_Expression_ 11
+
+#define __SK_AfterTouch_Cont_ 128
+#define __SK_ModFrequency_ __SK_Expression_
+
+#define __SK_ProphesyRibbon_ 16
+#define __SK_ProphesyWheelUp_ 2
+#define __SK_ProphesyWheelDown_ 3
+#define __SK_ProphesyPedal_ 18
+#define __SK_ProphesyKnob1_ 21
+#define __SK_ProphesyKnob2_ 22
+
+/*** Instrument Family Specific ***/
+
+#define __SK_NoiseLevel_ __SK_FootControl_
+
+#define __SK_PickPosition_ __SK_FootControl_
+#define __SK_StringDamping_ __SK_Expression_
+#define __SK_StringDetune_ __SK_ModWheel_
+#define __SK_BodySize_ __SK_Breath_
+#define __SK_BowPressure_ __SK_Breath_
+#define __SK_BowPosition_ __SK_PickPosition_
+#define __SK_BowBeta_ __SK_BowPosition_
+
+#define __SK_ReedStiffness_ __SK_Breath_
+#define __SK_ReedRestPos_ __SK_FootControl_
+
+#define __SK_FluteEmbouchure_ __SK_Breath_
+#define __SK_JetDelay_ __SK_FluteEmbouchure_
+
+#define __SK_LipTension_ __SK_Breath_
+#define __SK_SlideLength_ __SK_FootControl_
+
+#define __SK_StrikePosition_ __SK_PickPosition_
+#define __SK_StickHardness_ __SK_Breath_
+
+#define __SK_TrillDepth_ 1051
+#define __SK_TrillSpeed_ 1052
+#define __SK_StrumSpeed_ __SK_TrillSpeed_
+#define __SK_RollSpeed_ __SK_TrillSpeed_
+
+#define __SK_FilterQ_ __SK_Breath_
+#define __SK_FilterFreq_ 1062
+#define __SK_FilterSweepRate_ __SK_FootControl_
+
+#define __SK_ShakerInst_ 1071
+#define __SK_ShakerEnergy_ __SK_Breath_
+#define __SK_ShakerDamping_ __SK_ModFrequency_
+#define __SK_ShakerNumObjects_ __SK_FootControl_
+
+#define __SK_Strumming_ 1090
+#define __SK_NotStrumming_ 1091
+#define __SK_Trilling_ 1092
+#define __SK_NotTrilling_ 1093
+#define __SK_Rolling_ __SK_Strumming_
+#define __SK_NotRolling_ __SK_NotStrumming_
+
+#define __SK_PlayerSkill_ 2001
+#define __SK_Chord_ 2002
+#define __SK_ChordOff_ 2003
+
+#define __SK_SINGER_FilePath_ 3000
+#define __SK_SINGER_Frequency_ 3001
+#define __SK_SINGER_NoteName_ 3002
+#define __SK_SINGER_Shape_ 3003
+#define __SK_SINGER_Glot_ 3004
+#define __SK_SINGER_VoicedUnVoiced_ 3005
+#define __SK_SINGER_Synthesize_ 3006
+#define __SK_SINGER_Silence_ 3007
+#define __SK_SINGER_VibratoAmt_ __SK_ModWheel_
+#define __SK_SINGER_RndVibAmt_ 3008
+#define __SK_SINGER_VibFreq_ __SK_Expression_
+
+} // stk namespace
+
+
+#endif
\ No newline at end of file
--- /dev/null
+#include "Skini_msg.h"
+
+// MoMu Modified
+
+namespace stk {
+
+#define __SK_MaxMsgTypes_ 80
+
+struct SkiniSpec { char messageString[32];
+ long type;
+ long data2;
+ long data3;
+ };
+
+/* SEE COMMENT BLOCK AT BOTTOM FOR FIELDS AND USES */
+/* MessageString , type, data2, data3 */
+
+struct SkiniSpec skini_msgs[__SK_MaxMsgTypes_] =
+{
+ {"NoteOff" , __SK_NoteOff_, SK_DBL, SK_DBL},
+ {"NoteOn" , __SK_NoteOn_, SK_DBL, SK_DBL},
+ {"PolyPressure" , __SK_PolyPressure_, SK_DBL, SK_DBL},
+ {"ControlChange" , __SK_ControlChange_, SK_INT, SK_DBL},
+ {"ProgramChange" , __SK_ProgramChange_, SK_DBL, NOPE},
+ {"AfterTouch" , __SK_AfterTouch_, SK_DBL, NOPE},
+ {"ChannelPressure" ,__SK_ChannelPressure_, SK_DBL, NOPE},
+ {"PitchWheel" , __SK_PitchWheel_, SK_DBL, NOPE},
+ {"PitchBend" , __SK_PitchBend_, SK_DBL, NOPE},
+ {"PitchChange" , __SK_PitchChange_, SK_DBL, NOPE},
+
+ {"Clock" , __SK_Clock_, NOPE, NOPE},
+ {"Undefined" , 249, NOPE, NOPE},
+ {"SongStart" , __SK_SongStart_, NOPE, NOPE},
+ {"Continue" , __SK_Continue_, NOPE, NOPE},
+ {"SongStop" , __SK_SongStop_, NOPE, NOPE},
+ {"Undefined" , 253, NOPE, NOPE},
+ {"ActiveSensing" , __SK_ActiveSensing_, NOPE, NOPE},
+ {"SystemReset" , __SK_SystemReset_, NOPE, NOPE},
+
+ {"Volume" , __SK_ControlChange_, __SK_Volume_ , SK_DBL},
+ {"ModWheel" , __SK_ControlChange_, __SK_ModWheel_ , SK_DBL},
+ {"Modulation" , __SK_ControlChange_, __SK_Modulation_ , SK_DBL},
+ {"Breath" , __SK_ControlChange_, __SK_Breath_ , SK_DBL},
+ {"FootControl" , __SK_ControlChange_, __SK_FootControl_ , SK_DBL},
+ {"Portamento" , __SK_ControlChange_, __SK_Portamento_ , SK_DBL},
+ {"Balance" , __SK_ControlChange_, __SK_Balance_ , SK_DBL},
+ {"Pan" , __SK_ControlChange_, __SK_Pan_ , SK_DBL},
+ {"Sustain" , __SK_ControlChange_, __SK_Sustain_ , SK_DBL},
+ {"Damper" , __SK_ControlChange_, __SK_Damper_ , SK_DBL},
+ {"Expression" , __SK_ControlChange_, __SK_Expression_ , SK_DBL},
+
+ {"NoiseLevel" , __SK_ControlChange_, __SK_NoiseLevel_ , SK_DBL},
+ {"PickPosition" , __SK_ControlChange_, __SK_PickPosition_ , SK_DBL},
+ {"StringDamping" , __SK_ControlChange_, __SK_StringDamping_ , SK_DBL},
+ {"StringDetune" , __SK_ControlChange_, __SK_StringDetune_ , SK_DBL},
+ {"BodySize" , __SK_ControlChange_, __SK_BodySize_ , SK_DBL},
+ {"BowPressure" , __SK_ControlChange_, __SK_BowPressure_ , SK_DBL},
+ {"BowPosition" , __SK_ControlChange_, __SK_BowPosition_ , SK_DBL},
+ {"BowBeta" , __SK_ControlChange_, __SK_BowBeta_ , SK_DBL},
+
+ {"ReedStiffness" , __SK_ControlChange_, __SK_ReedStiffness_ , SK_DBL},
+ {"ReedRestPos" , __SK_ControlChange_, __SK_ReedRestPos_ , SK_DBL},
+ {"FluteEmbouchure" , __SK_ControlChange_, __SK_FluteEmbouchure_ , SK_DBL},
+ {"LipTension" , __SK_ControlChange_, __SK_LipTension_ , SK_DBL},
+ {"StrikePosition" , __SK_ControlChange_, __SK_StrikePosition_ , SK_DBL},
+ {"StickHardness" , __SK_ControlChange_, __SK_StickHardness_ , SK_DBL},
+
+ {"TrillDepth" , __SK_ControlChange_, __SK_TrillDepth_ , SK_DBL},
+ {"TrillSpeed" , __SK_ControlChange_, __SK_TrillSpeed_ , SK_DBL},
+
+ {"Strumming" , __SK_ControlChange_, __SK_Strumming_ , 127 },
+ {"NotStrumming" , __SK_ControlChange_, __SK_Strumming_ , 0 },
+
+ {"PlayerSkill" , __SK_ControlChange_, __SK_PlayerSkill_ , SK_DBL},
+
+ {"Chord" , __SK_Chord_ , SK_DBL, SK_STR},
+ {"ChordOff" , __SK_ChordOff_ , SK_DBL, NOPE},
+
+ {"ShakerInst" , __SK_ControlChange_, __SK_ShakerInst_ , SK_DBL},
+ {"Maraca" , __SK_ControlChange_, __SK_ShakerInst_ , 0 },
+ {"Sekere" , __SK_ControlChange_, __SK_ShakerInst_ , 1 },
+ {"Cabasa" , __SK_ControlChange_, __SK_ShakerInst_ , 2 },
+ {"Bamboo" , __SK_ControlChange_, __SK_ShakerInst_ , 3 },
+ {"Waterdrp" , __SK_ControlChange_, __SK_ShakerInst_ , 4 },
+ {"Tambourn" , __SK_ControlChange_, __SK_ShakerInst_ , 5 },
+ {"Sleighbl" , __SK_ControlChange_, __SK_ShakerInst_ , 6 },
+ {"Guiro" , __SK_ControlChange_, __SK_ShakerInst_ , 7 },
+
+ {"OpenFile" , 256, SK_STR, NOPE},
+ {"SetPath" , 257, SK_STR, NOPE},
+
+ {"FilePath" , __SK_SINGER_FilePath_ , SK_STR, NOPE},
+ {"Frequency" , __SK_SINGER_Frequency_ , SK_STR, NOPE},
+ {"NoteName" , __SK_SINGER_NoteName_ , SK_STR, NOPE},
+ {"VocalShape" , __SK_SINGER_Shape_ , SK_STR, NOPE},
+ {"Glottis" , __SK_SINGER_Glot_ , SK_STR, NOPE},
+ {"VoicedUnVoiced" , __SK_SINGER_VoicedUnVoiced_, SK_DBL, SK_STR},
+ {"Synthesize" , __SK_SINGER_Synthesize_ , SK_STR, NOPE},
+ {"Silence" , __SK_SINGER_Silence_ , SK_STR, NOPE},
+ {"RndVibAmt" , __SK_SINGER_RndVibAmt_ , SK_STR, NOPE},
+ {"VibratoAmt" , __SK_ControlChange_ ,__SK_SINGER_VibratoAmt_,SK_DBL},
+ {"VibFreq" , __SK_ControlChange_ ,__SK_SINGER_VibFreq_ ,SK_DBL}
+};
+
+
+/** FORMAT: *************************************************************/
+/* */
+/* MessageStr$ , type, data2, data3, */
+/* */
+/* type is the message type sent back from the SKINI line parser. */
+/* data<n> is either */
+/* NOPE : field not used, specifically, there aren't going */
+/* to be any more fields on this line. So if there */
+/* is NOPE in data2, data3 won't even be checked */
+/* SK_INT : byte (actually scanned as 32 bit signed integer) */
+/* If it's a MIDI data field which is required to */
+/* be an integer, like a controller number, it's */
+/* 0-127. Otherwise, get creative with SK_INTs. */
+/* SK_DBL : double precision floating point. SKINI uses these */
+/* in the MIDI context for note numbers with micro */
+/* tuning, velocities, controller values, etc. */
+/* SK_STR : only valid in final field. This allows (nearly) */
+/* arbitrary message types to be supported by simply */
+/* scanning the string to EndOfLine and then passing */
+/* it to a more intelligent handler. For example, */
+/* MIDI SYSEX (system exclusive) messages of up to */
+/* 256 bytes can be read as space-delimited integers */
+/* into the SK_STR buffer. Longer bulk dumps, */
+/* soundfiles, etc. should be handled as a new */
+/* message type pointing to a FileName stored in the */
+/* SK_STR field, or as a new type of multi-line */
+/* message. */
+/* */
+/*************************************************************************/
+
+} // stk namespace
--- /dev/null
+#ifndef STK_SOCKET_H
+#define STK_SOCKET_H
+
+#include "Stk.h"
+
+#if (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__))
+
+ #include <sys/socket.h>
+ #include <sys/types.h>
+ #include <arpa/inet.h>
+ #include <netdb.h>
+ #include <unistd.h>
+ #include <fcntl.h>
+ #include <netinet/in.h>
+ #include <netinet/tcp.h>
+
+#elif defined(__OS_WINDOWS__)
+
+ #include <winsock.h>
+
+#endif
+
+namespace stk {
+
+/***************************************************/
+/*! \class Socket
+ \brief STK internet socket abstract base class.
+
+ This class provides common functionality for TCP and UDP internet
+ socket server and client subclasses. This class also provides a
+ number of static functions for use with external socket
+ descriptors.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class Socket : public Stk
+{
+ public:
+
+ enum ProtocolType {
+ PROTO_TCP,
+ PROTO_UDP
+ };
+
+ //! Class constructor
+ Socket();
+
+ //! Class destructor.
+ virtual ~Socket();
+
+ //! Close the socket.
+ static void close( int socket );
+
+ //! Return the socket descriptor.
+ int id( void ) const { return soket_; };
+
+ //! Return the socket port number.
+ int port( void ) const { return port_; };
+
+ //! Returns true if the socket descriptor is valid.
+ static bool isValid( int socket ) { return socket != -1; };
+
+ //! If enable = false, the socket is set to non-blocking mode. When first created, sockets are by default in blocking mode.
+ static void setBlocking( int socket, bool enable );
+
+ //! Write a buffer over the socket connection. Returns the number of bytes written or -1 if an error occurs.
+ virtual int writeBuffer(const void *buffer, long bufferSize, int flags = 0) = 0;
+
+ //! Read an input buffer, up to length \e bufferSize. Returns the number of bytes read or -1 if an error occurs.
+ virtual int readBuffer(void *buffer, long bufferSize, int flags = 0) = 0;
+
+ //! Write a buffer via the specified socket. Returns the number of bytes written or -1 if an error occurs.
+ static int writeBuffer(int socket, const void *buffer, long bufferSize, int flags );
+
+ //! Read a buffer via the specified socket. Returns the number of bytes read or -1 if an error occurs.
+ static int readBuffer(int socket, void *buffer, long bufferSize, int flags );
+
+ protected:
+
+ int soket_;
+ int port_;
+
+};
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_SPHERE_H
+#define STK_SPHERE_H
+
+#include "Stk.h"
+#include "Vector3D.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class Sphere
+ \brief STK sphere class.
+
+ This class implements a spherical ball with
+ radius, mass, position, and velocity parameters.
+
+ by Perry R. Cook, 1995 - 2010.
+*/
+/***************************************************/
+
+class Sphere : public Stk
+{
+public:
+ //! Constructor taking an initial radius value.
+ Sphere( StkFloat radius = 1.0 ) { radius_ = radius; mass_ = 1.0; };
+
+ //! Set the 3D center position of the sphere.
+ void setPosition( StkFloat x, StkFloat y, StkFloat z ) { position_.setXYZ(x, y, z); };
+
+ //! Set the 3D velocity of the sphere.
+ void setVelocity( StkFloat x, StkFloat y, StkFloat z ) { velocity_.setXYZ(x, y, z); };
+
+ //! Set the radius of the sphere.
+ void setRadius( StkFloat radius ) { radius_ = radius; };
+
+ //! Set the mass of the sphere.
+ void setMass( StkFloat mass ) { mass_ = mass; };
+
+ //! Get the current position of the sphere as a 3D vector.
+ Vector3D* getPosition( void ) { return &position_; };
+
+ //! Get the relative position of the given point to the sphere as a 3D vector.
+ Vector3D* getRelativePosition( Vector3D *position );
+
+ //! Set the velcoity of the sphere as a 3D vector.
+ StkFloat getVelocity( Vector3D* velocity );
+
+ //! Returns the distance from the sphere boundary to the given position (< 0 if inside).
+ StkFloat isInside( Vector3D *position );
+
+ //! Get the current sphere radius.
+ StkFloat getRadius( void ) { return radius_; };
+
+ //! Get the current sphere mass.
+ StkFloat getMass( void ) { return mass_; };
+
+ //! Increase the current sphere velocity by the given 3D components.
+ void addVelocity( StkFloat x, StkFloat y, StkFloat z );
+
+ //! Move the sphere for the given time increment.
+ void tick( StkFloat timeIncrement );
+
+private:
+ Vector3D position_;
+ Vector3D velocity_;
+ Vector3D workingVector_;
+ StkFloat radius_;
+ StkFloat mass_;
+};
+
+inline void Sphere::tick( StkFloat timeIncrement )
+{
+ position_.setX(position_.getX() + (timeIncrement * velocity_.getX()));
+ position_.setY(position_.getY() + (timeIncrement * velocity_.getY()));
+ position_.setZ(position_.getZ() + (timeIncrement * velocity_.getZ()));
+};
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_STIFKARP_H
+#define STK_STIFKARP_H
+
+#include "Instrmnt.h"
+#include "DelayL.h"
+#include "DelayA.h"
+#include "OneZero.h"
+#include "Noise.h"
+#include "BiQuad.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class StifKarp
+ \brief STK plucked stiff string instrument.
+
+ This class implements a simple plucked string
+ algorithm (Karplus Strong) with enhancements
+ (Jaffe-Smith, Smith, and others), including
+ string stiffness and pluck position controls.
+ The stiffness is modeled with allpass filters.
+
+ This is a digital waveguide model, making its
+ use possibly subject to patents held by
+ Stanford University, Yamaha, and others.
+
+ Control Change Numbers:
+ - Pickup Position = 4
+ - String Sustain = 11
+ - String Stretch = 1
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class StifKarp : public Instrmnt
+{
+ public:
+ //! Class constructor, taking the lowest desired playing frequency.
+ StifKarp( StkFloat lowestFrequency );
+
+ //! Class destructor.
+ ~StifKarp( void );
+
+ //! Reset and clear all internal state.
+ void clear( void );
+
+ //! Set instrument parameters for a particular frequency.
+ void setFrequency( StkFloat frequency );
+
+ //! Set the stretch "factor" of the string (0.0 - 1.0).
+ void setStretch( StkFloat stretch );
+
+ //! Set the pluck or "excitation" position along the string (0.0 - 1.0).
+ void setPickupPosition( StkFloat position );
+
+ //! Set the base loop gain.
+ /*!
+ The actual loop gain is set according to the frequency.
+ Because of high-frequency loop filter roll-off, higher
+ frequency settings have greater loop gains.
+ */
+ void setBaseLoopGain( StkFloat aGain );
+
+ //! Pluck the string with the given amplitude using the current frequency.
+ void pluck( StkFloat amplitude );
+
+ //! Start a note with the given frequency and amplitude.
+ void noteOn( StkFloat frequency, StkFloat amplitude );
+
+ //! Stop a note with the given amplitude (speed of decay).
+ void noteOff( StkFloat amplitude );
+
+ //! Perform the control change specified by \e number and \e value (0.0 - 128.0).
+ void controlChange( int number, StkFloat value );
+
+ //! Compute and return one output sample.
+ StkFloat tick( unsigned int channel = 0 );
+
+ protected:
+
+ DelayA delayLine_;
+ DelayL combDelay_;
+ OneZero filter_;
+ Noise noise_;
+ BiQuad biquad_[4];
+
+ unsigned long length_;
+ StkFloat loopGain_;
+ StkFloat baseLoopGain_;
+ StkFloat lastFrequency_;
+ StkFloat lastLength_;
+ StkFloat stretching_;
+ StkFloat pluckAmplitude_;
+ StkFloat pickupPosition_;
+
+};
+
+inline StkFloat StifKarp :: tick( unsigned int )
+{
+ StkFloat temp = delayLine_.lastOut() * loopGain_;
+
+ // Calculate allpass stretching.
+ for (int i=0; i<4; i++)
+ temp = biquad_[i].tick(temp);
+
+ // Moving average filter.
+ temp = filter_.tick(temp);
+
+ lastFrame_[0] = delayLine_.tick(temp);
+ lastFrame_[0] = lastFrame_[0] - combDelay_.tick( lastFrame_[0] );
+ return lastFrame_[0];
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_STK_H
+#define STK_STK_H
+
+#include <string>
+#include <iostream>
+#include <sstream>
+#include <vector>
+#include <cstdlib>
+
+/*! \namespace stk
+ \brief The STK namespace.
+
+ Most Stk classes are defined within the STK namespace. Exceptions
+ to this include the classes RtAudio, RtMidi, and RtError.
+*/
+namespace stk {
+
+/***************************************************/
+/*! \class Stk
+ \brief STK base class
+
+ Nearly all STK classes inherit from this class.
+ The global sample rate and rawwave path variables
+ can be queried and modified via Stk. In addition,
+ this class provides error handling and
+ byte-swapping functions.
+
+ The Synthesis ToolKit in C++ (STK) is a set of open source audio
+ signal processing and algorithmic synthesis classes written in the
+ C++ programming language. STK was designed to facilitate rapid
+ development of music synthesis and audio processing software, with
+ an emphasis on cross-platform functionality, realtime control,
+ ease of use, and educational example code. STK currently runs
+ with realtime support (audio and MIDI) on Linux, Macintosh OS X,
+ and Windows computer platforms. Generic, non-realtime support has
+ been tested under NeXTStep, Sun, and other platforms and should
+ work with any standard C++ compiler.
+
+ STK WWW site: http://ccrma.stanford.edu/software/stk/
+
+ The Synthesis ToolKit in C++ (STK)
+ Copyright (c) 1995-2010 Perry R. Cook and Gary P. Scavone
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation files
+ (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ Any person wishing to distribute modifications to the Software is
+ asked to send the modifications to the original developer so that
+ they can be incorporated into the canonical version. This is,
+ however, not a binding provision of this license.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+/***************************************************/
+
+//#define _STK_DEBUG_
+#define __OS_MACOSX__ // MoMu Modified
+
+#ifndef __APPLE__
+ #define __APPLE__
+#endif
+
+// Most data in STK is passed and calculated with the
+// following user-definable floating-point type. You
+// can change this to "float" if you prefer or perhaps
+// a "long double" in the future.
+typedef double StkFloat;
+
+//! STK error handling class.
+/*!
+ This is a fairly abstract exception handling class. There could
+ be sub-classes to take care of more specific error conditions ... or
+ not.
+*/
+class StkError
+{
+public:
+ enum Type {
+ STATUS,
+ WARNING,
+ DEBUG_WARNING,
+ MEMORY_ALLOCATION,
+ MEMORY_ACCESS,
+ FUNCTION_ARGUMENT,
+ FILE_NOT_FOUND,
+ FILE_UNKNOWN_FORMAT,
+ FILE_ERROR,
+ PROCESS_THREAD,
+ PROCESS_SOCKET,
+ PROCESS_SOCKET_IPADDR,
+ AUDIO_SYSTEM,
+ MIDI_SYSTEM,
+ UNSPECIFIED
+ };
+
+protected:
+ std::string message_;
+ Type type_;
+
+public:
+ //! The constructor.
+ StkError(const std::string& message, Type type = StkError::UNSPECIFIED)
+ : message_(message), type_(type) {}
+
+ //! The destructor.
+ virtual ~StkError(void) {};
+
+ //! Prints thrown error message to stderr.
+ virtual void printMessage(void) { std::cerr << '\n' << message_ << "\n\n"; }
+
+ //! Returns the thrown error message type.
+ virtual const Type& getType(void) { return type_; }
+
+ //! Returns the thrown error message string.
+ virtual const std::string& getMessage(void) { return message_; }
+
+ //! Returns the thrown error message as a C string.
+ virtual const char *getMessageCString(void) { return message_.c_str(); }
+};
+
+
+class Stk
+{
+public:
+
+ typedef unsigned long StkFormat;
+ static const StkFormat STK_SINT8; /*!< -128 to +127 */
+ static const StkFormat STK_SINT16; /*!< -32768 to +32767 */
+ static const StkFormat STK_SINT24; /*!< Upper 3 bytes of 32-bit signed integer. */
+ static const StkFormat STK_SINT32; /*!< -2147483648 to +2147483647. */
+ static const StkFormat STK_FLOAT32; /*!< Normalized between plus/minus 1.0. */
+ static const StkFormat STK_FLOAT64; /*!< Normalized between plus/minus 1.0. */
+
+ //! Static method that returns the current STK sample rate.
+ static StkFloat sampleRate( void ) { return srate_; }
+
+ //! Static method that sets the STK sample rate.
+ /*!
+ The sample rate set using this method is queried by all STK
+ classes that depend on its value. It is initialized to the
+ default SRATE set in Stk.h. Many STK classes use the sample rate
+ during instantiation. Therefore, if you wish to use a rate that
+ is different from the default rate, it is imperative that it be
+ set \e BEFORE STK objects are instantiated. A few classes that
+ make use of the global STK sample rate are automatically notified
+ when the rate changes so that internal class data can be
+ appropriately updated. However, this has not been fully
+ implemented. Specifically, classes that appropriately update
+ their own data when either a setFrequency() or noteOn() function
+ is called do not currently receive the automatic notification of
+ rate change. If the user wants a specific class instance to
+ ignore such notifications, perhaps in a multi-rate context, the
+ function Stk::ignoreSampleRateChange() should be called.
+ */
+ static void setSampleRate( StkFloat rate );
+
+ //! A function to enable/disable the automatic updating of class data when the STK sample rate changes.
+ /*!
+ This function allows the user to enable or disable class data
+ updates in response to global sample rate changes on a class by
+ class basis.
+ */
+ void ignoreSampleRateChange( bool ignore = true ) { ignoreSampleRateChange_ = ignore; };
+
+ //! Static method that returns the current rawwave path.
+ static std::string rawwavePath(void) { return rawwavepath_; }
+
+ //! Static method that sets the STK rawwave path.
+ static void setRawwavePath( std::string path );
+
+ //! Static method that byte-swaps a 16-bit data type.
+ static void swap16( unsigned char *ptr );
+
+ //! Static method that byte-swaps a 32-bit data type.
+ static void swap32( unsigned char *ptr );
+
+ //! Static method that byte-swaps a 64-bit data type.
+ static void swap64( unsigned char *ptr );
+
+ //! Static cross-platform method to sleep for a number of milliseconds.
+ static void sleep( unsigned long milliseconds );
+
+ //! Static function for error reporting and handling using c-strings.
+ static void handleError( const char *message, StkError::Type type );
+
+ //! Static function for error reporting and handling using c++ strings.
+ static void handleError( std::string message, StkError::Type type );
+
+ //! Toggle display of WARNING and STATUS messages.
+ static void showWarnings( bool status ) { showWarnings_ = status; }
+
+ //! Toggle display of error messages before throwing exceptions.
+ static void printErrors( bool status ) { printErrors_ = status; }
+
+private:
+ static StkFloat srate_;
+ static std::string rawwavepath_;
+ static bool showWarnings_;
+ static bool printErrors_;
+ static std::vector<Stk *> alertList_;
+
+protected:
+
+ std::ostringstream errorString_;
+ bool ignoreSampleRateChange_;
+
+ //! Default constructor.
+ Stk( void );
+
+ //! Class destructor.
+ virtual ~Stk( void );
+
+ //! This function should be implemented in subclasses that depend on the sample rate.
+ virtual void sampleRateChanged( StkFloat newRate, StkFloat oldRate );
+
+ //! Add class pointer to list for sample rate change notification.
+ void addSampleRateAlert( Stk *ptr );
+
+ //! Remove class pointer from list for sample rate change notification.
+ void removeSampleRateAlert( Stk *ptr );
+
+ //! Internal function for error reporting that assumes message in \c errorString_ variable.
+ void handleError( StkError::Type type );
+};
+
+
+/***************************************************/
+/*! \class StkFrames
+ \brief An STK class to handle vectorized audio data.
+
+ This class can hold single- or multi-channel audio data. The data
+ type is always StkFloat and the channel format is always
+ interleaved. In an effort to maintain efficiency, no
+ out-of-bounds checks are performed in this class unless
+ _STK_DEBUG_ is defined.
+
+ Internally, the data is stored in a one-dimensional C array. An
+ indexing operator is available to set and retrieve data values.
+ Alternately, one can use pointers to access the data, using the
+ index operator to get an address for a particular location in the
+ data:
+
+ StkFloat* ptr = &myStkFrames[0];
+
+ Possible future improvements in this class could include functions
+ to convert to and return other data types.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class StkFrames
+{
+public:
+
+ //! The default constructor initializes the frame data structure to size zero.
+ StkFrames( unsigned int nFrames = 0, unsigned int nChannels = 0 );
+
+ //! Overloaded constructor that initializes the frame data to the specified size with \c value.
+ StkFrames( const StkFloat& value, unsigned int nFrames, unsigned int nChannels );
+
+ //! The destructor.
+ ~StkFrames();
+
+ // A copy constructor.
+ StkFrames( const StkFrames& f );
+
+ // Assignment operator that returns a reference to self.
+ StkFrames& operator= ( const StkFrames& f );
+
+ //! Subscript operator that returns a reference to element \c n of self.
+ /*!
+ The result can be used as an lvalue. This reference is valid
+ until the resize function is called or the array is destroyed. The
+ index \c n must be between 0 and size less one. No range checking
+ is performed unless _STK_DEBUG_ is defined.
+ */
+ StkFloat& operator[] ( size_t n );
+
+ //! Subscript operator that returns the value at element \c n of self.
+ /*!
+ The index \c n must be between 0 and size less one. No range
+ checking is performed unless _STK_DEBUG_ is defined.
+ */
+ StkFloat operator[] ( size_t n ) const;
+
+ //! Assignment by sum operator into self.
+ /*!
+ The dimensions of the argument are expected to be the same as
+ self. No range checking is performed unless _STK_DEBUG_ is
+ defined.
+ */
+ void operator+= ( StkFrames& f );
+
+ //! Assignment by product operator into self.
+ /*!
+ The dimensions of the argument are expected to be the same as
+ self. No range checking is performed unless _STK_DEBUG_ is
+ defined.
+ */
+ void operator*= ( StkFrames& f );
+
+ //! Channel / frame subscript operator that returns a reference.
+ /*!
+ The result can be used as an lvalue. This reference is valid
+ until the resize function is called or the array is destroyed. The
+ \c frame index must be between 0 and frames() - 1. The \c channel
+ index must be between 0 and channels() - 1. No range checking is
+ performed unless _STK_DEBUG_ is defined.
+ */
+ StkFloat& operator() ( size_t frame, unsigned int channel );
+
+ //! Channel / frame subscript operator that returns a value.
+ /*!
+ The \c frame index must be between 0 and frames() - 1. The \c
+ channel index must be between 0 and channels() - 1. No range checking
+ is performed unless _STK_DEBUG_ is defined.
+ */
+ StkFloat operator() ( size_t frame, unsigned int channel ) const;
+
+ //! Return an interpolated value at the fractional frame index and channel.
+ /*!
+ This function performs linear interpolation. The \c frame
+ index must be between 0.0 and frames() - 1. The \c channel index
+ must be between 0 and channels() - 1. No range checking is
+ performed unless _STK_DEBUG_ is defined.
+ */
+ StkFloat interpolate( StkFloat frame, unsigned int channel = 0 ) const;
+
+ //! Returns the total number of audio samples represented by the object.
+ size_t size() const { return size_; };
+
+ //! Returns \e true if the object size is zero and \e false otherwise.
+ bool empty() const;
+
+ //! Resize self to represent the specified number of channels and frames.
+ /*!
+ Changes the size of self based on the number of frames and
+ channels. No element assignment is performed. No memory
+ deallocation occurs if the new size is smaller than the previous
+ size. Further, no new memory is allocated when the new size is
+ smaller or equal to a previously allocated size.
+ */
+ void resize( size_t nFrames, unsigned int nChannels = 1 );
+
+ //! Resize self to represent the specified number of channels and frames and perform element initialization.
+ /*!
+ Changes the size of self based on the number of frames and
+ channels, and assigns \c value to every element. No memory
+ deallocation occurs if the new size is smaller than the previous
+ size. Further, no new memory is allocated when the new size is
+ smaller or equal to a previously allocated size.
+ */
+ void resize( size_t nFrames, unsigned int nChannels, StkFloat value );
+
+ //! Return the number of channels represented by the data.
+ unsigned int channels( void ) const { return nChannels_; };
+
+ //! Return the number of sample frames represented by the data.
+ unsigned int frames( void ) const { return nFrames_; };
+
+ //! Set the sample rate associated with the StkFrames data.
+ /*!
+ By default, this value is set equal to the current STK sample
+ rate at the time of instantiation.
+ */
+ void setDataRate( StkFloat rate ) { dataRate_ = rate; };
+
+ //! Return the sample rate associated with the StkFrames data.
+ /*!
+ By default, this value is set equal to the current STK sample
+ rate at the time of instantiation.
+ */
+ StkFloat dataRate( void ) const { return dataRate_; };
+
+private:
+
+ StkFloat *data_;
+ StkFloat dataRate_;
+ size_t nFrames_;
+ unsigned int nChannels_;
+ size_t size_;
+ size_t bufferSize_;
+
+};
+
+inline bool StkFrames :: empty() const
+{
+ if ( size_ > 0 ) return false;
+ else return true;
+}
+
+inline StkFloat& StkFrames :: operator[] ( size_t n )
+{
+#if defined(_STK_DEBUG_)
+ if ( n >= size_ ) {
+ std::ostringstream error;
+ error << "StkFrames::operator[]: invalid index (" << n << ") value!";
+ Stk::handleError( error.str(), StkError::MEMORY_ACCESS );
+ }
+#endif
+
+ return data_[n];
+}
+
+inline StkFloat StkFrames :: operator[] ( size_t n ) const
+{
+#if defined(_STK_DEBUG_)
+ if ( n >= size_ ) {
+ std::ostringstream error;
+ error << "StkFrames::operator[]: invalid index (" << n << ") value!";
+ Stk::handleError( error.str(), StkError::MEMORY_ACCESS );
+ }
+#endif
+
+ return data_[n];
+}
+
+inline StkFloat& StkFrames :: operator() ( size_t frame, unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( frame >= nFrames_ || channel >= nChannels_ ) {
+ std::ostringstream error;
+ error << "StkFrames::operator(): invalid frame (" << frame << ") or channel (" << channel << ") value!";
+ Stk::handleError( error.str(), StkError::MEMORY_ACCESS );
+ }
+#endif
+
+ return data_[ frame * nChannels_ + channel ];
+}
+
+inline StkFloat StkFrames :: operator() ( size_t frame, unsigned int channel ) const
+{
+#if defined(_STK_DEBUG_)
+ if ( frame >= nFrames_ || channel >= nChannels_ ) {
+ std::ostringstream error;
+ error << "StkFrames::operator(): invalid frame (" << frame << ") or channel (" << channel << ") value!";
+ Stk::handleError( error.str(), StkError::MEMORY_ACCESS );
+ }
+#endif
+
+ return data_[ frame * nChannels_ + channel ];
+}
+
+inline void StkFrames :: operator+= ( StkFrames& f )
+{
+#if defined(_STK_DEBUG_)
+ if ( f.frames() != nFrames_ || f.channels() != nChannels_ ) {
+ std::ostringstream error;
+ error << "StkFrames::operator+=: frames argument must be of equal dimensions!";
+ Stk::handleError( error.str(), StkError::MEMORY_ACCESS );
+ }
+#endif
+
+ StkFloat *fptr = &f[0];
+ StkFloat *dptr = data_;
+ for ( unsigned int i=0; i<size_; i++ )
+ *dptr++ += *fptr++;
+}
+
+inline void StkFrames :: operator*= ( StkFrames& f )
+{
+#if defined(_STK_DEBUG_)
+ if ( f.frames() != nFrames_ || f.channels() != nChannels_ ) {
+ std::ostringstream error;
+ error << "StkFrames::operator*=: frames argument must be of equal dimensions!";
+ Stk::handleError( error.str(), StkError::MEMORY_ACCESS );
+ }
+#endif
+
+ StkFloat *fptr = &f[0];
+ StkFloat *dptr = data_;
+ for ( unsigned int i=0; i<size_; i++ )
+ *dptr++ *= *fptr++;
+}
+
+// Here are a few other useful typedefs.
+typedef unsigned short UINT16;
+typedef unsigned int UINT32;
+typedef signed short SINT16;
+typedef signed int SINT32;
+typedef float FLOAT32;
+typedef double FLOAT64;
+
+// The default sampling rate.
+const StkFloat SRATE = 44100.0;
+
+// The default real-time audio input and output buffer size. If
+// clicks are occuring in the input and/or output sound stream, a
+// larger buffer size may help. Larger buffer sizes, however, produce
+// more latency.
+const unsigned int RT_BUFFER_SIZE = 512;
+
+// The default rawwave path value is set with the preprocessor
+// definition RAWWAVE_PATH. This can be specified as an argument to
+// the configure script, in an integrated development environment, or
+// below. The global STK rawwave path variable can be dynamically set
+// with the Stk::setRawwavePath() function. This value is
+// concatenated to the beginning of all references to rawwave files in
+// the various STK core classes (ex. Clarinet.cpp). If you wish to
+// move the rawwaves directory to a different location in your file
+// system, you will need to set this path definition appropriately.
+
+//#if !defined(RAWWAVE_PATH)
+// #define RAWWAVE_PATH "" //MoMu Modified
+//#endif
+
+const StkFloat PI = 3.14159265358979;
+const StkFloat TWO_PI = 2 * PI;
+const StkFloat ONE_OVER_128 = 0.0078125;
+
+#if defined(__WINDOWS_DS__) || defined(__WINDOWS_ASIO__) || defined(__WINDOWS_MM__)
+ #define __OS_WINDOWS__
+ #define __STK_REALTIME__
+#elif defined(__LINUX_OSS__) || defined(__LINUX_ALSA__) || defined(__UNIX_JACK__)
+ #define __OS_LINUX__
+ #define __STK_REALTIME__
+#elif defined(__IRIX_AL__)
+ #define __OS_IRIX__
+#elif defined(__MACOSX_CORE__) || defined(__UNIX_JACK__)
+ #define __OS_MACOSX__
+ #define __STK_REALTIME__
+#endif
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_UDPSOCKET_H
+#define STK_UDPSOCKET_H
+
+#include "Socket.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class UdpSocket
+ \brief STK UDP socket server/client class.
+
+ This class provides a uniform cross-platform UDP socket
+ server/client interface. Methods are provided for reading or
+ writing data buffers. The constructor creates a UDP socket and
+ binds it to the specified port. Note that only one socket can be
+ bound to a given port on the same machine.
+
+ UDP sockets provide unreliable, connection-less service. Messages
+ can be lost, duplicated, or received out of order. That said,
+ data transmission tends to be faster than with TCP connections and
+ datagrams are not potentially combined by the underlying system.
+
+ The user is responsible for checking the values returned by the
+ read/write methods. Values less than or equal to zero indicate
+ the occurence of an error.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class StkUdpSocket : public Socket
+{
+ public:
+ //! Default constructor creates a local UDP socket on port 2006 (or the specified port number).
+ /*!
+ An StkError will be thrown if a socket error occurs during instantiation.
+ */
+ StkUdpSocket( int port = 2006 );
+
+ //! The class destructor closes the socket instance.
+ ~StkUdpSocket();
+
+ //! Set the address for subsequent outgoing data sent via the \e writeBuffer() function.
+ /*!
+ An StkError will be thrown if the host is unknown.
+ */
+ void setDestination( int port = 2006, std::string hostname = "localhost" );
+
+ //! Send a buffer to the address specified with the \e setDestination() function. Returns the number of bytes written or -1 if an error occurs.
+ /*!
+ This function will fail if the default address (set with \e setDestination()) is invalid or has not been specified.
+ */
+ int writeBuffer(const void *buffer, long bufferSize, int flags = 0);
+
+ //! Read an input buffer, up to length \e bufferSize. Returns the number of bytes read or -1 if an error occurs.
+ int readBuffer(void *buffer, long bufferSize, int flags = 0);
+
+ //! Write a buffer to the specified socket. Returns the number of bytes written or -1 if an error occurs.
+ int writeBufferTo(const void *buffer, long bufferSize, int port, std::string hostname = "localhost", int flags = 0 );
+
+ protected:
+
+ //! A protected function for use in writing a socket address structure.
+ /*!
+ An StkError will be thrown if the host is unknown.
+ */
+ void setAddress( struct sockaddr_in *address, int port = 2006, std::string hostname = "localhost" );
+
+ struct sockaddr_in address_;
+ bool validAddress_;
+
+};
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_TAPDELAY_H
+#define STK_TAPDELAY_H
+
+#include "Filter.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class TapDelay
+ \brief STK non-interpolating tapped delay line class.
+
+ This class implements a non-interpolating digital delay-line with
+ an arbitrary number of output "taps". If the maximum length and
+ tap delays are not specified during instantiation, a fixed maximum
+ length of 4095 and a single tap delay of zero is set.
+
+ A non-interpolating delay line is typically used in fixed
+ delay-length applications, such as for reverberation.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class TapDelay : public Filter
+{
+ public:
+
+ //! The default constructor creates a delay-line with maximum length of 4095 samples and a single tap at delay = 0.
+ /*!
+ An StkError will be thrown if any tap delay parameter is less
+ than zero, the maximum delay parameter is less than one, or any
+ tap delay parameter is greater than the maxDelay value.
+ */
+ TapDelay( std::vector<unsigned long> taps = std::vector<unsigned long>( 1, 0 ), unsigned long maxDelay = 4095 );
+
+ //! Class destructor.
+ ~TapDelay();
+
+ //! Set the maximum delay-line length.
+ /*!
+ This method should generally only be used during initial setup
+ of the delay line. If it is used between calls to the tick()
+ function, without a call to clear(), a signal discontinuity will
+ likely occur. If the current maximum length is greater than the
+ new length, no change will be made.
+ */
+ void setMaximumDelay( unsigned long delay );
+
+ //! Set the delay-line tap lengths.
+ /*!
+ The valid range for each tap length is from 0 to the maximum delay-line length.
+ */
+ void setTapDelays( std::vector<unsigned long> taps );
+
+ //! Return the current delay-line length.
+ std::vector<unsigned long> getTapDelays( void ) const { return delays_; };
+
+ //! Return the specified tap value of the last computed frame.
+ /*!
+ Use the lastFrame() function to get all tap values from the
+ last computed frame. The \c tap argument must be less than the
+ number of delayline taps (the first tap is specified by 0).
+ However, range checking is only performed if _STK_DEBUG_ is
+ defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFloat lastOut( unsigned int tap = 0 ) const;
+
+ //! Input one sample to the delayline and return outputs at all tap positions.
+ /*!
+ The StkFrames argument reference is returned. The output
+ values are ordered according to the tap positions set using the
+ setTapDelays() function (no sorting is performed). The StkFrames
+ argument must contain at least as many channels as the number of
+ taps. However, range checking is only performed if _STK_DEBUG_ is
+ defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFloat input, StkFrames& outputs );
+
+ //! Take a channel of the StkFrames object as inputs to the filter and write outputs back to the same object.
+ /*!
+ The StkFrames argument reference is returned. The output
+ values are ordered according to the tap positions set using the
+ setTapDelays() function (no sorting is performed). The StkFrames
+ argument must contain at least as many channels as the number of
+ taps. However, range checking is only performed if _STK_DEBUG_ is
+ defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
+
+ //! Take a channel of the \c iFrames object as inputs to the filter and write outputs to the \c oFrames object.
+ /*!
+ The \c iFrames object reference is returned. The output values
+ are ordered according to the tap positions set using the
+ setTapDelays() function (no sorting is performed). The \c
+ iChannel argument must be less than the number of channels in
+ the \c iFrames argument (the first channel is specified by 0).
+ The \c oFrames argument must contain at least as many channels as
+ the number of taps. However, range checking is only performed if
+ _STK_DEBUG_ is defined during compilation, in which case an
+ out-of-range value will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& iFrames, StkFrames &oFrames, unsigned int iChannel = 0 );
+
+ protected:
+
+ unsigned long inPoint_;
+ std::vector<unsigned long> outPoint_;
+ std::vector<unsigned long> delays_;
+
+};
+
+inline StkFloat TapDelay :: lastOut( unsigned int tap ) const
+{
+#if defined(_STK_DEBUG_)
+ if ( tap >= lastFrame_.size() ) ) {
+ errorString_ << "TapDelay::lastOut(): tap argument and number of taps are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ return lastFrame_[tap];
+}
+
+inline StkFrames& TapDelay :: tick( StkFloat input, StkFrames& outputs )
+{
+#if defined(_STK_DEBUG_)
+ if ( outputs.channels() < outPoint_.size() ) {
+ errorString_ << "TapDelay::tick(): number of taps > channels in StkFrames argument!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ inputs_[inPoint_++] = input * gain_;
+
+ // Check for end condition
+ if ( inPoint_ == inputs_.size() )
+ inPoint_ = 0;
+
+ // Read out next values
+ StkFloat *outs = &outputs[0];
+ for ( unsigned int i=0; i<outPoint_.size(); i++ ) {
+ *outs++ = inputs_[outPoint_[i]];
+ lastFrame_[i] = *outs;
+ if ( ++outPoint_[i] == inputs_.size() )
+ outPoint_[i] = 0;
+ }
+
+ return outputs;
+}
+
+inline StkFrames& TapDelay :: tick( StkFrames& frames, unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel >= frames.channels() ) {
+ errorString_ << "TapDelay::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+ if ( frames.channels() < outPoint_.size() ) {
+ errorString_ << "TapDelay::tick(): number of taps > channels in StkFrames argument!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *iSamples = &frames[channel];
+ StkFloat *oSamples = &frames[0];
+ unsigned int j, iHop = frames.channels(), oHop = frames.channels() - outPoint_.size();
+ for ( unsigned int i=0; i<frames.frames(); i++, iSamples += iHop, oSamples += oHop ) {
+ inputs_[inPoint_++] = *iSamples * gain_;
+ if ( inPoint_ == inputs_.size() ) inPoint_ = 0;
+ for ( j=0; j<outPoint_.size(); j++ ) {
+ *oSamples++ = inputs_[outPoint_[j]];
+ if ( ++outPoint_[j] == inputs_.size() ) outPoint_[j] = 0;
+ }
+ }
+
+ oSamples -= frames.channels();
+ for ( j=0; j<outPoint_.size(); j++ ) lastFrame_[j] = *oSamples++;
+ return frames;
+}
+
+inline StkFrames& TapDelay :: tick( StkFrames& iFrames, StkFrames& oFrames, unsigned int iChannel )
+{
+#if defined(_STK_DEBUG_)
+ if ( iChannel >= iFrames.channels() ) {
+ errorString_ << "TapDelay::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+ if ( oFrames.channels() < outPoint_.size() ) {
+ errorString_ << "TapDelay::tick(): number of taps > channels in output StkFrames argument!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *iSamples = &iFrames[iChannel];
+ StkFloat *oSamples = &oFrames[0];
+ unsigned int j, iHop = iFrames.channels(), oHop = oFrames.channels() - outPoint_.size();
+ for ( unsigned int i=0; i<iFrames.frames(); i++, iSamples += iHop, oSamples += oHop ) {
+ inputs_[inPoint_++] = *iSamples * gain_;
+ if ( inPoint_ == inputs_.size() ) inPoint_ = 0;
+ for ( j=0; j<outPoint_.size(); j++ ) {
+ *oSamples++ = inputs_[outPoint_[j]];
+ if ( ++outPoint_[j] == inputs_.size() ) outPoint_[j] = 0;
+ }
+ }
+
+ oSamples -= oFrames.channels();
+ for ( j=0; j<outPoint_.size(); j++ ) lastFrame_[j] = *oSamples++;
+ return iFrames;
+}
+
+#endif
+
+} // stk namespace
--- /dev/null
+#ifndef STK_TCPCLIENT_H
+#define STK_TCPCLIENT_H
+
+#include "Socket.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class TcpClient
+ \brief STK TCP socket client class.
+
+ This class provides a uniform cross-platform TCP socket client
+ interface. Methods are provided for reading or writing data
+ buffers to/from connections.
+
+ TCP sockets are reliable and connection-oriented. A TCP socket
+ client must be connected to a TCP server before data can be sent
+ or received. Data delivery is guaranteed in order, without loss,
+ error, or duplication. That said, TCP transmissions tend to be
+ slower than those using the UDP protocol and data sent with
+ multiple \e write() calls can be arbitrarily combined by the
+ underlying system.
+
+ The user is responsible for checking the values
+ returned by the read/write methods. Values
+ less than or equal to zero indicate a closed
+ or lost connection or the occurence of an error.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class TcpClient : public Socket
+{
+ public:
+ //! Default class constructor creates a socket client connection to the specified host and port.
+ /*!
+ An StkError will be thrown if a socket error occurs during instantiation.
+ */
+ TcpClient( int port, std::string hostname = "localhost" );
+
+ //! The class destructor closes the socket instance, breaking any existing connections.
+ ~TcpClient();
+
+ //! Connect the socket client to the specified host and port and returns the resulting socket descriptor.
+ /*!
+ If the socket client is already connected, that connection is
+ terminated and a new connection is attempted. An StkError will be
+ thrown if a socket error occurs.
+ */
+ int connect( int port, std::string hostname = "localhost" );
+
+ //! Write a buffer over the socket connection. Returns the number of bytes written or -1 if an error occurs.
+ int writeBuffer(const void *buffer, long bufferSize, int flags = 0);
+
+ //! Read a buffer from the socket connection, up to length \e bufferSize. Returns the number of bytes read or -1 if an error occurs.
+ int readBuffer(void *buffer, long bufferSize, int flags = 0);
+
+ protected:
+
+};
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_TCPSERVER_H
+#define STK_TCPSERVER_H
+
+#include "Socket.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class TcpServer
+ \brief STK TCP socket server class.
+
+ This class provides a uniform cross-platform TCP socket server
+ interface. Methods are provided for reading or writing data
+ buffers to/from connections.
+
+ TCP sockets are reliable and connection-oriented. A TCP socket
+ server must accept a connection from a TCP client before data can
+ be sent or received. Data delivery is guaranteed in order,
+ without loss, error, or duplication. That said, TCP transmissions
+ tend to be slower than those using the UDP protocol and data sent
+ with multiple \e write() calls can be arbitrarily combined by the
+ underlying system.
+
+ The user is responsible for checking the values
+ returned by the read/write methods. Values
+ less than or equal to zero indicate a closed
+ or lost connection or the occurence of an error.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class TcpServer : public Socket
+{
+ public:
+ //! Default constructor creates a local socket server on port 2006 (or the specified port number).
+ /*!
+ An StkError will be thrown if a socket error occurs during instantiation.
+ */
+ TcpServer( int port = 2006 );
+
+ //! The class destructor closes the socket instance, breaking any existing connections.
+ ~TcpServer();
+
+ //! Extract the first pending connection request from the queue and create a new connection, returning the descriptor for the accepted socket.
+ /*!
+ If no connection requests are pending and the socket has not
+ been set non-blocking, this function will block until a connection
+ is present. If an error occurs, -1 is returned.
+ */
+ int accept( void );
+
+ //! Write a buffer over the socket connection. Returns the number of bytes written or -1 if an error occurs.
+ int writeBuffer(const void *buffer, long bufferSize, int flags = 0);
+
+ //! Read a buffer from the socket connection, up to length \e bufferSize. Returns the number of bytes read or -1 if an error occurs.
+ int readBuffer(void *buffer, long bufferSize, int flags = 0);
+
+ protected:
+
+};
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_THREAD_H
+#define STK_THREAD_H
+
+#include "Stk.h"
+
+#if (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__))
+
+ #include <pthread.h>
+ #define THREAD_TYPE
+ typedef pthread_t THREAD_HANDLE;
+ typedef void * THREAD_RETURN;
+ typedef void * (*THREAD_FUNCTION)(void *);
+
+#elif defined(__OS_WINDOWS__)
+
+ #include <windows.h>
+ #include <process.h>
+ #define THREAD_TYPE __stdcall
+ typedef unsigned long THREAD_HANDLE;
+ typedef unsigned THREAD_RETURN;
+ typedef unsigned (__stdcall *THREAD_FUNCTION)(void *);
+
+#endif
+
+namespace stk {
+
+/***************************************************/
+/*! \class Thread
+ \brief STK thread class.
+
+ This class provides a uniform interface for cross-platform
+ threads. On unix systems, the pthread library is used. Under
+ Windows, the C runtime threadex functions are used.
+
+ Each instance of the Thread class can be used to control a single
+ thread process. Routines are provided to signal cancelation
+ and/or joining with a thread, though it is not possible for this
+ class to know the running status of a thread once it is started.
+
+ For cross-platform compatability, thread functions should be
+ declared as follows:
+
+ THREAD_RETURN THREAD_TYPE thread_function(void *ptr)
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class Thread : public Stk
+{
+ public:
+ //! Default constructor.
+ Thread();
+
+ //! The class destructor does not attempt to cancel or join a thread.
+ ~Thread();
+
+ //! Begin execution of the thread \e routine. Upon success, true is returned.
+ /*!
+ A data pointer can be supplied to the thread routine via the
+ optional \e ptr argument. If the thread cannot be created, the
+ return value is false.
+ */
+ bool start( THREAD_FUNCTION routine, void * ptr = NULL );
+
+ //! Signal cancellation of a thread routine, returning \e true on success.
+ /*!
+ This function only signals thread cancellation. It does not
+ wait to verify actual routine termination. A \e true return value
+ only signifies that the cancellation signal was properly executed,
+ not thread cancellation. A thread routine may need to make use of
+ the testCancel() function to specify a cancellation point.
+ */
+ bool cancel(void);
+
+ //! Block the calling routine indefinitely until the thread terminates.
+ /*!
+ This function suspends execution of the calling routine until the thread has terminated. It will return immediately if the thread was already terminated. A \e true return value signifies successful termination. A \e false return value indicates a problem with the wait call.
+ */
+ bool wait(void);
+
+ //! Create a cancellation point within a thread routine.
+ /*!
+ This function call checks for thread cancellation, allowing the
+ thread to be terminated if a cancellation request was previously
+ signaled.
+ */
+ void testCancel(void);
+
+ protected:
+
+ THREAD_HANDLE thread_;
+
+};
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_TUBEBELL_H
+#define STK_TUBEBELL_H
+
+#include "FM.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class TubeBell
+ \brief STK tubular bell (orchestral chime) FM
+ synthesis instrument.
+
+ This class implements two simple FM Pairs
+ summed together, also referred to as algorithm
+ 5 of the TX81Z.
+
+ \code
+ Algorithm 5 is : 4->3--\
+ + --> Out
+ 2->1--/
+ \endcode
+
+ Control Change Numbers:
+ - Modulator Index One = 2
+ - Crossfade of Outputs = 4
+ - LFO Speed = 11
+ - LFO Depth = 1
+ - ADSR 2 & 4 Target = 128
+
+ The basic Chowning/Stanford FM patent expired
+ in 1995, but there exist follow-on patents,
+ mostly assigned to Yamaha. If you are of the
+ type who should worry about this (making
+ money) worry away.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class TubeBell : public FM
+{
+ public:
+ //! Class constructor.
+ /*!
+ An StkError will be thrown if the rawwave path is incorrectly set.
+ */
+ TubeBell( void );
+
+ //! Class destructor.
+ ~TubeBell( void );
+
+ //! Start a note with the given frequency and amplitude.
+ void noteOn( StkFloat frequency, StkFloat amplitude );
+
+ //! Compute and return one output sample.
+ StkFloat tick( unsigned int channel = 0 );
+
+ protected:
+
+};
+
+inline StkFloat TubeBell :: tick( unsigned int )
+{
+ StkFloat temp, temp2;
+
+ temp = gains_[1] * adsr_[1]->tick() * waves_[1]->tick();
+ temp = temp * control1_;
+
+ waves_[0]->addPhaseOffset( temp );
+ waves_[3]->addPhaseOffset( twozero_.lastOut() );
+ temp = gains_[3] * adsr_[3]->tick() * waves_[3]->tick();
+ twozero_.tick( temp );
+
+ waves_[2]->addPhaseOffset( temp );
+ temp = ( 1.0 - (control2_ * 0.5)) * gains_[0] * adsr_[0]->tick() * waves_[0]->tick();
+ temp += control2_ * 0.5 * gains_[2] * adsr_[2]->tick() * waves_[2]->tick();
+
+ // Calculate amplitude modulation and apply it to output.
+ temp2 = vibrato_.tick() * modDepth_;
+ temp = temp * (1.0 + temp2);
+
+ lastFrame_[0] = temp * 0.5;
+ return lastFrame_[0];
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_TWOPOLE_H
+#define STK_TWOPOLE_H
+
+#include "Filter.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class TwoPole
+ \brief STK two-pole filter class.
+
+ This class implements a two-pole digital filter. A method is
+ provided for creating a resonance in the frequency response while
+ maintaining a nearly constant filter gain.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class TwoPole : public Filter
+{
+ public:
+
+ //! Default constructor creates a second-order pass-through filter.
+ TwoPole( void );
+
+ //! Class destructor.
+ ~TwoPole();
+
+ //! A function to enable/disable the automatic updating of class data when the STK sample rate changes.
+ void ignoreSampleRateChange( bool ignore = true ) { ignoreSampleRateChange_ = ignore; };
+
+ //! Set the b[0] coefficient value.
+ void setB0( StkFloat b0 ) { b_[0] = b0; };
+
+ //! Set the a[1] coefficient value.
+ void setA1( StkFloat a1 ) { a_[1] = a1; };
+
+ //! Set the a[2] coefficient value.
+ void setA2( StkFloat a2 ) { a_[2] = a2; };
+
+ //! Set all filter coefficients.
+ void setCoefficients( StkFloat b0, StkFloat a1, StkFloat a2, bool clearState = false );
+
+ //! Sets the filter coefficients for a resonance at \e frequency (in Hz).
+ /*!
+ This method determines the filter coefficients corresponding to
+ two complex-conjugate poles with the given \e frequency (in Hz)
+ and \e radius from the z-plane origin. If \e normalize is true,
+ the coefficients are then normalized to produce unity gain at \e
+ frequency (the actual maximum filter gain tends to be slightly
+ greater than unity when \e radius is not close to one). The
+ resulting filter frequency response has a resonance at the given
+ \e frequency. The closer the poles are to the unit-circle (\e
+ radius close to one), the narrower the resulting resonance width.
+ An unstable filter will result for \e radius >= 1.0. For a better
+ resonance filter, use a BiQuad filter. \sa BiQuad filter class
+ */
+ void setResonance(StkFloat frequency, StkFloat radius, bool normalize = false);
+
+ //! Return the last computed output value.
+ StkFloat lastOut( void ) const { return lastFrame_[0]; };
+
+ //! Input one sample to the filter and return one output.
+ StkFloat tick( StkFloat input );
+
+ //! Take a channel of the StkFrames object as inputs to the filter and replace with corresponding outputs.
+ /*!
+ The StkFrames argument reference is returned. The \c channel
+ argument must be less than the number of channels in the
+ StkFrames argument (the first channel is specified by 0).
+ However, range checking is only performed if _STK_DEBUG_ is
+ defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
+
+ //! Take a channel of the \c iFrames object as inputs to the filter and write outputs to the \c oFrames object.
+ /*!
+ The \c iFrames object reference is returned. Each channel
+ argument must be less than the number of channels in the
+ corresponding StkFrames argument (the first channel is specified
+ by 0). However, range checking is only performed if _STK_DEBUG_
+ is defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& iFrames, StkFrames &oFrames, unsigned int iChannel = 0, unsigned int oChannel = 0 );
+
+ protected:
+
+ virtual void sampleRateChanged( StkFloat newRate, StkFloat oldRate );
+};
+
+inline StkFloat TwoPole :: tick( StkFloat input )
+{
+ inputs_[0] = gain_ * input;
+ lastFrame_[0] = b_[0] * inputs_[0] - a_[1] * outputs_[1] - a_[2] * outputs_[2];
+ outputs_[2] = outputs_[1];
+ outputs_[1] = lastFrame_[0];
+
+ return lastFrame_[0];
+}
+
+inline StkFrames& TwoPole :: tick( StkFrames& frames, unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel >= frames.channels() ) {
+ errorString_ << "TwoPole::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *samples = &frames[channel];
+ unsigned int hop = frames.channels();
+ for ( unsigned int i=0; i<frames.frames(); i++, samples += hop ) {
+ inputs_[0] = gain_ * *samples;
+ *samples = b_[0] * inputs_[0] - a_[1] * outputs_[1] - a_[2] * outputs_[2];
+ outputs_[2] = outputs_[1];
+ outputs_[1] = *samples;
+ }
+
+ lastFrame_[0] = outputs_[1];
+ return frames;
+}
+
+inline StkFrames& TwoPole :: tick( StkFrames& iFrames, StkFrames& oFrames, unsigned int iChannel, unsigned int oChannel )
+{
+#if defined(_STK_DEBUG_)
+ if ( iChannel >= iFrames.channels() || oChannel >= oFrames.channels() ) {
+ errorString_ << "TwoPole::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *iSamples = &iFrames[iChannel];
+ StkFloat *oSamples = &oFrames[oChannel];
+ unsigned int iHop = iFrames.channels(), oHop = oFrames.channels();
+ for ( unsigned int i=0; i<iFrames.frames(); i++, iSamples += iHop, oSamples += oHop ) {
+ inputs_[0] = gain_ * *iSamples;
+ *oSamples = b_[0] * inputs_[0] - a_[1] * outputs_[1] - a_[2] * outputs_[2];
+ outputs_[2] = outputs_[1];
+ outputs_[1] = *oSamples;
+ }
+
+ lastFrame_[0] = outputs_[1];
+ return iFrames;
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_TWOZERO_H
+#define STK_TWOZERO_H
+
+#include "Filter.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class TwoZero
+ \brief STK two-zero filter class.
+
+ This class implements a two-zero digital filter. A method is
+ provided for creating a "notch" in the frequency response while
+ maintaining a constant filter gain.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class TwoZero : public Filter
+{
+ public:
+ //! Default constructor creates a second-order pass-through filter.
+ TwoZero();
+
+ //! Class destructor.
+ ~TwoZero();
+
+ //! A function to enable/disable the automatic updating of class data when the STK sample rate changes.
+ void ignoreSampleRateChange( bool ignore = true ) { ignoreSampleRateChange_ = ignore; };
+
+ //! Set the b[0] coefficient value.
+ void setB0( StkFloat b0 ) { b_[0] = b0; };
+
+ //! Set the b[1] coefficient value.
+ void setB1( StkFloat b1 ) { b_[1] = b1; };
+
+ //! Set the b[2] coefficient value.
+ void setB2( StkFloat b2 ) { b_[2] = b2; };
+
+ //! Set all filter coefficients.
+ void setCoefficients( StkFloat b0, StkFloat b1, StkFloat b2, bool clearState = false );
+
+ //! Sets the filter coefficients for a "notch" at \e frequency (in Hz).
+ /*!
+ This method determines the filter coefficients corresponding to
+ two complex-conjugate zeros with the given \e frequency (in Hz)
+ and \e radius from the z-plane origin. The coefficients are then
+ normalized to produce a maximum filter gain of one (independent of
+ the filter \e gain parameter). The resulting filter frequency
+ response has a "notch" or anti-resonance at the given \e
+ frequency. The closer the zeros are to the unit-circle (\e radius
+ close to or equal to one), the narrower the resulting notch width.
+ */
+ void setNotch( StkFloat frequency, StkFloat radius );
+
+ //! Return the last computed output value.
+ StkFloat lastOut( void ) const { return lastFrame_[0]; };
+
+ //! Input one sample to the filter and return one output.
+ StkFloat tick( StkFloat input );
+
+ //! Take a channel of the StkFrames object as inputs to the filter and replace with corresponding outputs.
+ /*!
+ The StkFrames argument reference is returned. The \c channel
+ argument must be less than the number of channels in the
+ StkFrames argument (the first channel is specified by 0).
+ However, range checking is only performed if _STK_DEBUG_ is
+ defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
+
+ //! Take a channel of the \c iFrames object as inputs to the filter and write outputs to the \c oFrames object.
+ /*!
+ The \c iFrames object reference is returned. Each channel
+ argument must be less than the number of channels in the
+ corresponding StkFrames argument (the first channel is specified
+ by 0). However, range checking is only performed if _STK_DEBUG_
+ is defined during compilation, in which case an out-of-range value
+ will trigger an StkError exception.
+ */
+ StkFrames& tick( StkFrames& iFrames, StkFrames &oFrames, unsigned int iChannel = 0, unsigned int oChannel = 0 );
+
+ protected:
+
+ void sampleRateChanged( StkFloat newRate, StkFloat oldRate );
+};
+
+inline StkFloat TwoZero :: tick( StkFloat input )
+{
+ inputs_[0] = gain_ * input;
+ lastFrame_[0] = b_[2] * inputs_[2] + b_[1] * inputs_[1] + b_[0] * inputs_[0];
+ inputs_[2] = inputs_[1];
+ inputs_[1] = inputs_[0];
+
+ return lastFrame_[0];
+}
+
+inline StkFrames& TwoZero :: tick( StkFrames& frames, unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel >= frames.channels() ) {
+ errorString_ << "TwoZero::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *samples = &frames[channel];
+ unsigned int hop = frames.channels();
+ for ( unsigned int i=0; i<frames.frames(); i++, samples += hop ) {
+ inputs_[0] = gain_ * *samples;
+ *samples = b_[2] * inputs_[2] + b_[1] * inputs_[1] + b_[0] * inputs_[0];
+ inputs_[2] = inputs_[1];
+ inputs_[1] = inputs_[0];
+ }
+
+ lastFrame_[0] = *(samples-hop);
+ return frames;
+}
+
+inline StkFrames& TwoZero :: tick( StkFrames& iFrames, StkFrames& oFrames, unsigned int iChannel, unsigned int oChannel )
+{
+#if defined(_STK_DEBUG_)
+ if ( iChannel >= iFrames.channels() || oChannel >= oFrames.channels() ) {
+ errorString_ << "TwoZero::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *iSamples = &iFrames[iChannel];
+ StkFloat *oSamples = &oFrames[oChannel];
+ unsigned int iHop = iFrames.channels(), oHop = oFrames.channels();
+ for ( unsigned int i=0; i<iFrames.frames(); i++, iSamples += iHop, oSamples += oHop ) {
+ inputs_[0] = gain_ * *iSamples;
+ *oSamples = b_[2] * inputs_[2] + b_[1] * inputs_[1] + b_[0] * inputs_[0];
+ inputs_[2] = inputs_[1];
+ inputs_[1] = inputs_[0];
+ }
+
+ lastFrame_[0] = *(oSamples-oHop);
+ return iFrames;
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_VECTOR3D_H
+#define STK_VECTOR3D_H
+
+#include "Stk.h"
+#include <cmath>
+
+namespace stk {
+
+/***************************************************/
+/*! \class Vector3D
+ \brief STK 3D vector class.
+
+ This class implements a three-dimensional vector.
+
+ by Perry R. Cook, 1995 - 2010.
+*/
+/***************************************************/
+
+class Vector3D : public Stk
+{
+
+public:
+ //! Default constructor taking optional initial X, Y, and Z values.
+ Vector3D( StkFloat x = 0.0, StkFloat y = 0.0, StkFloat z = 0.0 ) { setXYZ( x, y, z ); };
+
+ //! Get the current X value.
+ StkFloat getX( void ) { return X_; };
+
+ //! Get the current Y value.
+ StkFloat getY( void ) { return Y_; };
+
+ //! Get the current Z value.
+ StkFloat getZ( void ) { return Z_; };
+
+ //! Calculate the vector length.
+ StkFloat getLength( void );
+
+ //! Set the X, Y, and Z values simultaniously.
+ void setXYZ( StkFloat x, StkFloat y, StkFloat z ) { X_ = x; Y_ = y; Z_ = z; };
+
+ //! Set the X value.
+ void setX( StkFloat x ) { X_ = x; };
+
+ //! Set the Y value.
+ void setY( StkFloat y ) { Y_ = y; };
+
+ //! Set the Z value.
+ void setZ( StkFloat z ) { Z_ = z; };
+
+protected:
+ StkFloat X_;
+ StkFloat Y_;
+ StkFloat Z_;
+};
+
+inline StkFloat Vector3D :: getLength( void )
+{
+ StkFloat temp;
+ temp = X_ * X_;
+ temp += Y_ * Y_;
+ temp += Z_ * Z_;
+ temp = sqrt( temp );
+ return temp;
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_VOICFORM_H
+#define STK_VOICFORM_H
+
+#include "Instrmnt.h"
+#include "Envelope.h"
+#include "Noise.h"
+#include "SingWave.h"
+#include "FormSwep.h"
+#include "OnePole.h"
+#include "OneZero.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class VoicForm
+ \brief Four formant synthesis instrument.
+
+ This instrument contains an excitation singing
+ wavetable (looping wave with random and
+ periodic vibrato, smoothing on frequency,
+ etc.), excitation noise, and four sweepable
+ complex resonances.
+
+ Measured formant data is included, and enough
+ data is there to support either parallel or
+ cascade synthesis. In the floating point case
+ cascade synthesis is the most natural so
+ that's what you'll find here.
+
+ Control Change Numbers:
+ - Voiced/Unvoiced Mix = 2
+ - Vowel/Phoneme Selection = 4
+ - Vibrato Frequency = 11
+ - Vibrato Gain = 1
+ - Loudness (Spectral Tilt) = 128
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class VoicForm : public Instrmnt
+{
+ public:
+ //! Class constructor.
+ /*!
+ An StkError will be thrown if the rawwave path is incorrectly set.
+ */
+ VoicForm( void );
+
+ //! Class destructor.
+ ~VoicForm( void );
+
+ //! Reset and clear all internal state.
+ void clear( void );
+
+ //! Set instrument parameters for a particular frequency.
+ void setFrequency( StkFloat frequency );
+
+ //! Set instrument parameters for the given phoneme. Returns false if phoneme not found.
+ bool setPhoneme( const char* phoneme );
+
+ //! Set the voiced component gain.
+ void setVoiced( StkFloat vGain ) { voiced_->setGainTarget(vGain); };
+
+ //! Set the unvoiced component gain.
+ void setUnVoiced( StkFloat nGain ) { noiseEnv_.setTarget(nGain); };
+
+ //! Set the sweep rate for a particular formant filter (0-3).
+ void setFilterSweepRate( unsigned int whichOne, StkFloat rate );
+
+ //! Set voiced component pitch sweep rate.
+ void setPitchSweepRate( StkFloat rate ) { voiced_->setSweepRate(rate); };
+
+ //! Start the voice.
+ void speak( void ) { voiced_->noteOn(); };
+
+ //! Stop the voice.
+ void quiet( void );
+
+ //! Start a note with the given frequency and amplitude.
+ void noteOn( StkFloat frequency, StkFloat amplitude );
+
+ //! Stop a note with the given amplitude (speed of decay).
+ void noteOff( StkFloat amplitude ) { this->quiet(); };
+
+ //! Perform the control change specified by \e number and \e value (0.0 - 128.0).
+ void controlChange( int number, StkFloat value );
+
+ //! Compute and return one output sample.
+ StkFloat tick( unsigned int channel = 0 );
+
+protected:
+
+ SingWave *voiced_;
+ Noise noise_;
+ Envelope noiseEnv_;
+ FormSwep filters_[4];
+ OnePole onepole_;
+ OneZero onezero_;
+
+};
+
+inline StkFloat VoicForm :: tick( unsigned int )
+{
+ StkFloat temp;
+ temp = onepole_.tick( onezero_.tick( voiced_->tick() ) );
+ temp += noiseEnv_.tick() * noise_.tick();
+ lastFrame_[0] = filters_[0].tick(temp);
+ lastFrame_[0] += filters_[1].tick(temp);
+ lastFrame_[0] += filters_[2].tick(temp);
+ lastFrame_[0] += filters_[3].tick(temp);
+ /*
+ temp += noiseEnv_.tick() * noise_.tick();
+ lastFrame_[0] = filters_[0].tick(temp);
+ lastFrame_[0] = filters_[1].tick(lastFrame_[0]);
+ lastFrame_[0] = filters_[2].tick(lastFrame_[0]);
+ lastFrame_[0] = filters_[3].tick(lastFrame_[0]);
+ */
+ return lastFrame_[0];
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_VOICER_H
+#define STK_VOICER_H
+
+#include "Instrmnt.h"
+#include <vector>
+
+namespace stk {
+
+/***************************************************/
+/*! \class Voicer
+ \brief STK voice manager class.
+
+ This class can be used to manage a group of STK instrument
+ classes. Individual voices can be controlled via unique note
+ tags. Instrument groups can be controlled by group number.
+
+ A previously constructed STK instrument class is linked with a
+ voice manager using the addInstrument() function. An optional
+ group number argument can be specified to the addInstrument()
+ function as well (default group = 0). The voice manager does not
+ delete any instrument instances ... it is the responsibility of
+ the user to allocate and deallocate all instruments.
+
+ The tick() function returns the mix of all sounding voices. Each
+ noteOn returns a unique tag (credits to the NeXT MusicKit), so you
+ can send control changes to specific voices within an ensemble.
+ Alternately, control changes can be sent to all voices in a given
+ group.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class Voicer : public Stk
+{
+ public:
+ //! Class constructor taking an optional note decay time (in seconds).
+ Voicer( StkFloat decayTime = 0.2 );
+
+ //! Add an instrument with an optional group number to the voice manager.
+ /*!
+ A set of instruments can be grouped by group number and
+ controlled via the functions that take a group number argument.
+ */
+ void addInstrument( Instrmnt *instrument, int group=0 );
+
+ //! Remove the given instrument pointer from the voice manager's control.
+ /*!
+ It is important that any instruments which are to be deleted by
+ the user while the voice manager is running be first removed from
+ the manager's control via this function!!
+ */
+ void removeInstrument( Instrmnt *instrument );
+
+ //! Initiate a noteOn event with the given note number and amplitude and return a unique note tag.
+ /*!
+ Send the noteOn message to the first available unused voice.
+ If all voices are sounding, the oldest voice is interrupted and
+ sent the noteOn message. If the optional group argument is
+ non-zero, only voices in that group are used. If no voices are
+ found for a specified non-zero group value, the function returns
+ -1. The amplitude value should be in the range 0.0 - 128.0.
+ */
+ long noteOn( StkFloat noteNumber, StkFloat amplitude, int group=0 );
+
+ //! Send a noteOff to all voices having the given noteNumber and optional group (default group = 0).
+ /*!
+ The amplitude value should be in the range 0.0 - 128.0.
+ */
+ void noteOff( StkFloat noteNumber, StkFloat amplitude, int group=0 );
+
+ //! Send a noteOff to the voice with the given note tag.
+ /*!
+ The amplitude value should be in the range 0.0 - 128.0.
+ */
+ void noteOff( long tag, StkFloat amplitude );
+
+ //! Send a frequency update message to all voices assigned to the optional group argument (default group = 0).
+ /*!
+ The \e noteNumber argument corresponds to a MIDI note number, though it is a floating-point value and can range beyond the normal 0-127 range.
+ */
+ void setFrequency( StkFloat noteNumber, int group=0 );
+
+ //! Send a frequency update message to the voice with the given note tag.
+ /*!
+ The \e noteNumber argument corresponds to a MIDI note number, though it is a floating-point value and can range beyond the normal 0-127 range.
+ */
+ void setFrequency( long tag, StkFloat noteNumber );
+
+ //! Send a pitchBend message to all voices assigned to the optional group argument (default group = 0).
+ void pitchBend( StkFloat value, int group=0 );
+
+ //! Send a pitchBend message to the voice with the given note tag.
+ void pitchBend( long tag, StkFloat value );
+
+ //! Send a controlChange to all instruments assigned to the optional group argument (default group = 0).
+ void controlChange( int number, StkFloat value, int group=0 );
+
+ //! Send a controlChange to the voice with the given note tag.
+ void controlChange( long tag, int number, StkFloat value );
+
+ //! Send a noteOff message to all existing voices.
+ void silence( void );
+
+ //! Return the current number of output channels.
+ unsigned int channelsOut( void ) const { return lastFrame_.channels(); };
+
+ //! Return an StkFrames reference to the last output sample frame.
+ const StkFrames& lastFrame( void ) const { return lastFrame_; };
+
+ //! Return the specified channel value of the last computed frame.
+ /*!
+ The \c channel argument must be less than the number of output
+ channels, which can be determined with the channelsOut() function
+ (the first channel is specified by 0). However, range checking is
+ only performed if _STK_DEBUG_ is defined during compilation, in
+ which case an out-of-range value will trigger an StkError
+ exception. \sa lastFrame()
+ */
+ StkFloat lastOut( unsigned int channel = 0 );
+
+ //! Mix one sample frame of all sounding voices and return the specified \c channel value.
+ /*!
+ The \c channel argument must be less than the number of output
+ channels, which can be determined with the channelsOut() function
+ (the first channel is specified by 0). However, range checking is
+ only performed if _STK_DEBUG_ is defined during compilation, in
+ which case an out-of-range value will trigger an StkError
+ exception.
+ */
+ StkFloat tick( unsigned int channel = 0 );
+
+ //! Fill the StkFrames argument with computed frames and return the same reference.
+ /*!
+ The number of channels in the StkFrames argument must equal
+ the number of channels in the file data. However, this is only
+ checked if _STK_DEBUG_ is defined during compilation, in which
+ case an incompatibility will trigger an StkError exception. If no
+ file data is loaded, the function does nothing (a warning will be
+ issued if _STK_DEBUG_ is defined during compilation).
+ */
+ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
+
+ protected:
+
+ struct Voice {
+ Instrmnt *instrument;
+ long tag;
+ StkFloat noteNumber;
+ StkFloat frequency;
+ int sounding;
+ int group;
+
+ // Default constructor.
+ Voice()
+ :instrument(0), tag(0), noteNumber(-1.0), frequency(0.0), sounding(0), group(0) {}
+ };
+
+ std::vector<Voice> voices_;
+ long tags_;
+ int muteTime_;
+ StkFrames lastFrame_;
+};
+
+inline StkFloat Voicer :: lastOut( unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel >= lastFrame_.channels() ) {
+ errorString_ << "Voicer::lastOut(): channel argument is invalid!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ return lastFrame_[channel];
+}
+
+
+inline StkFloat Voicer :: tick( unsigned int channel )
+{
+ unsigned int j;
+ for ( j=0; j<lastFrame_.channels(); j++ ) lastFrame_[j] = 0.0;
+ for ( unsigned int i=0; i<voices_.size(); i++ ) {
+ if ( voices_[i].sounding != 0 ) {
+ voices_[i].instrument->tick();
+ for ( j=0; j<voices_[i].instrument->channelsOut(); j++ ) lastFrame_[j] += voices_[i].instrument->lastOut( j );
+ }
+ if ( voices_[i].sounding < 0 )
+ voices_[i].sounding++;
+ if ( voices_[i].sounding == 0 )
+ voices_[i].noteNumber = -1;
+ }
+
+ return lastFrame_[channel];
+}
+
+inline StkFrames& Voicer :: tick( StkFrames& frames, unsigned int channel )
+{
+ unsigned int nChannels = lastFrame_.channels();
+#if defined(_STK_DEBUG_)
+ if ( channel > frames.channels() - nChannels ) {
+ errorString_ << "Voicer::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *samples = &frames[channel];
+ unsigned int j, hop = frames.channels() - nChannels;
+ for ( unsigned int i=0; i<frames.frames(); i++, samples += hop ) {
+ tick();
+ for ( j=0; j<nChannels; j++ )
+ *samples++ = lastFrame_[j];
+ }
+
+ return frames;
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_WHISTLE_H
+#define STK_WHISTLE_H
+
+#include "Instrmnt.h"
+#include "Sphere.h"
+#include "Vector3D.h"
+#include "Noise.h"
+#include "SineWave.h"
+#include "OnePole.h"
+#include "Envelope.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class Whistle
+ \brief STK police/referee whistle instrument class.
+
+ This class implements a hybrid physical/spectral
+ model of a police whistle (a la Cook).
+
+ Control Change Numbers:
+ - Noise Gain = 4
+ - Fipple Modulation Frequency = 11
+ - Fipple Modulation Gain = 1
+ - Blowing Frequency Modulation = 2
+ - Volume = 128
+
+ by Perry R. Cook 1996 - 2010.
+*/
+/***************************************************/
+
+class Whistle : public Instrmnt
+{
+public:
+ //! Class constructor.
+ /*!
+ An StkError will be thrown if the rawwave path is incorrectly set.
+ */
+ Whistle( void );
+
+ //! Class destructor.
+ ~Whistle( void );
+
+ //! Reset and clear all internal state.
+ void clear( void );
+
+ //! Set instrument parameters for a particular frequency.
+ void setFrequency( StkFloat frequency );
+
+ //! Apply breath velocity to instrument with given amplitude and rate of increase.
+ void startBlowing( StkFloat amplitude, StkFloat rate );
+
+ //! Decrease breath velocity with given rate of decrease.
+ void stopBlowing( StkFloat rate );
+
+ //! Start a note with the given frequency and amplitude.
+ void noteOn( StkFloat frequency, StkFloat amplitude );
+
+ //! Stop a note with the given amplitude (speed of decay).
+ void noteOff( StkFloat amplitude );
+
+ //! Perform the control change specified by \e number and \e value (0.0 - 128.0).
+ void controlChange( int number, StkFloat value );
+
+ //! Compute and return one output sample.
+ StkFloat tick( unsigned int channel = 0 );
+
+protected:
+
+ Vector3D *tempVectorP_;
+ Vector3D tempVector_;
+ OnePole onepole_;
+ Noise noise_;
+ Envelope envelope_;
+ Sphere can_; // Declare a Spherical "can".
+ Sphere pea_, bumper_; // One spherical "pea", and a spherical "bumper".
+
+ SineWave sine_;
+
+ StkFloat baseFrequency_;
+ StkFloat noiseGain_;
+ StkFloat fippleFreqMod_;
+ StkFloat fippleGainMod_;
+ StkFloat blowFreqMod_;
+ StkFloat tickSize_;
+ StkFloat canLoss_;
+ int subSample_, subSampCount_;
+};
+
+} // stk namespace
+#endif
--- /dev/null
+#ifndef STK_WURLEY_H
+#define STK_WURLEY_H
+
+#include "FM.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class Wurley
+ \brief STK Wurlitzer electric piano FM
+ synthesis instrument.
+
+ This class implements two simple FM Pairs
+ summed together, also referred to as algorithm
+ 5 of the TX81Z.
+
+ \code
+ Algorithm 5 is : 4->3--\
+ + --> Out
+ 2->1--/
+ \endcode
+
+ Control Change Numbers:
+ - Modulator Index One = 2
+ - Crossfade of Outputs = 4
+ - LFO Speed = 11
+ - LFO Depth = 1
+ - ADSR 2 & 4 Target = 128
+
+ The basic Chowning/Stanford FM patent expired
+ in 1995, but there exist follow-on patents,
+ mostly assigned to Yamaha. If you are of the
+ type who should worry about this (making
+ money) worry away.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class Wurley : public FM
+{
+ public:
+ //! Class constructor.
+ /*!
+ An StkError will be thrown if the rawwave path is incorrectly set.
+ */
+ Wurley( void );
+
+ //! Class destructor.
+ ~Wurley( void );
+
+ //! Set instrument parameters for a particular frequency.
+ void setFrequency( StkFloat frequency );
+
+ //! Start a note with the given frequency and amplitude.
+ void noteOn( StkFloat frequency, StkFloat amplitude );
+
+ //! Compute and return one output sample.
+ StkFloat tick( unsigned int channel = 0 );
+
+ protected:
+
+};
+
+inline StkFloat Wurley :: tick( unsigned int )
+{
+ StkFloat temp, temp2;
+
+ temp = gains_[1] * adsr_[1]->tick() * waves_[1]->tick();
+ temp = temp * control1_;
+
+ waves_[0]->addPhaseOffset( temp );
+ waves_[3]->addPhaseOffset( twozero_.lastOut() );
+ temp = gains_[3] * adsr_[3]->tick() * waves_[3]->tick();
+ twozero_.tick(temp);
+
+ waves_[2]->addPhaseOffset( temp );
+ temp = ( 1.0 - (control2_ * 0.5)) * gains_[0] * adsr_[0]->tick() * waves_[0]->tick();
+ temp += control2_ * 0.5 * gains_[2] * adsr_[2]->tick() * waves_[2]->tick();
+
+ // Calculate amplitude modulation and apply it to output.
+ temp2 = vibrato_.tick() * modDepth_;
+ temp = temp * (1.0 + temp2);
+
+ lastFrame_[0] = temp * 0.5;
+ return lastFrame_[0];
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_WVIN_H
+#define STK_WVIN_H
+
+#include "Stk.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class WvIn
+ \brief STK audio input abstract base class.
+
+ This class provides common functionality for a variety of audio
+ data input subclasses.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class WvIn : public Stk
+{
+public:
+ //! Return the number of audio channels in the data or stream.
+ unsigned int channelsOut( void ) const { return data_.channels(); };
+
+ //! Return an StkFrames reference to the last computed sample frame.
+ /*!
+ If no file data is loaded, an empty container is returned.
+ */
+ const StkFrames& lastFrame( void ) const { return lastFrame_; };
+
+ //! Compute one sample frame and return the specified \c channel value.
+ virtual StkFloat tick( unsigned int channel = 0 ) = 0;
+
+ //! Fill the StkFrames argument with computed frames and return the same reference.
+ virtual StkFrames& tick( StkFrames& frames ) = 0;
+
+protected:
+
+ StkFrames data_;
+ StkFrames lastFrame_;
+
+};
+
+} // stk namespace
+
+#endif
--- /dev/null
+#ifndef STK_WVOUT_H
+#define STK_WVOUT_H
+
+#include "Stk.h"
+
+namespace stk {
+
+/***************************************************/
+/*! \class WvOut
+ \brief STK audio output abstract base class.
+
+ This class provides common functionality for a variety of audio
+ data output subclasses.
+
+ Currently, WvOut is non-interpolating and the output rate is
+ always Stk::sampleRate().
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+class WvOut : public Stk
+{
+ public:
+
+ //! Default constructor.
+ WvOut( void ) : frameCounter_(0), clipping_(false) {};
+
+ //! Return the number of sample frames output.
+ unsigned long getFrameCount( void ) const { return frameCounter_; };
+
+ //! Return the number of seconds of data output.
+ StkFloat getTime( void ) const { return (StkFloat) frameCounter_ / Stk::sampleRate(); };
+
+ //! Returns \c true if clipping has been detected during output since instantiation or the last reset.
+ bool clipStatus( void ) { return clipping_; };
+
+ //! Reset the clipping status to \c false.
+ void resetClipStatus( void ) { clipping_ = false; };
+
+ //! Output a single sample to all channels in a sample frame.
+ /*!
+ An StkError is thrown if an output error occurs.
+ */
+ virtual void tick( const StkFloat sample ) = 0;
+
+ //! Output the StkFrames data.
+ virtual void tick( const StkFrames& frames ) = 0;
+
+ protected:
+
+ // Check for sample clipping and clamp.
+ StkFloat& clipTest( StkFloat& sample );
+
+ StkFrames data_;
+ unsigned long frameCounter_;
+ bool clipping_;
+
+};
+
+inline StkFloat& WvOut :: clipTest( StkFloat& sample )
+{
+ bool clip = false;
+ if ( sample > 1.0 ) {
+ sample = 1.0;
+ clip = true;
+ }
+ else if ( sample < -1.0 ) {
+ sample = -1.0;
+ clip = true;
+ }
+
+ if ( clip == true && clipping_ == false ) {
+ // First occurrence of clipping since instantiation or reset.
+ clipping_ = true;
+ errorString_ << "WvOut: data value(s) outside +-1.0 detected ... clamping at outer bound!";
+ handleError( StkError::WARNING );
+ }
+
+ return sample;
+}
+
+} // stk namespace
+
+#endif
--- /dev/null
+/**********************************************/
+/** Utility to make various functions **/
+/** like exponential and log gain curves. **/
+/** **/
+/** Included here: **/
+/** Yamaha TX81Z curves for master gain, **/
+/** Envelope Rates (in normalized units), **/
+/** envelope sustain level, and more.... **/
+/**********************************************/
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+void main1() //MoMu modified
+{
+ int i;
+ double data[128];
+
+ /*************** TX81Z Master Gain *************/
+ for (i=0;i<100;i++) {
+ data[i] = pow(2.0,-(99-i)/10.0);
+ }
+ data[0] = 0.0;
+ printf("double __FM4Op_gains[99] = {");
+ for (i=0;i<100;i++) {
+ if (i%8 == 0) printf("\n");
+ printf("%lf,",data[i]);
+ }
+ printf("};\n");
+ /*************** TX81Z Sustain Level ***********/
+ for (i=0;i<16;i++) {
+ data[i] = pow(2.0,-(15-i)/2.0);
+ }
+ data[0] = 0.0;
+ printf("double __FM4Op_susLevels[16] = {");
+ for (i=0;i<16;i++) {
+ if (i%8 == 0) printf("\n");
+ printf("%lf,",data[i]);
+ }
+ printf("};\n");
+ /****************** Attack Rate ***************/
+ for (i=0;i<32;i++) {
+ data[i] = 6.0 * pow(5.7,-(i-1)/5.0);
+ }
+ printf("double __FM4Op_attTimes[16] = {");
+ for (i=0;i<32;i++) {
+ if (i%8 == 0) printf("\n");
+ printf("%lf,",data[i]);
+ }
+ printf("};\n");
+ exit(1);
+}
+
--- /dev/null
+/**********************************************/
+/** Utility to make various functions **/
+/** like exponential and log gain curves. **/
+/** Specifically for direct MIDI parameter **/
+/** conversions. **/
+/** Included here: **/
+/** A440 Referenced Equal Tempered Pitches **/
+/** as a function of MIDI note number. **/
+/** **/
+/**********************************************/
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+void main2() //MoMu modified
+{
+ int i;
+ double temp;
+ //double data[128];
+
+ /********* Pitch as fn. of MIDI Note **********/
+
+ printf("double __MIDI_To_Pitch[128] = {");
+ for (i=0;i<128;i++) {
+ if (i%8 == 0) printf("\n");
+ temp = 220.0 * pow(2.0,((double) i - 57) / 12.0);
+ printf("%.2lf,",temp);
+ }
+ printf("};\n");
+ exit(1);
+}
+
--- /dev/null
+/**********************************************/
+/** Utility to make various flavors of **/
+/** sine wave (rectified, etc), and **/
+/** other commonly needed waveforms, like **/
+/** triangles, ramps, etc. **/
+/** The files generated are all 16 bit **/
+/** linear signed integer, of length **/
+/** as defined by LENGTH below **/
+/**********************************************/
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define LENGTH 256
+#define PI 3.14159265358979323846
+
+void main3() //MoMu modified
+{
+ int i,j;
+ double temp;
+ short data[LENGTH + 2];
+ FILE *fd;
+
+ /////////// Yer Basic TX81Z Waves, Including Sine ///////////
+ fd = fopen("halfwave.raw","wb");
+ for (i=0;i<LENGTH/2;i++)
+ data[i] = 32767 * sin(i * 2 * PI / (double) LENGTH);
+ for (i=LENGTH/2;i<LENGTH;i++)
+ data[i] = 0;
+ fwrite(&data,2,LENGTH,fd);
+ fclose(fd);
+
+ fd = fopen("sinewave.raw","wb");
+ for (i=LENGTH/2;i<LENGTH;i++)
+ data[i] = 32767 * sin(i * 2 * PI / (double) LENGTH);
+ fwrite(&data,2,LENGTH,fd);
+ fclose(fd);
+
+ fd = fopen("sineblnk.raw","wb");
+ for (i=0;i<LENGTH/2;i++)
+ data[i] = data[2*i];
+ for (i=LENGTH/2;i<LENGTH;i++)
+ data[i] = 0;
+ fwrite(&data,2,LENGTH,fd);
+ fclose(fd);
+
+ fd = fopen("fwavblnk.raw","wb");
+ for (i=0;i<LENGTH/4;i++)
+ data[i+LENGTH/4] = data[i];
+ fwrite(&data,2,LENGTH,fd);
+ fclose(fd);
+
+ fd = fopen("snglpeak.raw","wb");
+ for (i=0;i<=LENGTH/4;i++)
+ data[i] = 32767 * (1.0 - cos(i * 2 * PI / (double) LENGTH));
+ for (i=0;i<=LENGTH/4;i++)
+ data[LENGTH/2-i] = data[i];
+ for (i=LENGTH/2;i<LENGTH;i++)
+ data[i] = 0;
+ fwrite(&data,2,LENGTH,fd);
+ fclose(fd);
+
+ fd = fopen("twopeaks.raw","wb");
+ for (i=0;i<=LENGTH/2;i++) {
+ data[LENGTH/2+i] = -data[i];
+ }
+ fwrite(&data,2,LENGTH,fd);
+ fclose(fd);
+
+ fd = fopen("peksblnk.raw","wb");
+ for (i=0;i<=LENGTH/2;i++)
+ data[i] = data[i*2];
+ for (i=LENGTH/2;i<LENGTH;i++)
+ data[i] = 0;
+ fwrite(&data,2,LENGTH,fd);
+ fclose(fd);
+
+ fd = fopen("ppksblnk.raw","wb");
+ for (i=0;i<=LENGTH/4;i++)
+ data[i+LENGTH/4] = data[i];
+ fwrite(&data,2,LENGTH,fd);
+ fclose(fd);
+
+ /////////// Impulses of various bandwidth ///////////
+ fd = fopen("impuls10.raw","wb");
+ for (i=0;i<LENGTH;i++) {
+ temp = 0.0;
+ for (j=1;j<=10;j++)
+ temp += cos(i * j * 2 * PI / (double) LENGTH);
+ data[i] = 32767 / 10.0 * temp;
+ }
+ fwrite(&data,2,LENGTH,fd);
+ fclose(fd);
+
+ fd = fopen("impuls20.raw","wb");
+ for (i=0;i<LENGTH;i++) {
+ temp = 0.0;
+ for (j=1;j<=20;j++)
+ temp += cos(i * j * 2 * PI / (double) LENGTH);
+ data[i] = 32767 / 20.0 * temp;
+ }
+ fwrite(&data,2,LENGTH,fd);
+ fclose(fd);
+
+ fd = fopen("impuls40.raw","wb");
+ for (i=0;i<LENGTH;i++) {
+ temp = 0.0;
+ for (j=1;j<=40;j++)
+ temp += cos(i * j * 2 * PI / (double) LENGTH);
+ data[i] = 32767 / 40.0 * temp;
+ }
+ fwrite(&data,2,LENGTH,fd);
+ fclose(fd);
+
+}
--- /dev/null
+// Utility to make a rawwave sine table (assumes big-endian machine).
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define LENGTH 1024
+#define PI 3.14159265358979323846
+
+void main4() //MoMu modified
+{
+ int i;
+ //double temp;
+ short data[LENGTH + 2];
+ FILE *fd;
+
+ fd = fopen("sinewave.raw","wb");
+ for (i=0; i<LENGTH; i++)
+ data[i] = 32767 * sin(i * 2 * PI / (double) LENGTH);
+ fwrite(&data,2,LENGTH,fd);
+ fclose(fd);
+}
--- /dev/null
+/***************************************************/
+/*! \class ADSR
+ \brief STK ADSR envelope class.
+
+ This class implements a traditional ADSR (Attack, Decay, Sustain,
+ Release) envelope. It responds to simple keyOn and keyOff
+ messages, keeping track of its state. The \e state = ADSR::DONE
+ after the envelope value reaches 0.0 in the ADSR::RELEASE state.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "ADSR.h"
+
+namespace stk {
+
+ADSR :: ADSR( void )
+{
+ target_ = 0.0;
+ value_ = 0.0;
+ attackRate_ = 0.001;
+ decayRate_ = 0.001;
+ releaseRate_ = 0.005;
+ sustainLevel_ = 0.5;
+ state_ = ATTACK;
+ Stk::addSampleRateAlert( this );
+}
+
+ADSR :: ~ADSR( void )
+{
+}
+
+void ADSR :: sampleRateChanged( StkFloat newRate, StkFloat oldRate )
+{
+ if ( !ignoreSampleRateChange_ ) {
+ attackRate_ = oldRate * attackRate_ / newRate;
+ decayRate_ = oldRate * decayRate_ / newRate;
+ releaseRate_ = oldRate * releaseRate_ / newRate;
+ }
+}
+
+void ADSR :: keyOn()
+{
+ target_ = 1.0;
+ state_ = ATTACK;
+}
+
+void ADSR :: keyOff()
+{
+ target_ = 0.0;
+ state_ = RELEASE;
+}
+
+void ADSR :: setAttackRate( StkFloat rate )
+{
+ if ( rate < 0.0 ) {
+ errorString_ << "ADSR::setAttackRate: negative rates not allowed ... correcting!";
+ handleError( StkError::WARNING );
+ attackRate_ = -rate;
+ }
+ else attackRate_ = rate;
+}
+
+void ADSR :: setDecayRate( StkFloat rate )
+{
+ if ( rate < 0.0 ) {
+ errorString_ << "ADSR::setDecayRate: negative rates not allowed ... correcting!";
+ handleError( StkError::WARNING );
+ decayRate_ = -rate;
+ }
+ else decayRate_ = rate;
+}
+
+void ADSR :: setSustainLevel( StkFloat level )
+{
+ if ( level < 0.0 ) {
+ errorString_ << "ADSR::setSustainLevel: level out of range ... correcting!";
+ handleError( StkError::WARNING );
+ sustainLevel_ = 0.0;
+ }
+ else sustainLevel_ = level;
+}
+
+void ADSR :: setReleaseRate( StkFloat rate )
+{
+ if ( rate < 0.0 ) {
+ errorString_ << "ADSR::setReleaseRate: negative rates not allowed ... correcting!";
+ handleError( StkError::WARNING );
+ releaseRate_ = -rate;
+ }
+ else releaseRate_ = rate;
+}
+
+void ADSR :: setAttackTime( StkFloat time )
+{
+ if ( time < 0.0 ) {
+ errorString_ << "ADSR::setAttackTime: negative times not allowed ... correcting!";
+ handleError( StkError::WARNING );
+ attackRate_ = 1.0 / ( -time * Stk::sampleRate() );
+ }
+ else attackRate_ = 1.0 / ( time * Stk::sampleRate() );
+}
+
+void ADSR :: setDecayTime( StkFloat time )
+{
+ if ( time < 0.0 ) {
+ errorString_ << "ADSR::setDecayTime: negative times not allowed ... correcting!";
+ handleError( StkError::WARNING );
+ decayRate_ = 1.0 / ( -time * Stk::sampleRate() );
+ }
+ else decayRate_ = 1.0 / ( time * Stk::sampleRate() );
+}
+
+void ADSR :: setReleaseTime( StkFloat time )
+{
+ if ( time < 0.0 ) {
+ errorString_ << "ADSR::setReleaseTime: negative times not allowed ... correcting!";
+ handleError( StkError::WARNING );
+ releaseRate_ = sustainLevel_ / ( -time * Stk::sampleRate() );
+ }
+ else releaseRate_ = sustainLevel_ / ( time * Stk::sampleRate() );
+}
+
+void ADSR :: setAllTimes( StkFloat aTime, StkFloat dTime, StkFloat sLevel, StkFloat rTime )
+{
+ this->setAttackTime( aTime );
+ this->setDecayTime( dTime );
+ this->setSustainLevel( sLevel );
+ this->setReleaseTime( rTime );
+}
+
+void ADSR :: setTarget( StkFloat target )
+{
+ target_ = target;
+ if ( value_ < target_ ) {
+ state_ = ATTACK;
+ this->setSustainLevel( target_ );
+ }
+ if ( value_ > target_ ) {
+ this->setSustainLevel( target_ );
+ state_ = DECAY;
+ }
+}
+
+void ADSR :: setValue( StkFloat value )
+{
+ state_ = SUSTAIN;
+ target_ = value;
+ value_ = value;
+ this->setSustainLevel( value );
+ lastFrame_[0] = value;
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class Asymp
+ \brief STK asymptotic curve envelope class
+
+ This class implements a simple envelope generator
+ which asymptotically approaches a target value.
+ The algorithm used is of the form:
+
+ y[n] = a y[n-1] + (1-a) target,
+
+ where a = exp(-T/tau), T is the sample period, and
+ tau is a time constant. The user can set the time
+ constant (default value = 0.3) and target value.
+ Theoretically, this recursion never reaches its
+ target, though the calculations in this class are
+ stopped when the current value gets within a small
+ threshold value of the target (at which time the
+ current value is set to the target). It responds
+ to \e keyOn and \e keyOff messages by ramping to
+ 1.0 on keyOn and to 0.0 on keyOff.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "Asymp.h"
+#include <cmath>
+
+namespace stk {
+
+Asymp :: Asymp( void )
+{
+ value_ = 0.0;
+ target_ = 0.0;
+ state_ = 0;
+ factor_ = exp( -1.0 / ( 0.3 * Stk::sampleRate() ) );
+ constant_ = 0.0;
+ Stk::addSampleRateAlert( this );
+}
+
+Asymp :: ~Asymp( void )
+{
+}
+
+void Asymp :: sampleRateChanged( StkFloat newRate, StkFloat oldRate )
+{
+ if ( !ignoreSampleRateChange_ ) {
+ StkFloat tau = -1.0 / ( std::log( factor_ ) * oldRate );
+ factor_ = std::exp( -1.0 / ( tau * newRate ) );
+ }
+}
+
+void Asymp :: keyOn( void )
+{
+ this->setTarget( 1.0 );
+}
+
+void Asymp :: keyOff( void )
+{
+ this->setTarget( 0.0 );
+}
+
+void Asymp :: setTau( StkFloat tau )
+{
+ if ( tau <= 0.0 ) {
+ errorString_ << "Asymp::setTau: negative or zero tau not allowed ... ignoring!";
+ handleError( StkError::WARNING );
+ return;
+ }
+
+ factor_ = std::exp( -1.0 / ( tau * Stk::sampleRate() ) );
+ constant_ = ( 1.0 - factor_ ) * target_;
+}
+
+void Asymp :: setTime( StkFloat time )
+{
+ if ( time <= 0.0 ) {
+ errorString_ << "Asymp::setTime: negative or zero times not allowed ... ignoring!";
+ handleError( StkError::WARNING );
+ return;
+ }
+
+ StkFloat tau = -time / std::log( TARGET_THRESHOLD );
+ factor_ = std::exp( -1.0 / ( tau * Stk::sampleRate() ) );
+ constant_ = ( 1.0 - factor_ ) * target_;
+}
+
+void Asymp :: setTarget( StkFloat target )
+{
+ target_ = target;
+ if ( value_ != target_ ) state_ = 1;
+ constant_ = ( 1.0 - factor_ ) * target_;
+}
+
+void Asymp :: setValue( StkFloat value )
+{
+ state_ = 0;
+ target_ = value;
+ value_ = value;
+}
+
+} // stk namespace
+
--- /dev/null
+/***************************************************/
+/*! \class BandedWG
+ \brief Banded waveguide modeling class.
+
+ This class uses banded waveguide techniques to
+ model a variety of sounds, including bowed
+ bars, glasses, and bowls. For more
+ information, see Essl, G. and Cook, P. "Banded
+ Waveguides: Towards Physical Modelling of Bar
+ Percussion Instruments", Proceedings of the
+ 1999 International Computer Music Conference.
+
+ Control Change Numbers:
+ - Bow Pressure = 2
+ - Bow Motion = 4
+ - Strike Position = 8 (not implemented)
+ - Vibrato Frequency = 11
+ - Gain = 1
+ - Bow Velocity = 128
+ - Set Striking = 64
+ - Instrument Presets = 16
+ - Uniform Bar = 0
+ - Tuned Bar = 1
+ - Glass Harmonica = 2
+ - Tibetan Bowl = 3
+
+ by Georg Essl, 1999 - 2004.
+ Modified for STK 4.0 by Gary Scavone.
+*/
+/***************************************************/
+
+#include "BandedWG.h"
+#include "Skini_msg.h"
+#include <cmath>
+
+namespace stk {
+
+BandedWG :: BandedWG( void )
+{
+ doPluck_ = true;
+
+ bowTable_.setSlope( 3.0 );
+ adsr_.setAllTimes( 0.02, 0.005, 0.9, 0.01);
+
+ frequency_ = 220.0;
+ this->setPreset(0);
+
+ bowPosition_ = 0;
+ baseGain_ = (StkFloat) 0.999;
+
+ integrationConstant_ = 0.0;
+ trackVelocity_ = false;
+
+ bowVelocity_ = 0.0;
+ bowTarget_ = 0.0;
+
+ strikeAmp_ = 0.0;
+}
+
+BandedWG :: ~BandedWG( void )
+{
+}
+
+void BandedWG :: clear( void )
+{
+ for ( int i=0; i<nModes_; i++ ) {
+ delay_[i].clear();
+ bandpass_[i].clear();
+ }
+}
+
+void BandedWG :: setPreset( int preset )
+{
+ int i;
+ switch ( preset ) {
+
+ case 1: // Tuned Bar
+ presetModes_ = 4;
+ modes_[0] = (StkFloat) 1.0;
+ modes_[1] = (StkFloat) 4.0198391420;
+ modes_[2] = (StkFloat) 10.7184986595;
+ modes_[3] = (StkFloat) 18.0697050938;
+
+ for (i=0; i<presetModes_; i++) {
+ basegains_[i] = (StkFloat) pow(0.999,(double) i+1);
+ excitation_[i] = 1.0;
+ }
+
+ break;
+
+ case 2: // Glass Harmonica
+ presetModes_ = 5;
+ modes_[0] = (StkFloat) 1.0;
+ modes_[1] = (StkFloat) 2.32;
+ modes_[2] = (StkFloat) 4.25;
+ modes_[3] = (StkFloat) 6.63;
+ modes_[4] = (StkFloat) 9.38;
+ // modes_[5] = (StkFloat) 12.22;
+
+ for (i=0; i<presetModes_; i++) {
+ basegains_[i] = (StkFloat) pow(0.999,(double) i+1);
+ excitation_[i] = 1.0;
+ }
+ /*
+ baseGain_ = (StkFloat) 0.99999;
+ for (i=0; i<presetModes_; i++)
+ gains_[i]= (StkFloat) pow(baseGain_, delay_[i].getDelay()+i);
+ */
+
+ break;
+
+ case 3: // Tibetan Prayer Bowl (ICMC'02)
+ presetModes_ = 12;
+ modes_[0]=0.996108344;
+ basegains_[0]=0.999925960128219;
+ excitation_[0]=11.900357/10.0;
+ modes_[1]=1.0038916562;
+ basegains_[1]=0.999925960128219;
+ excitation_[1]=11.900357/10.;
+ modes_[2]=2.979178;
+ basegains_[2]=0.999982774366897;
+ excitation_[2]=10.914886/10.;
+ modes_[3]=2.99329767;
+ basegains_[3]=0.999982774366897;
+ excitation_[3]=10.914886/10.;
+ modes_[4]=5.704452;
+ basegains_[4]=1.0; //0.999999999999999999987356406352;
+ excitation_[4]=42.995041/10.;
+ modes_[5]=5.704452;
+ basegains_[5]=1.0; //0.999999999999999999987356406352;
+ excitation_[5]=42.995041/10.;
+ modes_[6]=8.9982;
+ basegains_[6]=1.0; //0.999999999999999999996995497558225;
+ excitation_[6]=40.063034/10.;
+ modes_[7]=9.01549726;
+ basegains_[7]=1.0; //0.999999999999999999996995497558225;
+ excitation_[7]=40.063034/10.;
+ modes_[8]=12.83303;
+ basegains_[8]=0.999965497558225;
+ excitation_[8]=7.063034/10.;
+ modes_[9]=12.807382;
+ basegains_[9]=0.999965497558225;
+ excitation_[9]=7.063034/10.;
+ modes_[10]=17.2808219;
+ basegains_[10]=0.9999999999999999999965497558225;
+ excitation_[10]=57.063034/10.;
+ modes_[11]=21.97602739726;
+ basegains_[11]=0.999999999999999965497558225;
+ excitation_[11]=57.063034/10.;
+
+ break;
+
+ default: // Uniform Bar
+ presetModes_ = 4;
+ modes_[0] = (StkFloat) 1.0;
+ modes_[1] = (StkFloat) 2.756;
+ modes_[2] = (StkFloat) 5.404;
+ modes_[3] = (StkFloat) 8.933;
+
+ for (i=0; i<presetModes_; i++) {
+ basegains_[i] = (StkFloat) pow(0.9,(double) i+1);
+ excitation_[i] = 1.0;
+ }
+
+ break;
+ }
+
+ nModes_ = presetModes_;
+ setFrequency( frequency_ );
+}
+
+void BandedWG :: setFrequency( StkFloat frequency )
+{
+ frequency_ = frequency;
+ if ( frequency <= 0.0 ) {
+ errorString_ << "BandedWG::setFrequency: parameter is less than or equal to zero!";
+ handleError( StkError::WARNING );
+ frequency_ = 220.0;
+ }
+ if (frequency_ > 1568.0) frequency_ = 1568.0;
+
+ StkFloat radius;
+ StkFloat base = Stk::sampleRate() / frequency_;
+ StkFloat length;
+ for (int i=0; i<presetModes_; i++) {
+ // Calculate the delay line lengths for each mode.
+ length = (int)(base / modes_[i]);
+ if ( length > 2.0) {
+ delay_[i].setDelay( length );
+ gains_[i]=basegains_[i];
+ // gains_[i]=(StkFloat) pow(basegains_[i], 1/((StkFloat)delay_[i].getDelay()));
+ // std::cerr << gains_[i];
+ }
+ else {
+ nModes_ = i;
+ break;
+ }
+ // std::cerr << std::endl;
+
+ // Set the bandpass filter resonances
+ radius = 1.0 - PI * 32 / Stk::sampleRate(); //frequency_ * modes_[i] / Stk::sampleRate()/32;
+ if ( radius < 0.0 ) radius = 0.0;
+ bandpass_[i].setResonance(frequency_ * modes_[i], radius, true);
+
+ delay_[i].clear();
+ bandpass_[i].clear();
+ }
+
+ //int olen = (int)(delay_[0].getDelay());
+ //strikePosition_ = (int)(strikePosition_*(length/modes_[0])/olen);
+}
+
+void BandedWG :: setStrikePosition( StkFloat position )
+{
+ strikePosition_ = (int)(delay_[0].getDelay() * position / 2.0);
+}
+
+void BandedWG :: startBowing( StkFloat amplitude, StkFloat rate )
+{
+ adsr_.setAttackRate(rate);
+ adsr_.keyOn();
+ maxVelocity_ = 0.03 + (0.1 * amplitude);
+}
+
+void BandedWG :: stopBowing( StkFloat rate )
+{
+ adsr_.setReleaseRate(rate);
+ adsr_.keyOff();
+}
+
+void BandedWG :: pluck( StkFloat amplitude )
+{
+ int j;
+ StkFloat min_len = delay_[nModes_-1].getDelay();
+ for (int i=0; i<nModes_; i++)
+ for(j=0; j<(int)(delay_[i].getDelay()/min_len); j++)
+ delay_[i].tick( excitation_[i]*amplitude / nModes_ );
+
+ // strikeAmp_ += amplitude;
+}
+
+void BandedWG :: noteOn( StkFloat frequency, StkFloat amplitude )
+{
+ this->setFrequency(frequency);
+
+ if ( doPluck_ )
+ this->pluck(amplitude);
+ else
+ this->startBowing(amplitude, amplitude * 0.001);
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "BandedWG::NoteOn: frequency = " << frequency << ", amplitude = " << amplitude << ".";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+void BandedWG :: noteOff( StkFloat amplitude )
+{
+ if ( !doPluck_ )
+ this->stopBowing((1.0 - amplitude) * 0.005);
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "BandedWG::NoteOff: amplitude = " << amplitude << ".";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+StkFloat BandedWG :: tick( unsigned int )
+{
+ int k;
+
+ StkFloat input = 0.0;
+ if ( doPluck_ ) {
+ input = 0.0;
+ // input = strikeAmp_/nModes_;
+ // strikeAmp_ = 0.0;
+ }
+ else {
+ if ( integrationConstant_ == 0.0 )
+ velocityInput_ = 0.0;
+ else
+ velocityInput_ = integrationConstant_ * velocityInput_;
+
+ for ( k=0; k<nModes_; k++ )
+ velocityInput_ += baseGain_ * delay_[k].lastOut();
+
+ if ( trackVelocity_ ) {
+ bowVelocity_ *= 0.9995;
+ bowVelocity_ += bowTarget_;
+ bowTarget_ *= 0.995;
+ }
+ else
+ bowVelocity_ = adsr_.tick() * maxVelocity_;
+
+ input = bowVelocity_ - velocityInput_;
+ input = input * bowTable_.tick(input);
+ input = input/(StkFloat)nModes_;
+ }
+
+ StkFloat data = 0.0;
+ for ( k=0; k<nModes_; k++ ) {
+ bandpass_[k].tick(input + gains_[k] * delay_[k].lastOut());
+ delay_[k].tick(bandpass_[k].lastOut());
+ data += bandpass_[k].lastOut();
+ }
+
+ //lastFrame_[0] = data * nModes_;
+ lastFrame_[0] = data * 4;
+ return lastFrame_[0];
+}
+
+void BandedWG :: controlChange( int number, StkFloat value )
+{
+ StkFloat norm = value * ONE_OVER_128;
+ if ( norm < 0 ) {
+ norm = 0.0;
+ errorString_ << "BandedWG::controlChange: control value less than zero ... setting to zero!";
+ handleError( StkError::WARNING );
+ }
+ else if ( norm > 1.0 ) {
+ norm = 1.0;
+ errorString_ << "BandedWG::controlChange: control value greater than 128.0 ... setting to 128.0!";
+ handleError( StkError::WARNING );
+ }
+
+ if (number == __SK_BowPressure_) { // 2
+ if ( norm == 0.0 )
+ doPluck_ = true;
+ else {
+ doPluck_ = false;
+ bowTable_.setSlope( 10.0 - (9.0 * norm));
+ }
+ }
+ else if (number == 4) { // 4
+ if ( !trackVelocity_ ) trackVelocity_ = true;
+ bowTarget_ += 0.005 * (norm - bowPosition_);
+ bowPosition_ = norm;
+ //adsr_.setTarget(bowPosition_);
+ }
+ else if (number == 8) // 8
+ this->setStrikePosition( norm );
+ else if (number == __SK_AfterTouch_Cont_) { // 128
+ //bowTarget_ += 0.02 * (norm - bowPosition_);
+ //bowPosition_ = norm;
+ if ( trackVelocity_ ) trackVelocity_ = false;
+ maxVelocity_ = 0.13 * norm;
+ adsr_.setTarget(norm);
+ }
+ else if (number == __SK_ModWheel_) { // 1
+ // baseGain_ = 0.9989999999 + (0.001 * norm );
+ baseGain_ = 0.8999999999999999 + (0.1 * norm);
+ // std::cerr << "Yuck!" << std::endl;
+ for (int i=0; i<nModes_; i++)
+ gains_[i]=(StkFloat) basegains_[i]*baseGain_;
+ // gains_[i]=(StkFloat) pow(baseGain_, (int)((StkFloat)delay_[i].getDelay()+i));
+ }
+ else if (number == __SK_ModFrequency_) // 11
+ integrationConstant_ = norm;
+ else if (number == __SK_Sustain_) { // 64
+ if (value < 65) doPluck_ = true;
+ else doPluck_ = false;
+ }
+ else if (number == __SK_Portamento_) { // 65
+ if (value < 65) trackVelocity_ = false;
+ else trackVelocity_ = true;
+ }
+ else if (number == __SK_ProphesyRibbon_) // 16
+ this->setPreset((int) value);
+ else {
+ errorString_ << "BandedWG::controlChange: undefined control number (" << number << ")!";
+ handleError( StkError::WARNING );
+ }
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "BandedWG::controlChange: number = " << number << ", value = " << value << ".";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class BeeThree
+ \brief STK Hammond-oid organ FM synthesis instrument.
+
+ This class implements a simple 4 operator
+ topology, also referred to as algorithm 8 of
+ the TX81Z.
+
+ \code
+ Algorithm 8 is :
+ 1 --.
+ 2 -\|
+ +-> Out
+ 3 -/|
+ 4 --
+ \endcode
+
+ Control Change Numbers:
+ - Operator 4 (feedback) Gain = 2
+ - Operator 3 Gain = 4
+ - LFO Speed = 11
+ - LFO Depth = 1
+ - ADSR 2 & 4 Target = 128
+
+ The basic Chowning/Stanford FM patent expired
+ in 1995, but there exist follow-on patents,
+ mostly assigned to Yamaha. If you are of the
+ type who should worry about this (making
+ money) worry away.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "BeeThree.h"
+
+namespace stk {
+
+BeeThree :: BeeThree( void )
+ : FM()
+{
+ // Concatenate the STK rawwave path to the rawwave files
+ for ( unsigned int i=0; i<3; i++ )
+ waves_[i] = new FileLoop( (Stk::rawwavePath() + "sinewave.raw").c_str(), true );
+ waves_[3] = new FileLoop( (Stk::rawwavePath() + "fwavblnk.raw").c_str(), true );
+
+ this->setRatio( 0, 0.999 );
+ this->setRatio( 1, 1.997 );
+ this->setRatio( 2, 3.006 );
+ this->setRatio( 3, 6.009 );
+
+ gains_[0] = fmGains_[95];
+ gains_[1] = fmGains_[95];
+ gains_[2] = fmGains_[99];
+ gains_[3] = fmGains_[95];
+
+ adsr_[0]->setAllTimes( 0.005, 0.003, 1.0, 0.01 );
+ adsr_[1]->setAllTimes( 0.005, 0.003, 1.0, 0.01 );
+ adsr_[2]->setAllTimes( 0.005, 0.003, 1.0, 0.01 );
+ adsr_[3]->setAllTimes( 0.005, 0.001, 0.4, 0.03 );
+
+ twozero_.setGain( 0.1 );
+}
+
+BeeThree :: ~BeeThree( void )
+{
+}
+
+void BeeThree :: noteOn( StkFloat frequency, StkFloat amplitude )
+{
+ gains_[0] = amplitude * fmGains_[95];
+ gains_[1] = amplitude * fmGains_[95];
+ gains_[2] = amplitude * fmGains_[99];
+ gains_[3] = amplitude * fmGains_[95];
+ this->setFrequency( frequency );
+ this->keyOn();
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "BeeThree::NoteOn: frequency = " << frequency << ", amplitude = " << amplitude << '.';
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class BiQuad
+ \brief STK biquad (two-pole, two-zero) filter class.
+
+ This class implements a two-pole, two-zero digital filter.
+ Methods are provided for creating a resonance or notch in the
+ frequency response while maintaining a constant filter gain.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "BiQuad.h"
+#include <cmath>
+
+namespace stk {
+
+BiQuad :: BiQuad() : Filter()
+{
+ b_.resize( 3, 0.0 );
+ a_.resize( 3, 0.0 );
+ b_[0] = 1.0;
+ a_[0] = 1.0;
+ inputs_.resize( 3, 1, 0.0 );
+ outputs_.resize( 3, 1, 0.0 );
+
+ Stk::addSampleRateAlert( this );
+}
+
+BiQuad :: ~BiQuad()
+{
+ Stk::removeSampleRateAlert( this );
+}
+
+void BiQuad :: setCoefficients( StkFloat b0, StkFloat b1, StkFloat b2, StkFloat a1, StkFloat a2, bool clearState )
+{
+ b_[0] = b0;
+ b_[1] = b1;
+ b_[2] = b2;
+ a_[1] = a1;
+ a_[2] = a2;
+
+ if ( clearState ) this->clear();
+}
+
+void BiQuad :: sampleRateChanged( StkFloat newRate, StkFloat oldRate )
+{
+ if ( !ignoreSampleRateChange_ ) {
+ errorString_ << "BiQuad::sampleRateChanged: you may need to recompute filter coefficients!";
+ handleError( StkError::WARNING );
+ }
+}
+
+void BiQuad :: setResonance(StkFloat frequency, StkFloat radius, bool normalize)
+{
+ a_[2] = radius * radius;
+ a_[1] = -2.0 * radius * cos( TWO_PI * frequency / Stk::sampleRate() );
+
+ if ( normalize ) {
+ // Use zeros at +- 1 and normalize the filter peak gain.
+ b_[0] = 0.5 - 0.5 * a_[2];
+ b_[1] = 0.0;
+ b_[2] = -b_[0];
+ }
+}
+
+void BiQuad :: setNotch(StkFloat frequency, StkFloat radius)
+{
+ // This method does not attempt to normalize the filter gain.
+ b_[2] = radius * radius;
+ b_[1] = (StkFloat) -2.0 * radius * cos( TWO_PI * (double) frequency / Stk::sampleRate() );
+}
+
+void BiQuad :: setEqualGainZeroes()
+{
+ b_[0] = 1.0;
+ b_[1] = 0.0;
+ b_[2] = -1.0;
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/\r
+/*! \class Blit\r
+ \brief STK band-limited impulse train class.\r
+\r
+ This class generates a band-limited impulse train using a\r
+ closed-form algorithm reported by Stilson and Smith in "Alias-Free\r
+ Digital Synthesis of Classic Analog Waveforms", 1996. The user\r
+ can specify both the fundamental frequency of the impulse train\r
+ and the number of harmonics contained in the resulting signal.\r
+\r
+ The signal is normalized so that the peak value is +/-1.0.\r
+\r
+ If nHarmonics is 0, then the signal will contain all harmonics up\r
+ to half the sample rate. Note, however, that this setting may\r
+ produce aliasing in the signal when the frequency is changing (no\r
+ automatic modification of the number of harmonics is performed by\r
+ the setFrequency() function).\r
+\r
+ Original code by Robin Davies, 2005.\r
+ Revisions by Gary Scavone for STK, 2005.\r
+*/\r
+/***************************************************/\r
+\r
+#include "Blit.h"\r
+\r
+namespace stk {\r
+ \r
+Blit:: Blit( StkFloat frequency )\r
+{\r
+ nHarmonics_ = 0;\r
+ this->setFrequency( frequency );\r
+ this->reset();\r
+}\r
+\r
+Blit :: ~Blit()\r
+{\r
+}\r
+\r
+void Blit :: reset()\r
+{\r
+ phase_ = 0.0;\r
+ lastFrame_[0] = 0.0;\r
+}\r
+\r
+void Blit :: setFrequency( StkFloat frequency )\r
+{\r
+#if defined(_STK_DEBUG_)\r
+ errorString_ << "Blit::setFrequency: frequency = " << frequency << '.';\r
+ handleError( StkError::DEBUG_WARNING );\r
+#endif\r
+\r
+ p_ = Stk::sampleRate() / frequency;\r
+ rate_ = PI / p_;\r
+ this->updateHarmonics();\r
+}\r
+\r
+void Blit :: setHarmonics( unsigned int nHarmonics )\r
+{\r
+ nHarmonics_ = nHarmonics;\r
+ this->updateHarmonics();\r
+}\r
+\r
+void Blit :: updateHarmonics( void )\r
+{\r
+ if ( nHarmonics_ <= 0 ) {\r
+ unsigned int maxHarmonics = (unsigned int) floor( 0.5 * p_ );\r
+ m_ = 2 * maxHarmonics + 1;\r
+ }\r
+ else\r
+ m_ = 2 * nHarmonics_ + 1;\r
+\r
+#if defined(_STK_DEBUG_)\r
+ errorString_ << "Blit::updateHarmonics: nHarmonics_ = " << nHarmonics_ << ", m_ = " << m_ << '.';\r
+ handleError( StkError::DEBUG_WARNING );\r
+#endif\r
+}\r
+\r
+} // stk namespace\r
--- /dev/null
+/***************************************************/\r
+/*! \class BlitSaw\r
+ \brief STK band-limited sawtooth wave class.\r
+\r
+ This class generates a band-limited sawtooth waveform using a\r
+ closed-form algorithm reported by Stilson and Smith in "Alias-Free\r
+ Digital Synthesis of Classic Analog Waveforms", 1996. The user\r
+ can specify both the fundamental frequency of the sawtooth and the\r
+ number of harmonics contained in the resulting signal.\r
+\r
+ If nHarmonics is 0, then the signal will contain all harmonics up\r
+ to half the sample rate. Note, however, that this setting may\r
+ produce aliasing in the signal when the frequency is changing (no\r
+ automatic modification of the number of harmonics is performed by\r
+ the setFrequency() function).\r
+\r
+ Based on initial code of Robin Davies, 2005.\r
+ Modified algorithm code by Gary Scavone, 2005.\r
+*/\r
+/***************************************************/\r
+\r
+#include "BlitSaw.h"\r
+\r
+namespace stk {\r
+ \r
+BlitSaw:: BlitSaw( StkFloat frequency )\r
+{\r
+ nHarmonics_ = 0;\r
+ this->reset();\r
+ this->setFrequency( frequency );\r
+}\r
+\r
+BlitSaw :: ~BlitSaw()\r
+{\r
+}\r
+\r
+void BlitSaw :: reset()\r
+{\r
+ phase_ = 0.0f;\r
+ state_ = 0.0;\r
+ lastFrame_[0] = 0.0;\r
+}\r
+\r
+void BlitSaw :: setFrequency( StkFloat frequency )\r
+{\r
+#if defined(_STK_DEBUG_)\r
+ errorString_ << "BlitSaw::setFrequency: frequency = " << frequency << '.';\r
+ handleError( StkError::DEBUG_WARNING );\r
+#endif\r
+\r
+ p_ = Stk::sampleRate() / frequency;\r
+ C2_ = 1 / p_;\r
+ rate_ = PI * C2_;\r
+ this->updateHarmonics();\r
+}\r
+\r
+void BlitSaw :: setHarmonics( unsigned int nHarmonics )\r
+{\r
+ nHarmonics_ = nHarmonics;\r
+ this->updateHarmonics();\r
+\r
+ // I found that the initial DC offset could be minimized with an\r
+ // initial state setting as given below. This initialization should\r
+ // only happen before starting the oscillator for the first time\r
+ // (but after setting the frequency and number of harmonics). I\r
+ // struggled a bit to decide where best to put this and finally\r
+ // settled on here. In general, the user shouldn't be messing with\r
+ // the number of harmonics once the oscillator is running because\r
+ // this is automatically taken care of in the setFrequency()\r
+ // function. (GPS - 1 October 2005)\r
+ state_ = -0.5 * a_;\r
+}\r
+\r
+void BlitSaw :: updateHarmonics( void )\r
+{\r
+ if ( nHarmonics_ <= 0 ) {\r
+ unsigned int maxHarmonics = (unsigned int) floor( 0.5 * p_ );\r
+ m_ = 2 * maxHarmonics + 1;\r
+ }\r
+ else\r
+ m_ = 2 * nHarmonics_ + 1;\r
+\r
+ a_ = m_ / p_;\r
+\r
+#if defined(_STK_DEBUG_)\r
+ errorString_ << "BlitSaw::updateHarmonics: nHarmonics_ = " << nHarmonics_ << ", m_ = " << m_ << '.';\r
+ handleError( StkError::DEBUG_WARNING );\r
+#endif\r
+}\r
+\r
+} // stk namespace\r
--- /dev/null
+/***************************************************/\r
+/*! \class BlitSquare\r
+ \brief STK band-limited square wave class.\r
+\r
+ This class generates a band-limited square wave signal. It is\r
+ derived in part from the approach reported by Stilson and Smith in\r
+ "Alias-Free Digital Synthesis of Classic Analog Waveforms", 1996.\r
+ The algorithm implemented in this class uses a SincM function with\r
+ an even M value to achieve a bipolar bandlimited impulse train.\r
+ This signal is then integrated to achieve a square waveform. The\r
+ integration process has an associated DC offset so a DC blocking\r
+ filter is applied at the output.\r
+\r
+ The user can specify both the fundamental frequency of the\r
+ waveform and the number of harmonics contained in the resulting\r
+ signal.\r
+\r
+ If nHarmonics is 0, then the signal will contain all harmonics up\r
+ to half the sample rate. Note, however, that this setting may\r
+ produce aliasing in the signal when the frequency is changing (no\r
+ automatic modification of the number of harmonics is performed by\r
+ the setFrequency() function). Also note that the harmonics of a\r
+ square wave fall at odd integer multiples of the fundamental, so\r
+ aliasing will happen with a lower fundamental than with the other\r
+ Blit waveforms. This class is not guaranteed to be well behaved\r
+ in the presence of significant aliasing.\r
+\r
+ Based on initial code of Robin Davies, 2005\r
+ Modified algorithm code by Gary Scavone, 2005 - 2010.\r
+*/\r
+/***************************************************/\r
+\r
+#include "BlitSquare.h"\r
+\r
+namespace stk {\r
+\r
+BlitSquare:: BlitSquare( StkFloat frequency )\r
+{\r
+ nHarmonics_ = 0;\r
+ this->setFrequency( frequency );\r
+ this->reset();\r
+}\r
+\r
+BlitSquare :: ~BlitSquare()\r
+{\r
+}\r
+\r
+void BlitSquare :: reset()\r
+{\r
+ phase_ = 0.0;\r
+ lastFrame_[0] = 0.0;\r
+ dcbState_ = 0.0;\r
+ lastBlitOutput_ = 0;\r
+}\r
+\r
+void BlitSquare :: setFrequency( StkFloat frequency )\r
+{\r
+#if defined(_STK_DEBUG_)\r
+ errorString_ << "BlitSquare::setFrequency: frequency = " << frequency << '.';\r
+ handleError( StkError::DEBUG_WARNING );\r
+#endif\r
+\r
+ // By using an even value of the parameter M, we get a bipolar blit\r
+ // waveform at half the blit frequency. Thus, we need to scale the\r
+ // frequency value here by 0.5. (GPS, 2006).\r
+ p_ = 0.5 * Stk::sampleRate() / frequency;\r
+ rate_ = PI / p_;\r
+ this->updateHarmonics();\r
+}\r
+\r
+void BlitSquare :: setHarmonics( unsigned int nHarmonics )\r
+{\r
+ nHarmonics_ = nHarmonics;\r
+ this->updateHarmonics();\r
+}\r
+\r
+void BlitSquare :: updateHarmonics( void )\r
+{\r
+ // Make sure we end up with an even value of the parameter M here.\r
+ if ( nHarmonics_ <= 0 ) {\r
+ unsigned int maxHarmonics = (unsigned int) floor( 0.5 * p_ );\r
+ m_ = 2 * (maxHarmonics + 1);\r
+ }\r
+ else\r
+ m_ = 2 * (nHarmonics_ + 1);\r
+\r
+ a_ = m_ / p_;\r
+\r
+#if defined(_STK_DEBUG_)\r
+ errorString_ << "BlitSquare::updateHarmonics: nHarmonics_ = " << nHarmonics_ << ", m_ = " << m_ << '.';\r
+ handleError( StkError::DEBUG_WARNING );\r
+#endif\r
+}\r
+\r
+} // stk namespace\r
--- /dev/null
+/***************************************************/
+/*! \class BlowBotl
+ \brief STK blown bottle instrument class.
+
+ This class implements a helmholtz resonator
+ (biquad filter) with a polynomial jet
+ excitation (a la Cook).
+
+ Control Change Numbers:
+ - Noise Gain = 4
+ - Vibrato Frequency = 11
+ - Vibrato Gain = 1
+ - Volume = 128
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "BlowBotl.h"
+#include "Skini_msg.h"
+
+namespace stk {
+
+#define __BOTTLE_RADIUS_ 0.999
+
+BlowBotl :: BlowBotl( void )
+{
+ dcBlock_.setBlockZero();
+
+ vibrato_.setFrequency( 5.925 );
+ vibratoGain_ = 0.0;
+
+ resonator_.setResonance(500.0, __BOTTLE_RADIUS_, true);
+ adsr_.setAllTimes( 0.005, 0.01, 0.8, 0.010);
+
+ noiseGain_ = 20.0;
+ maxPressure_ = (StkFloat) 0.0;
+}
+
+BlowBotl :: ~BlowBotl( void )
+{
+}
+
+void BlowBotl :: clear( void )
+{
+ resonator_.clear();
+}
+
+void BlowBotl :: setFrequency( StkFloat frequency )
+{
+ StkFloat freakency = frequency;
+ if ( frequency <= 0.0 ) {
+ errorString_ << "BlowBotl::setFrequency: parameter is less than or equal to zero!";
+ handleError( StkError::WARNING );
+ freakency = 220.0;
+ }
+
+ resonator_.setResonance( freakency, __BOTTLE_RADIUS_, true );
+}
+
+void BlowBotl :: startBlowing( StkFloat amplitude, StkFloat rate )
+{
+ adsr_.setAttackRate(rate);
+ maxPressure_ = amplitude;
+ adsr_.keyOn();
+}
+
+void BlowBotl :: stopBlowing( StkFloat rate )
+{
+ adsr_.setReleaseRate(rate);
+ adsr_.keyOff();
+}
+
+void BlowBotl :: noteOn( StkFloat frequency, StkFloat amplitude )
+{
+ this->setFrequency(frequency);
+ startBlowing( 1.1 + (amplitude * 0.20), amplitude * 0.02);
+ outputGain_ = amplitude + 0.001;
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "BlowBotl::NoteOn: frequency = " << frequency << ", amplitude = " << amplitude << ".";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+void BlowBotl :: noteOff( StkFloat amplitude )
+{
+ this->stopBlowing(amplitude * 0.02);
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "BlowBotl::NoteOff: amplitude = " << amplitude << ".";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+void BlowBotl :: controlChange( int number, StkFloat value )
+{
+ StkFloat norm = value * ONE_OVER_128;
+ if ( norm < 0 ) {
+ norm = 0.0;
+ errorString_ << "BlowBotl::controlChange: control value less than zero ... setting to zero!";
+ handleError( StkError::WARNING );
+ }
+ else if ( norm > 1.0 ) {
+ norm = 1.0;
+ errorString_ << "BlowBotl::controlChange: control value greater than 128.0 ... setting to 128.0!";
+ handleError( StkError::WARNING );
+ }
+
+ if (number == __SK_NoiseLevel_) // 4
+ noiseGain_ = norm * 30.0;
+ else if (number == __SK_ModFrequency_) // 11
+ vibrato_.setFrequency( norm * 12.0 );
+ else if (number == __SK_ModWheel_) // 1
+ vibratoGain_ = norm * 0.4;
+ else if (number == __SK_AfterTouch_Cont_) // 128
+ adsr_.setTarget( norm );
+ else {
+ errorString_ << "BlowBotl::controlChange: undefined control number (" << number << ")!";
+ handleError( StkError::WARNING );
+ }
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "BlowBotl::controlChange: number = " << number << ", value = " << value << ".";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class BlowHole
+ \brief STK clarinet physical model with one
+ register hole and one tonehole.
+
+ This class is based on the clarinet model,
+ with the addition of a two-port register hole
+ and a three-port dynamic tonehole
+ implementation, as discussed by Scavone and
+ Cook (1998).
+
+ In this implementation, the distances between
+ the reed/register hole and tonehole/bell are
+ fixed. As a result, both the tonehole and
+ register hole will have variable influence on
+ the playing frequency, which is dependent on
+ the length of the air column. In addition,
+ the highest playing freqeuency is limited by
+ these fixed lengths.
+
+ This is a digital waveguide model, making its
+ use possibly subject to patents held by Stanford
+ University, Yamaha, and others.
+
+ Control Change Numbers:
+ - Reed Stiffness = 2
+ - Noise Gain = 4
+ - Tonehole State = 11
+ - Register State = 1
+ - Breath Pressure = 128
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "BlowHole.h"
+#include "Skini_msg.h"
+#include <cmath>
+
+namespace stk {
+
+BlowHole :: BlowHole( StkFloat lowestFrequency )
+{
+ length_ = (unsigned long) ( Stk::sampleRate() / lowestFrequency + 1 );
+ // delays[0] is the delay line between the reed and the register vent.
+ delays_[0].setDelay( 5.0 * Stk::sampleRate() / 22050.0 );
+ // delays[1] is the delay line between the register vent and the tonehole.
+ delays_[1].setMaximumDelay( length_ );
+ delays_[1].setDelay( length_ >> 1 );
+ // delays[2] is the delay line between the tonehole and the end of the bore.
+ delays_[2].setDelay( 4.0 * Stk::sampleRate() / 22050.0 );
+
+ reedTable_.setOffset( 0.7 );
+ reedTable_.setSlope( -0.3 );
+
+ // Calculate the initial tonehole three-port scattering coefficient
+ StkFloat rb = 0.0075; // main bore radius
+ StkFloat rth = 0.003; // tonehole radius
+ scatter_ = -pow(rth,2) / ( pow(rth,2) + 2*pow(rb,2) );
+
+ // Calculate tonehole coefficients and set for initially open.
+ StkFloat te = 1.4 * rth; // effective length of the open hole
+ thCoeff_ = (te*2*Stk::sampleRate() - 347.23) / (te*2*Stk::sampleRate() + 347.23);
+ tonehole_.setA1(-thCoeff_);
+ tonehole_.setB0(thCoeff_);
+ tonehole_.setB1(-1.0);
+
+ // Calculate register hole filter coefficients
+ double r_rh = 0.0015; // register vent radius
+ te = 1.4 * r_rh; // effective length of the open hole
+ double xi = 0.0; // series resistance term
+ double zeta = 347.23 + 2*PI*pow(rb,2)*xi/1.1769;
+ double psi = 2*PI*pow(rb,2)*te / (PI*pow(r_rh,2));
+ StkFloat rhCoeff = (zeta - 2 * Stk::sampleRate() * psi) / (zeta + 2 * Stk::sampleRate() * psi);
+ rhGain_ = -347.23 / (zeta + 2 * Stk::sampleRate() * psi);
+ vent_.setA1( rhCoeff );
+ vent_.setB0(1.0);
+ vent_.setB1(1.0);
+ // Start with register vent closed
+ vent_.setGain(0.0);
+
+ vibrato_.setFrequency((StkFloat) 5.735);
+ outputGain_ = 1.0;
+ noiseGain_ = 0.2;
+ vibratoGain_ = 0.01;
+}
+
+BlowHole :: ~BlowHole( void )
+{
+}
+
+void BlowHole :: clear( void )
+{
+ delays_[0].clear();
+ delays_[1].clear();
+ delays_[2].clear();
+ filter_.tick( 0.0 );
+ tonehole_.tick( 0.0 );
+ vent_.tick( 0.0 );
+}
+
+void BlowHole :: setFrequency( StkFloat frequency )
+{
+ StkFloat freakency = frequency;
+ if ( frequency <= 0.0 ) {
+ std::cerr << "BlowHole: setFrequency parameter is less than or equal to zero!" << std::endl;
+ freakency = 220.0;
+ }
+
+ // Delay = length - approximate filter delay.
+ StkFloat delay = (Stk::sampleRate() / freakency) * 0.5 - 3.5;
+ delay -= delays_[0].getDelay() + delays_[2].getDelay();
+
+ if (delay <= 0.0) delay = 0.3;
+ else if (delay > length_) delay = length_;
+ delays_[1].setDelay(delay);
+}
+
+void BlowHole :: setVent( StkFloat newValue )
+{
+ // This method allows setting of the register vent "open-ness" at
+ // any point between "Open" (newValue = 1) and "Closed"
+ // (newValue = 0).
+
+ StkFloat gain;
+
+ if (newValue <= 0.0)
+ gain = 0.0;
+ else if (newValue >= 1.0)
+ gain = rhGain_;
+ else
+ gain = newValue * rhGain_;
+
+ vent_.setGain( gain );
+}
+
+void BlowHole :: setTonehole( StkFloat newValue )
+{
+ // This method allows setting of the tonehole "open-ness" at
+ // any point between "Open" (newValue = 1) and "Closed"
+ // (newValue = 0).
+ StkFloat new_coeff;
+
+ if ( newValue <= 0.0 )
+ new_coeff = 0.9995;
+ else if ( newValue >= 1.0 )
+ new_coeff = thCoeff_;
+ else
+ new_coeff = (newValue * (thCoeff_ - 0.9995)) + 0.9995;
+
+ tonehole_.setA1( -new_coeff );
+ tonehole_.setB0( new_coeff );
+}
+
+void BlowHole :: startBlowing( StkFloat amplitude, StkFloat rate )
+{
+ envelope_.setRate( rate );
+ envelope_.setTarget( amplitude );
+}
+
+void BlowHole :: stopBlowing( StkFloat rate )
+{
+ envelope_.setRate( rate );
+ envelope_.setTarget( 0.0 );
+}
+
+void BlowHole :: noteOn( StkFloat frequency, StkFloat amplitude )
+{
+ this->setFrequency( frequency );
+ this->startBlowing( 0.55 + (amplitude * 0.30), amplitude * 0.005 );
+ outputGain_ = amplitude + 0.001;
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "BlowHole::NoteOn: frequency = " << frequency << ", amplitude = " << amplitude << ".";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+void BlowHole :: noteOff( StkFloat amplitude )
+{
+ this->stopBlowing( amplitude * 0.01 );
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "BlowHole::NoteOff: amplitude = " << amplitude << ".";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+void BlowHole :: controlChange( int number, StkFloat value )
+{
+ StkFloat norm = value * ONE_OVER_128;
+ if ( norm < 0 ) {
+ norm = 0.0;
+ errorString_ << "BlowHole::controlChange: control value less than zero ... setting to zero!";
+ handleError( StkError::WARNING );
+ }
+ else if ( norm > 1.0 ) {
+ norm = 1.0;
+ errorString_ << "BlowHole::controlChange: control value greater than 128.0 ... setting to 128.0!";
+ handleError( StkError::WARNING );
+ }
+
+ if (number == __SK_ReedStiffness_) // 2
+ reedTable_.setSlope( -0.44 + (0.26 * norm) );
+ else if (number == __SK_NoiseLevel_) // 4
+ noiseGain_ = ( norm * 0.4);
+ else if (number == __SK_ModFrequency_) // 11
+ this->setTonehole( norm );
+ else if (number == __SK_ModWheel_) // 1
+ this->setVent( norm );
+ else if (number == __SK_AfterTouch_Cont_) // 128
+ envelope_.setValue( norm );
+ else {
+ errorString_ << "BlowHole::controlChange: undefined control number (" << number << ")!";
+ handleError( StkError::WARNING );
+ }
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "BlowHole::controlChange: number = " << number << ", value = " << value << ".";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class Bowed
+ \brief STK bowed string instrument class.
+
+ This class implements a bowed string model, a
+ la Smith (1986), after McIntyre, Schumacher,
+ Woodhouse (1983).
+
+ This is a digital waveguide model, making its
+ use possibly subject to patents held by
+ Stanford University, Yamaha, and others.
+
+ Control Change Numbers:
+ - Bow Pressure = 2
+ - Bow Position = 4
+ - Vibrato Frequency = 11
+ - Vibrato Gain = 1
+ - Volume = 128
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "Bowed.h"
+#include "Skini_msg.h"
+
+namespace stk {
+
+Bowed :: Bowed( StkFloat lowestFrequency )
+{
+ unsigned long length;
+ length = (long) ( Stk::sampleRate() / lowestFrequency + 1 );
+ neckDelay_.setMaximumDelay( length );
+ neckDelay_.setDelay( 100.0 );
+
+ length >>= 1;
+ bridgeDelay_.setMaximumDelay( length );
+ bridgeDelay_.setDelay( 29.0 );
+
+ bowTable_.setSlope(3.0 );
+
+ vibrato_.setFrequency( 6.12723 );
+ vibratoGain_ = 0.0;
+
+ stringFilter_.setPole( 0.6 - (0.1 * 22050.0 / Stk::sampleRate()) );
+ stringFilter_.setGain( 0.95 );
+
+ bodyFilter_.setResonance( 500.0, 0.85, true );
+ bodyFilter_.setGain( 0.2 );
+
+ adsr_.setAllTimes( 0.02, 0.005, 0.9, 0.01 );
+
+ betaRatio_ = 0.127236;
+
+ // Necessary to initialize internal variables.
+ this->setFrequency( 220.0 );
+}
+
+Bowed :: ~Bowed( void )
+{
+}
+
+void Bowed :: clear( void )
+{
+ neckDelay_.clear();
+ bridgeDelay_.clear();
+}
+
+void Bowed :: setFrequency( StkFloat frequency )
+{
+ StkFloat freakency = frequency;
+ if ( frequency <= 0.0 ) {
+ errorString_ << "Bowed::setFrequency: parameter is less than or equal to zero!";
+ handleError( StkError::WARNING );
+ freakency = 220.0;
+ }
+
+ // Delay = length - approximate filter delay.
+ baseDelay_ = Stk::sampleRate() / freakency - 4.0;
+ if ( baseDelay_ <= 0.0 ) baseDelay_ = 0.3;
+ bridgeDelay_.setDelay( baseDelay_ * betaRatio_ ); // bow to bridge length
+ neckDelay_.setDelay( baseDelay_ * (1.0 - betaRatio_) ); // bow to nut (finger) length
+}
+
+void Bowed :: startBowing( StkFloat amplitude, StkFloat rate )
+{
+ adsr_.setAttackRate( rate );
+ adsr_.keyOn();
+ maxVelocity_ = 0.03 + ( 0.2 * amplitude );
+}
+
+void Bowed :: stopBowing( StkFloat rate )
+{
+ adsr_.setReleaseRate( rate );
+ adsr_.keyOff();
+}
+
+void Bowed :: noteOn( StkFloat frequency, StkFloat amplitude )
+{
+ this->startBowing( amplitude, amplitude * 0.001 );
+ this->setFrequency( frequency );
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Bowed::NoteOn: frequency = " << frequency << ", amplitude = " << amplitude << ".";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+void Bowed :: noteOff( StkFloat amplitude )
+{
+ this->stopBowing( (1.0 - amplitude) * 0.005 );
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Bowed::NoteOff: amplitude = " << amplitude << ".";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+void Bowed :: setVibrato( StkFloat gain )
+{
+ vibratoGain_ = gain;
+}
+
+void Bowed :: controlChange( int number, StkFloat value )
+{
+ StkFloat norm = value * ONE_OVER_128;
+ if ( norm < 0 ) {
+ norm = 0.0;
+ errorString_ << "Bowed::controlChange: control value less than zero ... setting to zero!";
+ handleError( StkError::WARNING );
+ }
+ else if ( norm > 1.0 ) {
+ norm = 1.0;
+ errorString_ << "Bowed::controlChange: control value greater than 128.0 ... setting to 128.0!";
+ handleError( StkError::WARNING );
+ }
+
+ if (number == __SK_BowPressure_) // 2
+ bowTable_.setSlope( 5.0 - (4.0 * norm) );
+ else if (number == __SK_BowPosition_) { // 4
+ betaRatio_ = 0.027236 + (0.2 * norm);
+ bridgeDelay_.setDelay( baseDelay_ * betaRatio_ );
+ neckDelay_.setDelay( baseDelay_ * (1.0 - betaRatio_) );
+ }
+ else if (number == __SK_ModFrequency_) // 11
+ vibrato_.setFrequency( norm * 12.0 );
+ else if (number == __SK_ModWheel_) // 1
+ vibratoGain_ = ( norm * 0.4 );
+ else if (number == __SK_AfterTouch_Cont_) // 128
+ adsr_.setTarget(norm);
+ else {
+ errorString_ << "Bowed::controlChange: undefined control number (" << number << ")!";
+ handleError( StkError::WARNING );
+ }
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Bowed::controlChange: number = " << number << ", value = " << value << ".";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class Brass
+ \brief STK simple brass instrument class.
+
+ This class implements a simple brass instrument
+ waveguide model, a la Cook (TBone, HosePlayer).
+
+ This is a digital waveguide model, making its
+ use possibly subject to patents held by
+ Stanford University, Yamaha, and others.
+
+ Control Change Numbers:
+ - Lip Tension = 2
+ - Slide Length = 4
+ - Vibrato Frequency = 11
+ - Vibrato Gain = 1
+ - Volume = 128
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "Brass.h"
+#include "Skini_msg.h"
+#include <cmath>
+
+namespace stk {
+
+Brass :: Brass( StkFloat lowestFrequency )
+{
+ length_ = (unsigned long) ( Stk::sampleRate() / lowestFrequency + 1 );
+ delayLine_.setMaximumDelay( length_ );
+ delayLine_.setDelay( 0.5 * length_ );
+
+ lipFilter_.setGain( 0.03 );
+ dcBlock_.setBlockZero();
+
+ adsr_.setAllTimes( 0.005, 0.001, 1.0, 0.010 );
+
+ vibrato_.setFrequency( 6.137 );
+ vibratoGain_ = 0.0;
+
+ this->clear();
+ maxPressure_ = 0.0;
+ lipTarget_ = 0.0;
+
+ // This is necessary to initialize variables.
+ this->setFrequency( 220.0 );
+}
+
+Brass :: ~Brass( void )
+{
+}
+
+void Brass :: clear( void )
+{
+ delayLine_.clear();
+ lipFilter_.clear();
+ dcBlock_.clear();
+}
+
+void Brass :: setFrequency( StkFloat frequency )
+{
+ StkFloat freakency = frequency;
+ if ( frequency <= 0.0 ) {
+ errorString_ << "Brass::setFrequency: parameter is less than or equal to zero!";
+ handleError( StkError::WARNING );
+ freakency = 220.0;
+ }
+
+ // Fudge correction for filter delays.
+ slideTarget_ = (Stk::sampleRate() / freakency * 2.0) + 3.0;
+ delayLine_.setDelay( slideTarget_ ); // play a harmonic
+
+ lipTarget_ = freakency;
+ lipFilter_.setResonance( freakency, 0.997 );
+}
+
+void Brass :: setLip( StkFloat frequency )
+{
+ StkFloat freakency = frequency;
+ if ( frequency <= 0.0 ) {
+ errorString_ << "Brass::setLip: parameter is less than or equal to zero!";
+ handleError( StkError::WARNING );
+ freakency = 220.0;
+ }
+
+ lipFilter_.setResonance( freakency, 0.997 );
+}
+
+void Brass :: startBlowing( StkFloat amplitude, StkFloat rate )
+{
+ adsr_.setAttackRate( rate );
+ maxPressure_ = amplitude;
+ adsr_.keyOn();
+}
+
+void Brass :: stopBlowing( StkFloat rate )
+{
+ adsr_.setReleaseRate( rate );
+ adsr_.keyOff();
+}
+
+void Brass :: noteOn( StkFloat frequency, StkFloat amplitude )
+{
+ this->setFrequency( frequency );
+ this->startBlowing( amplitude, amplitude * 0.001 );
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Brass::NoteOn: frequency = " << frequency << ", amplitude = " << amplitude << ".";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+void Brass :: noteOff( StkFloat amplitude )
+{
+ this->stopBlowing( amplitude * 0.005 );
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Brass::NoteOff: amplitude = " << amplitude << ".";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+void Brass :: controlChange( int number, StkFloat value )
+{
+ StkFloat norm = value * ONE_OVER_128;
+ if ( norm < 0 ) {
+ norm = 0.0;
+ errorString_ << "Brass::controlChange: control value less than zero ... setting to zero!";
+ handleError( StkError::WARNING );
+ }
+ else if ( norm > 1.0 ) {
+ norm = 1.0;
+ errorString_ << "Brass::controlChange: control value greater than 128.0 ... setting to 128.0!";
+ handleError( StkError::WARNING );
+ }
+
+ if (number == __SK_LipTension_) { // 2
+ StkFloat temp = lipTarget_ * pow( 4.0, (2.0 * norm) - 1.0 );
+ this->setLip(temp);
+ }
+ else if (number == __SK_SlideLength_) // 4
+ delayLine_.setDelay( slideTarget_ * (0.5 + norm) );
+ else if (number == __SK_ModFrequency_) // 11
+ vibrato_.setFrequency( norm * 12.0 );
+ else if (number == __SK_ModWheel_ ) // 1
+ vibratoGain_ = norm * 0.4;
+ else if (number == __SK_AfterTouch_Cont_) // 128
+ adsr_.setTarget( norm );
+ else {
+ errorString_ << "Brass::controlChange: undefined control number (" << number << ")!";
+ handleError( StkError::WARNING );
+ }
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Brass::controlChange: number = " << number << ", value = " << value << ".";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class Chorus
+ \brief STK chorus effect class.
+
+ This class implements a chorus effect. It takes a monophonic
+ input signal and produces a stereo output signal.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "Chorus.h"
+
+namespace stk {
+
+Chorus :: Chorus( StkFloat baseDelay )
+{
+ lastFrame_.resize( 1, 2, 0.0 ); // resize lastFrame_ for stereo output
+ delayLine_[0].setMaximumDelay( (unsigned long) (baseDelay * 1.414) + 2);
+ delayLine_[0].setDelay( baseDelay );
+ delayLine_[1].setMaximumDelay( (unsigned long) (baseDelay * 1.414) + 2);
+ delayLine_[1].setDelay( baseDelay );
+ baseLength_ = baseDelay;
+
+ mods_[0].setFrequency( 0.2 );
+ mods_[1].setFrequency( 0.222222 );
+ modDepth_ = 0.05;
+ effectMix_ = 0.5;
+ this->clear();
+}
+
+void Chorus :: clear( void )
+{
+ delayLine_[0].clear();
+ delayLine_[1].clear();
+ lastFrame_[0] = 0.0;
+ lastFrame_[1] = 0.0;
+}
+
+void Chorus :: setModFrequency( StkFloat frequency )
+{
+ mods_[0].setFrequency( frequency );
+ mods_[1].setFrequency( frequency * 1.1111 );
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class Clarinet
+ \brief STK clarinet physical model class.
+
+ This class implements a simple clarinet
+ physical model, as discussed by Smith (1986),
+ McIntyre, Schumacher, Woodhouse (1983), and
+ others.
+
+ This is a digital waveguide model, making its
+ use possibly subject to patents held by Stanford
+ University, Yamaha, and others.
+
+ Control Change Numbers:
+ - Reed Stiffness = 2
+ - Noise Gain = 4
+ - Vibrato Frequency = 11
+ - Vibrato Gain = 1
+ - Breath Pressure = 128
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "Clarinet.h"
+#include "Skini_msg.h"
+
+namespace stk {
+
+Clarinet :: Clarinet( StkFloat lowestFrequency )
+{
+ length_ = (long) (Stk::sampleRate() / lowestFrequency + 1);
+ delayLine_.setMaximumDelay( length_ );
+ delayLine_.setDelay( length_ / 2.0 );
+ reedTable_.setOffset((StkFloat) 0.7);
+ reedTable_.setSlope((StkFloat) -0.3);
+
+ vibrato_.setFrequency((StkFloat) 5.735);
+ outputGain_ = (StkFloat) 1.0;
+ noiseGain_ = (StkFloat) 0.2;
+ vibratoGain_ = (StkFloat) 0.1;
+}
+
+Clarinet :: ~Clarinet( void )
+{
+}
+
+void Clarinet :: clear( void )
+{
+ delayLine_.clear();
+ filter_.tick( 0.0 );
+}
+
+void Clarinet :: setFrequency( StkFloat frequency )
+{
+ StkFloat freakency = frequency;
+ if ( frequency <= 0.0 ) {
+ errorString_ << "Clarinet::setFrequency: parameter is less than or equal to zero!";
+ handleError( StkError::WARNING );
+ freakency = 220.0;
+ }
+
+ // Delay = length - approximate filter delay.
+ StkFloat delay = (Stk::sampleRate() / freakency) * 0.5 - 1.5;
+ if (delay <= 0.0) delay = 0.3;
+ else if (delay > length_) delay = length_;
+ delayLine_.setDelay(delay);
+}
+
+void Clarinet :: startBlowing( StkFloat amplitude, StkFloat rate )
+{
+ envelope_.setRate(rate);
+ envelope_.setTarget(amplitude);
+}
+
+void Clarinet :: stopBlowing( StkFloat rate )
+{
+ envelope_.setRate(rate);
+ envelope_.setTarget((StkFloat) 0.0);
+}
+
+void Clarinet :: noteOn( StkFloat frequency, StkFloat amplitude )
+{
+ this->setFrequency(frequency);
+ this->startBlowing((StkFloat) 0.55 + (amplitude * (StkFloat) 0.30), amplitude * (StkFloat) 0.005);
+ outputGain_ = amplitude + (StkFloat) 0.001;
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Clarinet::NoteOn: frequency = " << frequency << ", amplitude = " << amplitude << '.';
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+void Clarinet :: noteOff( StkFloat amplitude )
+{
+ this->stopBlowing( amplitude * 0.01 );
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Clarinet::NoteOff: amplitude = " << amplitude << '.';
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+void Clarinet :: controlChange( int number, StkFloat value )
+{
+ StkFloat norm = value * ONE_OVER_128;
+ if ( norm < 0 ) {
+ norm = 0.0;
+ errorString_ << "Clarinet::controlChange: control value less than zero ... setting to zero!";
+ handleError( StkError::WARNING );
+ }
+ else if ( norm > 1.0 ) {
+ norm = 1.0;
+ errorString_ << "Clarinet::controlChange: control value greater than 128.0 ... setting to 128.0!";
+ handleError( StkError::WARNING );
+ }
+
+ if (number == __SK_ReedStiffness_) // 2
+ reedTable_.setSlope((StkFloat) -0.44 + ( (StkFloat) 0.26 * norm ));
+ else if (number == __SK_NoiseLevel_) // 4
+ noiseGain_ = (norm * (StkFloat) 0.4);
+ else if (number == __SK_ModFrequency_) // 11
+ vibrato_.setFrequency((norm * (StkFloat) 12.0));
+ else if (number == __SK_ModWheel_) // 1
+ vibratoGain_ = (norm * (StkFloat) 0.5);
+ else if (number == __SK_AfterTouch_Cont_) // 128
+ envelope_.setValue(norm);
+ else {
+ errorString_ << "Clarinet::controlChange: undefined control number (" << number << ")!";
+ handleError( StkError::WARNING );
+ }
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Clarinet::controlChange: number = " << number << ", value = " << value << '.';
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class Delay
+ \brief STK non-interpolating delay line class.
+
+ This class implements a non-interpolating digital delay-line. If
+ the delay and maximum length are not specified during
+ instantiation, a fixed maximum length of 4095 and a delay of zero
+ is set.
+
+ A non-interpolating delay line is typically used in fixed
+ delay-length applications, such as for reverberation.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "Delay.h"
+
+namespace stk {
+
+Delay :: Delay( unsigned long delay, unsigned long maxDelay )
+{
+ // Writing before reading allows delays from 0 to length-1.
+ // If we want to allow a delay of maxDelay, we need a
+ // delay-line of length = maxDelay+1.
+ if ( maxDelay < 1 ) {
+ errorString_ << "Delay::Delay: maxDelay must be > 0!\n";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+
+ if ( delay > maxDelay ) {
+ errorString_ << "Delay::Delay: maxDelay must be > than delay argument!\n";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+
+ if ( ( maxDelay + 1 ) > inputs_.size() )
+ inputs_.resize( maxDelay + 1, 1, 0.0 );
+
+ inPoint_ = 0;
+ this->setDelay( delay );
+}
+
+Delay :: ~Delay()
+{
+}
+
+void Delay :: setMaximumDelay( unsigned long delay )
+{
+ if ( delay < inputs_.size() ) return;
+
+ if ( delay < 0 ) {
+ errorString_ << "Delay::setMaximumDelay: argument (" << delay << ") less than zero!\n";
+ handleError( StkError::WARNING );
+ return;
+ }
+ else if ( delay < delay_ ) {
+ errorString_ << "Delay::setMaximumDelay: argument (" << delay << ") less than current delay setting (" << delay_ << ")!\n";
+ handleError( StkError::WARNING );
+ return;
+ }
+
+ inputs_.resize( delay + 1 );
+}
+
+void Delay :: setDelay( unsigned long delay )
+{
+ if ( delay > inputs_.size() - 1 ) { // The value is too big.
+ errorString_ << "Delay::setDelay: argument (" << delay << ") too big ... setting to maximum!\n";
+ handleError( StkError::WARNING );
+
+ // Force delay to maximum length.
+ outPoint_ = inPoint_ + 1;
+ if ( outPoint_ == inputs_.size() ) outPoint_ = 0;
+ delay_ = inputs_.size() - 1;
+ }
+ else if ( delay < 0 ) {
+ errorString_ << "Delay::setDelay: argument (" << delay << ") less than zero ... setting to zero!\n";
+ handleError( StkError::WARNING );
+
+ outPoint_ = inPoint_;
+ delay_ = 0;
+ }
+ else { // read chases write
+ if ( inPoint_ >= delay ) outPoint_ = inPoint_ - delay;
+ else outPoint_ = inputs_.size() + inPoint_ - delay;
+ delay_ = delay;
+ }
+}
+
+StkFloat Delay :: energy( void ) const
+{
+ unsigned long i;
+ register StkFloat e = 0;
+ if ( inPoint_ >= outPoint_ ) {
+ for ( i=outPoint_; i<inPoint_; i++ ) {
+ register StkFloat t = inputs_[i];
+ e += t*t;
+ }
+ } else {
+ for ( i=outPoint_; i<inputs_.size(); i++ ) {
+ register StkFloat t = inputs_[i];
+ e += t*t;
+ }
+ for ( i=0; i<inPoint_; i++ ) {
+ register StkFloat t = inputs_[i];
+ e += t*t;
+ }
+ }
+ return e;
+}
+
+StkFloat Delay :: contentsAt( unsigned long tapDelay )
+{
+ long tap = inPoint_ - tapDelay - 1;
+ while ( tap < 0 ) // Check for wraparound.
+ tap += inputs_.size();
+
+ return inputs_[tap];
+}
+
+StkFloat Delay :: addTo( unsigned long tapDelay, StkFloat value )
+{
+ long tap = inPoint_ - tapDelay - 1;
+ while ( tap < 0 ) // Check for wraparound.
+ tap += inputs_.size();
+
+ return inputs_[tap]+= value;
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class DelayA
+ \brief STK allpass interpolating delay line class.
+
+ This class implements a fractional-length digital delay-line using
+ a first-order allpass filter. If the delay and maximum length are
+ not specified during instantiation, a fixed maximum length of 4095
+ and a delay of zero is set.
+
+ An allpass filter has unity magnitude gain but variable phase
+ delay properties, making it useful in achieving fractional delays
+ without affecting a signal's frequency magnitude response. In
+ order to achieve a maximally flat phase delay response, the
+ minimum delay possible in this implementation is limited to a
+ value of 0.5.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "DelayA.h"
+
+namespace stk {
+
+DelayA :: DelayA( StkFloat delay, unsigned long maxDelay )
+{
+ if ( delay < 0.5 || maxDelay < 1 ) {
+ errorString_ << "DelayA::DelayA: delay must be >= 0.5, maxDelay must be > 0!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+
+ if ( delay > (StkFloat) maxDelay ) {
+ errorString_ << "DelayA::DelayA: maxDelay must be > than delay argument!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+
+ // Writing before reading allows delays from 0 to length-1.
+ if ( maxDelay + 1 > inputs_.size() )
+ inputs_.resize( maxDelay + 1, 1, 0.0 );
+
+ inPoint_ = 0;
+ this->setDelay( delay );
+ apInput_ = 0.0;
+ doNextOut_ = true;
+}
+
+DelayA :: ~DelayA()
+{
+}
+
+void DelayA :: clear()
+{
+ for ( unsigned int i=0; i<inputs_.size(); i++ )
+ inputs_[i] = 0.0;
+ lastFrame_[0] = 0.0;
+ apInput_ = 0.0;
+}
+
+void DelayA :: setMaximumDelay( unsigned long delay )
+{
+ if ( delay < inputs_.size() ) return;
+
+ if ( delay < 0 ) {
+ errorString_ << "DelayA::setMaximumDelay: argument (" << delay << ") less than zero!\n";
+ handleError( StkError::WARNING );
+ return;
+ }
+ else if ( delay < delay_ ) {
+ errorString_ << "DelayA::setMaximumDelay: argument (" << delay << ") less than current delay setting (" << delay_ << ")!\n";
+ handleError( StkError::WARNING );
+ return;
+ }
+
+ inputs_.resize( delay + 1 );
+}
+
+void DelayA :: setDelay( StkFloat delay )
+{
+ StkFloat outPointer;
+ unsigned long length = inputs_.size();
+
+ if ( delay + 1 > length ) { // The value is too big.
+ errorString_ << "DelayA::setDelay: argument (" << delay << ") too big ... setting to maximum!";
+ handleError( StkError::WARNING );
+
+ // Force delay to maxLength
+ outPointer = inPoint_ + 1.0;
+ delay_ = length - 1;
+ }
+ else if ( delay < 0.5 ) {
+ errorString_ << "DelayA::setDelay: argument (" << delay << ") less than 0.5 not possible!";
+ handleError( StkError::WARNING );
+
+ outPointer = inPoint_ + 0.4999999999;
+ delay_ = 0.5;
+ }
+ else {
+ outPointer = inPoint_ - delay + 1.0; // outPoint chases inpoint
+ delay_ = delay;
+ }
+
+ while ( outPointer < 0 )
+ outPointer += length; // modulo maximum length
+
+ outPoint_ = (long) outPointer; // integer part
+ if ( outPoint_ == length ) outPoint_ = 0;
+ alpha_ = 1.0 + outPoint_ - outPointer; // fractional part
+
+ if ( alpha_ < 0.5 ) {
+ // The optimal range for alpha is about 0.5 - 1.5 in order to
+ // achieve the flattest phase delay response.
+ outPoint_ += 1;
+ if (outPoint_ >= length) outPoint_ -= length;
+ alpha_ += (StkFloat) 1.0;
+ }
+
+ coeff_ = ((StkFloat) 1.0 - alpha_) /
+ ((StkFloat) 1.0 + alpha_); // coefficient for all pass
+}
+
+StkFloat DelayA :: contentsAt( unsigned long tapDelay )
+{
+ long tap = inPoint_ - tapDelay - 1;
+ while ( tap < 0 ) // Check for wraparound.
+ tap += inputs_.size();
+
+ return inputs_[tap];
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class DelayL
+ \brief STK linear interpolating delay line class.
+
+ This class implements a fractional-length digital delay-line using
+ first-order linear interpolation. If the delay and maximum length
+ are not specified during instantiation, a fixed maximum length of
+ 4095 and a delay of zero is set.
+
+ Linear interpolation is an efficient technique for achieving
+ fractional delay lengths, though it does introduce high-frequency
+ signal attenuation to varying degrees depending on the fractional
+ delay setting. The use of higher order Lagrange interpolators can
+ typically improve (minimize) this attenuation characteristic.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "DelayL.h"
+
+namespace stk {
+
+DelayL :: DelayL( StkFloat delay, unsigned long maxDelay )
+{
+ if ( delay < 0.0 || maxDelay < 1 ) {
+ errorString_ << "DelayL::DelayL: delay must be >= 0.0, maxDelay must be > 0!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+
+ if ( delay > (StkFloat) maxDelay ) {
+ errorString_ << "DelayL::DelayL: maxDelay must be > than delay argument!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+
+ // Writing before reading allows delays from 0 to length-1.
+ if ( maxDelay + 1 > inputs_.size() )
+ inputs_.resize( maxDelay + 1, 1, 0.0 );
+
+ inPoint_ = 0;
+ this->setDelay( delay );
+ doNextOut_ = true;
+}
+
+DelayL :: ~DelayL()
+{
+}
+
+void DelayL :: setMaximumDelay( unsigned long delay )
+{
+ if ( delay < inputs_.size() ) return;
+
+ if ( delay < 0 ) {
+ errorString_ << "DelayL::setMaximumDelay: argument (" << delay << ") less than zero!\n";
+ handleError( StkError::WARNING );
+ return;
+ }
+ else if ( delay < delay_ ) {
+ errorString_ << "DelayL::setMaximumDelay: argument (" << delay << ") less than current delay setting (" << delay_ << ")!\n";
+ handleError( StkError::WARNING );
+ return;
+ }
+
+ inputs_.resize( delay + 1 );
+}
+
+void DelayL :: setDelay( StkFloat delay )
+{
+ StkFloat outPointer;
+
+ if ( delay + 1 > inputs_.size() ) { // The value is too big.
+ errorString_ << "DelayL::setDelay: argument (" << delay << ") too big ... setting to maximum!";
+ handleError( StkError::WARNING );
+
+ // Force delay to maxLength
+ outPointer = inPoint_ + 1.0;
+ delay_ = inputs_.size() - 1;
+ }
+ else if (delay < 0 ) {
+ errorString_ << "DelayL::setDelay: argument (" << delay << ") less than zero ... setting to zero!";
+ handleError( StkError::WARNING );
+
+ outPointer = inPoint_;
+ delay_ = 0;
+ }
+ else {
+ outPointer = inPoint_ - delay; // read chases write
+ delay_ = delay;
+ }
+
+ while (outPointer < 0)
+ outPointer += inputs_.size(); // modulo maximum length
+
+ outPoint_ = (long) outPointer; // integer part
+ if ( outPoint_ == inputs_.size() ) outPoint_ = 0;
+ alpha_ = outPointer - outPoint_; // fractional part
+ omAlpha_ = (StkFloat) 1.0 - alpha_;
+}
+
+StkFloat DelayL :: contentsAt( unsigned long tapDelay )
+{
+ long tap = inPoint_ - tapDelay - 1;
+ while ( tap < 0 ) // Check for wraparound.
+ tap += inputs_.size();
+
+ return inputs_[tap];
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class Drummer
+ \brief STK drum sample player class.
+
+ This class implements a drum sampling
+ synthesizer using FileWvIn objects and one-pole
+ filters. The drum rawwave files are sampled
+ at 22050 Hz, but will be appropriately
+ interpolated for other sample rates. You can
+ specify the maximum polyphony (maximum number
+ of simultaneous voices) via a #define in the
+ Drummer.h.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "Drummer.h"
+#include <cmath>
+
+namespace stk {
+
+// Not really General MIDI yet.
+unsigned char genMIDIMap[128] =
+ { 0,0,0,0,0,0,0,0, // 0-7
+ 0,0,0,0,0,0,0,0, // 8-15
+ 0,0,0,0,0,0,0,0, // 16-23
+ 0,0,0,0,0,0,0,0, // 24-31
+ 0,0,0,0,1,0,2,0, // 32-39
+ 2,3,6,3,6,4,7,4, // 40-47
+ 5,8,5,0,0,0,10,0, // 48-55
+ 9,0,0,0,0,0,0,0, // 56-63
+ 0,0,0,0,0,0,0,0, // 64-71
+ 0,0,0,0,0,0,0,0, // 72-79
+ 0,0,0,0,0,0,0,0, // 80-87
+ 0,0,0,0,0,0,0,0, // 88-95
+ 0,0,0,0,0,0,0,0, // 96-103
+ 0,0,0,0,0,0,0,0, // 104-111
+ 0,0,0,0,0,0,0,0, // 112-119
+ 0,0,0,0,0,0,0,0 // 120-127
+ };
+
+char waveNames[DRUM_NUMWAVES][16] =
+ {
+ "dope.raw",
+ "bassdrum.raw",
+ "snardrum.raw",
+ "tomlowdr.raw",
+ "tommiddr.raw",
+ "tomhidrm.raw",
+ "hihatcym.raw",
+ "ridecymb.raw",
+ "crashcym.raw",
+ "cowbell1.raw",
+ "tambourn.raw"
+ };
+
+Drummer :: Drummer( void ) : Instrmnt()
+{
+ // This counts the number of sounding voices.
+ nSounding_ = 0;
+ soundOrder_ = std::vector<int> (DRUM_POLYPHONY, -1);
+ soundNumber_ = std::vector<int> (DRUM_POLYPHONY, -1);
+}
+
+Drummer :: ~Drummer( void )
+{
+}
+
+void Drummer :: noteOn( StkFloat instrument, StkFloat amplitude )
+{
+#if defined(_STK_DEBUG_)
+ errorString_ << "Drummer::NoteOn: instrument = " << instrument << ", amplitude = " << amplitude << '.';
+ handleError( StkError::DEBUG_WARNING );
+#endif
+
+ StkFloat gain = amplitude;
+ if ( amplitude > 1.0 ) {
+ errorString_ << "Drummer::noteOn: amplitude parameter is greater than 1.0 ... setting to 1.0!";
+ handleError( StkError::WARNING );
+ gain = 1.0;
+ }
+ else if ( amplitude < 0.0 ) {
+ errorString_ << "Drummer::noteOn: amplitude parameter is less than 0.0 ... doing nothing!";
+ handleError( StkError::WARNING );
+ return;
+ }
+
+ // Yes, this is tres kludgey.
+ //int noteNumber = (int) ( ( 12 * log( instrument / 220.0 ) / log( 2.0 ) ) + 57.01 );
+
+ int noteNumber = (int) ( instrument + .1 );
+
+ if( (noteNumber < 0) || (noteNumber >= DRUM_NUMWAVES) ) // MoMu Modified
+ noteNumber = 0;
+
+ // If we already have a wave of this note number loaded, just reset
+ // it. Otherwise, look first for an unused wave or preempt the
+ // oldest if already at maximum polyphony.
+ int iWave;
+ for ( iWave=0; iWave<DRUM_POLYPHONY; iWave++ ) {
+ if ( soundNumber_[iWave] == noteNumber ) {
+ if ( waves_[iWave].isFinished() ) {
+ soundOrder_[iWave] = nSounding_;
+ nSounding_++;
+ }
+ waves_[iWave].reset();
+ filters_[iWave].setPole( 0.999 - (gain * 0.6) );
+ filters_[iWave].setGain( gain );
+ break;
+ }
+ }
+
+ if ( iWave == DRUM_POLYPHONY ) { // This note number is not currently loaded.
+ if ( nSounding_ < DRUM_POLYPHONY ) {
+ for ( iWave=0; iWave<DRUM_POLYPHONY; iWave++ )
+ if ( soundOrder_[iWave] < 0 ) break;
+ nSounding_ += 1;
+ }
+ else { // interrupt oldest voice
+ for ( iWave=0; iWave<DRUM_POLYPHONY; iWave++ )
+ if ( soundOrder_[iWave] == 0 ) break;
+ // Re-order the list.
+ for ( int j=0; j<DRUM_POLYPHONY; j++ ) {
+ if ( soundOrder_[j] > soundOrder_[iWave] )
+ soundOrder_[j] -= 1;
+ }
+ }
+ soundOrder_[iWave] = nSounding_ - 1;
+ soundNumber_[iWave] = noteNumber;
+ std::cout << "iWave = " << iWave << ", nSounding = " << nSounding_ << ", soundOrder[] = " << soundOrder_[iWave] << std::endl;
+
+ // Concatenate the STK rawwave path to the rawwave file
+
+ std::cout<<Stk::rawwavePath()<<std::endl;
+ std::cout<<(Stk::rawwavePath() + waveNames[ noteNumber ]).c_str()<<std::endl;
+
+ waves_[iWave].openFile( (Stk::rawwavePath() + waveNames[ noteNumber ]).c_str(), true );
+ if ( Stk::sampleRate() != 22050.0 )
+ waves_[iWave].setRate( 22050.0 / Stk::sampleRate() );
+ filters_[iWave].setPole( 0.999 - (gain * 0.6) );
+ filters_[iWave].setGain( gain );
+ }
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Drummer::noteOn: number sounding = " << nSounding_ << ", notes: ";
+ for ( int i=0; i<nSounding_; i++ ) errorString_ << soundNumber_[i] << " ";
+ errorString_ << '\n';
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+void Drummer :: noteOff( StkFloat amplitude )
+{
+ // Set all sounding wave filter gains low.
+ int i = 0;
+ while ( i < nSounding_ ) filters_[i++].setGain( amplitude * 0.01 );
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class Echo
+ \brief STK echo effect class.
+
+ This class implements an echo effect.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "Echo.h"
+#include <iostream>
+
+namespace stk {
+
+Echo :: Echo( unsigned long maximumDelay ) : Effect()
+{
+ this->setMaximumDelay( maximumDelay );
+ delayLine_.setDelay( length_ >> 1 );
+ effectMix_ = 0.5;
+ this->clear();
+}
+
+void Echo :: clear( void )
+{
+ delayLine_.clear();
+ lastFrame_[0] = 0.0;
+}
+
+void Echo :: setMaximumDelay( unsigned long delay )
+{
+ length_ = delay;
+ if ( delay == 0 ) {
+ errorString_ << "Echo::setMaximumDelay: parameter cannot be zero ... setting to 10!";
+ handleError( StkError::WARNING );
+ length_ = 10;
+ }
+
+ delayLine_.setMaximumDelay( length_ );
+}
+
+void Echo :: setDelay( unsigned long delay )
+{
+ unsigned long size = delay;
+ if ( delay > length_ ) {
+ errorString_ << "Echo::setDelay: parameter is greater than maximum delay length ... setting to max!";
+ handleError( StkError::WARNING );
+ size = length_;
+ }
+
+ delayLine_.setDelay( size );
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class Envelope
+ \brief STK linear line envelope class.
+
+ This class implements a simple linear line envelope generator
+ which is capable of ramping to an arbitrary target value by a
+ specified \e rate. It also responds to simple \e keyOn and \e
+ keyOff messages, ramping to 1.0 on keyOn and to 0.0 on keyOff.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "Envelope.h"
+
+namespace stk {
+
+Envelope :: Envelope( void ) : Generator()
+{
+ target_ = 0.0;
+ value_ = 0.0;
+ rate_ = 0.001;
+ state_ = 0;
+ Stk::addSampleRateAlert( this );
+}
+
+Envelope :: ~Envelope( void )
+{
+ Stk::removeSampleRateAlert( this );
+}
+
+Envelope& Envelope :: operator= ( const Envelope& e )
+{
+ if ( this != &e ) {
+ target_ = e.target_;
+ value_ = e.value_;
+ rate_ = e.rate_;
+ state_ = e.state_;
+ }
+
+ return *this;
+}
+
+void Envelope :: sampleRateChanged( StkFloat newRate, StkFloat oldRate )
+{
+ if ( !ignoreSampleRateChange_ )
+ rate_ = oldRate * rate_ / newRate;
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class FM
+ \brief STK abstract FM synthesis base class.
+
+ This class controls an arbitrary number of
+ waves and envelopes, determined via a
+ constructor argument.
+
+ Control Change Numbers:
+ - Control One = 2
+ - Control Two = 4
+ - LFO Speed = 11
+ - LFO Depth = 1
+ - ADSR 2 & 4 Target = 128
+
+ The basic Chowning/Stanford FM patent expired
+ in 1995, but there exist follow-on patents,
+ mostly assigned to Yamaha. If you are of the
+ type who should worry about this (making
+ money) worry away.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "FM.h"
+#include "Skini_msg.h"
+
+namespace stk {
+
+FM :: FM( unsigned int operators )
+ : nOperators_(operators)
+{
+ if ( nOperators_ == 0 ) {
+ errorString_ << "FM: Invalid number of operators (" << operators << ") argument to constructor!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+
+ twozero_.setB2( -1.0 );
+ twozero_.setGain( 0.0 );
+
+ vibrato_.setFrequency( 6.0 );
+
+ unsigned int j;
+ adsr_.resize( nOperators_ );
+ waves_.resize( nOperators_ );
+ for (j=0; j<nOperators_; j++ ) {
+ ratios_.push_back( 1.0 );
+ gains_.push_back( 1.0 );
+ adsr_[j] = new ADSR();
+ }
+
+ modDepth_ = 0.0;
+ control1_ = 1.0;
+ control2_ = 1.0;
+ baseFrequency_ = 440.0;
+
+ int i;
+ StkFloat temp = 1.0;
+ for (i=99; i>=0; i--) {
+ fmGains_[i] = temp;
+ temp *= 0.933033;
+ }
+
+ temp = 1.0;
+ for (i=15; i>=0; i--) {
+ fmSusLevels_[i] = temp;
+ temp *= 0.707101;
+ }
+
+ temp = 8.498186;
+ for (i=0; i<32; i++) {
+ fmAttTimes_[i] = temp;
+ temp *= 0.707101;
+ }
+}
+
+FM :: ~FM( void )
+{
+ for (unsigned int i=0; i<nOperators_; i++ ) {
+ delete waves_[i];
+ delete adsr_[i];
+ }
+}
+
+void FM :: loadWaves( const char **filenames )
+{
+ for (unsigned int i=0; i<nOperators_; i++ )
+ waves_[i] = new FileLoop( filenames[i], true );
+}
+
+void FM :: setFrequency( StkFloat frequency )
+{
+ baseFrequency_ = frequency;
+
+ for ( unsigned int i=0; i<nOperators_; i++ )
+ waves_[i]->setFrequency( baseFrequency_ * ratios_[i] );
+}
+
+void FM :: setRatio( unsigned int waveIndex, StkFloat ratio )
+{
+ if ( waveIndex < 0 ) {
+ errorString_ << "FM::setRatio: waveIndex parameter is less than zero!";
+ handleError( StkError::WARNING );
+ return;
+ }
+ else if ( waveIndex >= nOperators_ ) {
+ errorString_ << "FM:setRatio: waveIndex parameter is greater than the number of operators!";
+ handleError( StkError::WARNING );
+ return;
+ }
+
+ ratios_[waveIndex] = ratio;
+ if (ratio > 0.0)
+ waves_[waveIndex]->setFrequency( baseFrequency_ * ratio );
+ else
+ waves_[waveIndex]->setFrequency( ratio );
+}
+
+void FM :: setGain( unsigned int waveIndex, StkFloat gain )
+{
+ if ( waveIndex < 0 ) {
+ errorString_ << "FM::setGain: waveIndex parameter is less than zero!";
+ handleError( StkError::WARNING );
+ return;
+ }
+ else if ( waveIndex >= nOperators_ ) {
+ errorString_ << "FM::setGain: waveIndex parameter is greater than the number of operators!";
+ handleError( StkError::WARNING );
+ return;
+ }
+
+ gains_[waveIndex] = gain;
+}
+
+void FM :: keyOn( void )
+{
+ for ( unsigned int i=0; i<nOperators_; i++ )
+ adsr_[i]->keyOn();
+}
+
+void FM :: keyOff( void )
+{
+ for ( unsigned int i=0; i<nOperators_; i++ )
+ adsr_[i]->keyOff();
+}
+
+void FM :: noteOff( StkFloat amplitude )
+{
+ this->keyOff();
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "FM::NoteOff: amplitude = " << amplitude << ".";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+void FM :: controlChange( int number, StkFloat value )
+{
+ StkFloat norm = value * ONE_OVER_128;
+ if ( norm < 0 ) {
+ norm = 0.0;
+ errorString_ << "FM::controlChange: control value less than zero ... setting to zero!";
+ handleError( StkError::WARNING );
+ }
+ else if ( norm > 1.0 ) {
+ norm = 1.0;
+ errorString_ << "FM::controlChange: control value greater than 128.0 ... setting to 128.0!";
+ handleError( StkError::WARNING );
+ }
+
+ if (number == __SK_Breath_) // 2
+ this->setControl1( norm );
+ else if (number == __SK_FootControl_) // 4
+ this->setControl2( norm );
+ else if (number == __SK_ModFrequency_) // 11
+ this->setModulationSpeed( norm * 12.0);
+ else if (number == __SK_ModWheel_) // 1
+ this->setModulationDepth( norm );
+ else if (number == __SK_AfterTouch_Cont_) { // 128
+ //adsr_[0]->setTarget( norm );
+ adsr_[1]->setTarget( norm );
+ //adsr_[2]->setTarget( norm );
+ adsr_[3]->setTarget( norm );
+ }
+ else {
+ errorString_ << "FM::controlChange: undefined control number (" << number << ")!";
+ handleError( StkError::WARNING );
+ }
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "FM::controlChange: number = " << number << ", value = " << value << '.';
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class FMVoices
+ \brief STK singing FM synthesis instrument.
+
+ This class implements 3 carriers and a common
+ modulator, also referred to as algorithm 6 of
+ the TX81Z.
+
+ \code
+ Algorithm 6 is :
+ /->1 -\
+ 4-|-->2 - +-> Out
+ \->3 -/
+ \endcode
+
+ Control Change Numbers:
+ - Vowel = 2
+ - Spectral Tilt = 4
+ - LFO Speed = 11
+ - LFO Depth = 1
+ - ADSR 2 & 4 Target = 128
+
+ The basic Chowning/Stanford FM patent expired
+ in 1995, but there exist follow-on patents,
+ mostly assigned to Yamaha. If you are of the
+ type who should worry about this (making
+ money) worry away.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "FMVoices.h"
+#include "Skini_msg.h"
+#include "Phonemes.h"
+
+namespace stk {
+
+FMVoices :: FMVoices( void )
+ : FM()
+{
+ // Concatenate the STK rawwave path to the rawwave files
+ for ( unsigned int i=0; i<3; i++ )
+ waves_[i] = new FileLoop( (Stk::rawwavePath() + "sinewave.raw").c_str(), true );
+ waves_[3] = new FileLoop( (Stk::rawwavePath() + "fwavblnk.raw").c_str(), true );
+
+ this->setRatio(0, 2.00);
+ this->setRatio(1, 4.00);
+ this->setRatio(2, 12.0);
+ this->setRatio(3, 1.00);
+
+ gains_[3] = fmGains_[80];
+
+ adsr_[0]->setAllTimes( 0.05, 0.05, fmSusLevels_[15], 0.05);
+ adsr_[1]->setAllTimes( 0.05, 0.05, fmSusLevels_[15], 0.05);
+ adsr_[2]->setAllTimes( 0.05, 0.05, fmSusLevels_[15], 0.05);
+ adsr_[3]->setAllTimes( 0.01, 0.01, fmSusLevels_[15], 0.5);
+
+ twozero_.setGain( 0.0 );
+ modDepth_ = (StkFloat) 0.005;
+ currentVowel_ = 0;
+ tilt_[0] = 1.0;
+ tilt_[1] = 0.5;
+ tilt_[2] = 0.2;
+ mods_[0] = 1.0;
+ mods_[1] = 1.1;
+ mods_[2] = 1.1;
+ baseFrequency_ = 110.0;
+ this->setFrequency( 110.0 );
+}
+
+FMVoices :: ~FMVoices( void )
+{
+}
+
+void FMVoices :: setFrequency( StkFloat frequency )
+{
+ StkFloat temp, temp2 = 0.0;
+ int tempi = 0;
+ unsigned int i = 0;
+
+ if (currentVowel_ < 32) {
+ i = currentVowel_;
+ temp2 = 0.9;
+ }
+ else if (currentVowel_ < 64) {
+ i = currentVowel_ - 32;
+ temp2 = 1.0;
+ }
+ else if (currentVowel_ < 96) {
+ i = currentVowel_ - 64;
+ temp2 = 1.1;
+ }
+ else if (currentVowel_ <= 128) {
+ i = currentVowel_ - 96;
+ temp2 = 1.2;
+ }
+
+ baseFrequency_ = frequency;
+ temp = (temp2 * Phonemes::formantFrequency(i, 0) / baseFrequency_) + 0.5;
+ tempi = (int) temp;
+ this->setRatio( 0, (StkFloat) tempi );
+ temp = (temp2 * Phonemes::formantFrequency(i, 1) / baseFrequency_) + 0.5;
+ tempi = (int) temp;
+ this->setRatio( 1, (StkFloat) tempi );
+ temp = (temp2 * Phonemes::formantFrequency(i, 2) / baseFrequency_) + 0.5;
+ tempi = (int) temp;
+ this->setRatio( 2, (StkFloat) tempi );
+ gains_[0] = 1.0;
+ gains_[1] = 1.0;
+ gains_[2] = 1.0;
+}
+
+void FMVoices :: noteOn( StkFloat frequency, StkFloat amplitude )
+{
+ this->setFrequency( frequency );
+ tilt_[0] = amplitude;
+ tilt_[1] = amplitude * amplitude;
+ tilt_[2] = tilt_[1] * amplitude;
+ this->keyOn();
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "FMVoices::NoteOn: frequency = " << frequency << ", amplitude = " << amplitude << '.';
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+void FMVoices :: controlChange( int number, StkFloat value )
+{
+ StkFloat norm = value * ONE_OVER_128;
+ if ( norm < 0 ) {
+ norm = 0.0;
+ errorString_ << "FMVoices::controlChange: control value less than zero ... setting to zero!";
+ handleError( StkError::WARNING );
+ }
+ else if ( norm > 1.0 ) {
+ norm = 1.0;
+ errorString_ << "FMVoices::controlChange: control value greater than 128.0 ... setting to 128.0!";
+ handleError( StkError::WARNING );
+ }
+
+
+ if (number == __SK_Breath_) // 2
+ gains_[3] = fmGains_[(int) ( norm * 99.9 )];
+ else if (number == __SK_FootControl_) { // 4
+ currentVowel_ = (int) (norm * 128.0);
+ this->setFrequency(baseFrequency_);
+ }
+ else if (number == __SK_ModFrequency_) // 11
+ this->setModulationSpeed( norm * 12.0);
+ else if (number == __SK_ModWheel_) // 1
+ this->setModulationDepth( norm );
+ else if (number == __SK_AfterTouch_Cont_) { // 128
+ tilt_[0] = norm;
+ tilt_[1] = norm * norm;
+ tilt_[2] = tilt_[1] * norm;
+ }
+ else {
+ errorString_ << "FMVoices::controlChange: undefined control number (" << number << ")!";
+ handleError( StkError::WARNING );
+ }
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "FMVoices::controlChange: number = " << number << ", value = " << value << '.';
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class FileLoop
+ \brief STK file looping / oscillator class.
+
+ This class provides audio file looping functionality. Any audio
+ file that can be loaded by FileRead can be looped using this
+ class.
+
+ FileLoop supports multi-channel data. It is important to
+ distinguish the tick() method that computes a single frame (and
+ returns only the specified sample of a multi-channel frame) from
+ the overloaded one that takes an StkFrames object for
+ multi-channel and/or multi-frame data.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "FileLoop.h"
+#include <cmath>
+
+namespace stk {
+
+FileLoop :: FileLoop( unsigned long chunkThreshold, unsigned long chunkSize )
+ : FileWvIn( chunkThreshold, chunkSize ), phaseOffset_(0.0)
+{
+ Stk::addSampleRateAlert( this );
+}
+
+FileLoop :: FileLoop( std::string fileName, bool raw, bool doNormalize,
+ unsigned long chunkThreshold, unsigned long chunkSize )
+ : FileWvIn( chunkThreshold, chunkSize ), phaseOffset_(0.0)
+{
+ this->openFile( fileName, raw, doNormalize );
+ Stk::addSampleRateAlert( this );
+}
+
+FileLoop :: ~FileLoop( void )
+{
+ Stk::removeSampleRateAlert( this );
+}
+
+void FileLoop :: openFile( std::string fileName, bool raw, bool doNormalize )
+{
+ // Call close() in case another file is already open.
+ this->closeFile();
+
+ // Attempt to open the file ... an error might be thrown here.
+ file_.open( fileName, raw );
+
+ // Determine whether chunking or not.
+ if ( file_.fileSize() > chunkThreshold_ ) {
+ chunking_ = true;
+ chunkPointer_ = 0;
+ data_.resize( chunkSize_ + 1, file_.channels() );
+ if ( doNormalize ) normalizing_ = true;
+ else normalizing_ = false;
+ }
+ else {
+ chunking_ = false;
+ data_.resize( file_.fileSize() + 1, file_.channels() );
+ }
+
+ // Load all or part of the data.
+ file_.read( data_, 0, doNormalize );
+
+ if ( chunking_ ) { // If chunking, save the first sample frame for later.
+ firstFrame_.resize( 1, data_.channels() );
+ for ( unsigned int i=0; i<data_.channels(); i++ )
+ firstFrame_[i] = data_[i];
+ }
+ else { // If not chunking, copy the first sample frame to the last.
+ for ( unsigned int i=0; i<data_.channels(); i++ )
+ data_( data_.frames() - 1, i ) = data_[i];
+ }
+
+ // Resize our lastOutputs container.
+ lastFrame_.resize( 1, file_.channels() );
+
+ // Set default rate based on file sampling rate.
+ this->setRate( data_.dataRate() / Stk::sampleRate() );
+
+ if ( doNormalize & !chunking_ ) this->normalize();
+
+ this->reset();
+}
+
+void FileLoop :: setRate( StkFloat rate )
+{
+ rate_ = rate;
+
+ if ( fmod( rate_, 1.0 ) != 0.0 ) interpolate_ = true;
+ else interpolate_ = false;
+}
+
+void FileLoop :: addTime( StkFloat time )
+{
+ // Add an absolute time in samples.
+ time_ += time;
+
+ StkFloat fileSize = file_.fileSize();
+ while ( time_ < 0.0 )
+ time_ += fileSize;
+ while ( time_ >= fileSize )
+ time_ -= fileSize;
+}
+
+void FileLoop :: addPhase( StkFloat angle )
+{
+ // Add a time in cycles (one cycle = fileSize).
+ StkFloat fileSize = file_.fileSize();
+ time_ += fileSize * angle;
+
+ while ( time_ < 0.0 )
+ time_ += fileSize;
+ while ( time_ >= fileSize )
+ time_ -= fileSize;
+}
+
+void FileLoop :: addPhaseOffset( StkFloat angle )
+{
+ // Add a phase offset in cycles, where 1.0 = fileSize.
+ phaseOffset_ = file_.fileSize() * angle;
+}
+
+StkFloat FileLoop :: tick( unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel >= data_.channels() ) {
+ errorString_ << "FileLoop::tick(): channel argument and soundfile data are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ // Check limits of time address ... if necessary, recalculate modulo
+ // fileSize.
+ StkFloat fileSize = file_.fileSize();
+
+ while ( time_ < 0.0 )
+ time_ += fileSize;
+ while ( time_ >= fileSize )
+ time_ -= fileSize;
+
+ StkFloat tyme = time_;
+ if ( phaseOffset_ ) {
+ tyme += phaseOffset_;
+ while ( tyme < 0.0 )
+ tyme += fileSize;
+ while ( tyme >= fileSize )
+ tyme -= fileSize;
+ }
+
+ if ( chunking_ ) {
+
+ // Check the time address vs. our current buffer limits.
+ if ( ( time_ < (StkFloat) chunkPointer_ ) ||
+ ( time_ > (StkFloat) ( chunkPointer_ + chunkSize_ - 1 ) ) ) {
+
+ while ( time_ < (StkFloat) chunkPointer_ ) { // negative rate
+ chunkPointer_ -= chunkSize_ - 1; // overlap chunks by one frame
+ if ( chunkPointer_ < 0 ) chunkPointer_ = 0;
+ }
+ while ( time_ > (StkFloat) ( chunkPointer_ + chunkSize_ - 1 ) ) { // positive rate
+ chunkPointer_ += chunkSize_ - 1; // overlap chunks by one frame
+ if ( chunkPointer_ + chunkSize_ > file_.fileSize() ) { // at end of file
+ chunkPointer_ = file_.fileSize() - chunkSize_ + 1; // leave extra frame at end of buffer
+ // Now fill extra frame with first frame data.
+ for ( unsigned int j=0; j<firstFrame_.channels(); j++ )
+ data_( data_.frames() - 1, j ) = firstFrame_[j];
+ }
+ }
+
+ // Load more data.
+ file_.read( data_, chunkPointer_, normalizing_ );
+ }
+
+ // Adjust index for the current buffer.
+ tyme -= chunkPointer_;
+ }
+
+ if ( interpolate_ ) {
+ for ( unsigned int i=0; i<lastFrame_.size(); i++ )
+ lastFrame_[i] = data_.interpolate( tyme, i );
+ }
+ else {
+ for ( unsigned int i=0; i<lastFrame_.size(); i++ )
+ lastFrame_[i] = data_( (size_t) tyme, i );
+ }
+
+ // Increment time, which can be negative.
+ time_ += rate_;
+
+ return lastFrame_[channel];
+}
+
+StkFrames& FileLoop :: tick( StkFrames& frames )
+{
+ if ( !file_.isOpen() ) {
+#if defined(_STK_DEBUG_)
+ errorString_ << "FileLoop::tick(): no file data is loaded!";
+ handleError( StkError::WARNING );
+#endif
+ return frames;
+ }
+
+ unsigned int nChannels = lastFrame_.channels();
+#if defined(_STK_DEBUG_)
+ if ( nChannels != frames.channels() ) {
+ errorString_ << "FileLoop::tick(): StkFrames argument is incompatible with file data!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ unsigned int j, counter = 0;
+ for ( unsigned int i=0; i<frames.frames(); i++ ) {
+ this->tick();
+ for ( j=0; j<nChannels; j++ )
+ frames[counter++] = lastFrame_[j];
+ }
+
+ return frames;
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class FileRead
+ \brief STK audio file input class.
+
+ This class provides input support for various
+ audio file formats. Multi-channel (>2)
+ soundfiles are supported. The file data is
+ returned via an external StkFrames object
+ passed to the read() function. This class
+ does not store its own copy of the file data,
+ rather the data is read directly from disk.
+
+ FileRead currently supports uncompressed WAV,
+ AIFF/AIFC, SND (AU), MAT-file (Matlab), and
+ STK RAW file formats. Signed integer (8-,
+ 16-, and 32-bit) and floating-point (32- and
+ 64-bit) data types are supported. Compressed
+ data types are not supported.
+
+ STK RAW files have no header and are assumed
+ to contain a monophonic stream of 16-bit
+ signed integers in big-endian byte order at a
+ sample rate of 22050 Hz. MAT-file data should
+ be saved in an array with each data channel
+ filling a matrix row. The sample rate for
+ MAT-files is assumed to be 44100 Hz.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
+*/
+/***************************************************/
+
+#include "FileRead.h"
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <cstring>
+#include <cmath>
+#include <cstdio>
+
+namespace stk {
+
+FileRead :: FileRead()
+ : fd_(0)
+{
+}
+
+FileRead :: FileRead( std::string fileName, bool typeRaw, unsigned int nChannels,
+ StkFormat format, StkFloat rate )
+ : fd_(0)
+{
+ open( fileName, typeRaw, nChannels, format, rate );
+}
+
+FileRead :: ~FileRead()
+{
+ if ( fd_ )
+ fclose( fd_ );
+}
+
+void FileRead :: close( void )
+{
+ if ( fd_ ) fclose( fd_ );
+ fd_ = 0;
+ wavFile_ = false;
+}
+
+bool FileRead :: isOpen( void )
+{
+ if ( fd_ ) return true;
+ else return false;
+}
+
+void FileRead :: open( std::string fileName, bool typeRaw, unsigned int nChannels,
+ StkFormat format, StkFloat rate )
+{
+ // If another file is open, close it.
+ close();
+
+ // Try to open the file.
+ fd_ = fopen( fileName.c_str(), "rb" );
+ if ( !fd_ ) {
+ errorString_ << "FileRead::open: could not open or find file (" << fileName << ")!";
+ handleError( StkError::FILE_NOT_FOUND );
+ }
+
+ // Attempt to determine file type from header (unless RAW).
+ bool result = false;
+ if ( typeRaw )
+ result = getRawInfo( fileName.c_str(), nChannels, format, rate );
+ else {
+ char header[12];
+ if ( fread( &header, 4, 3, fd_ ) != 3 ) goto error;
+ if ( !strncmp( header, "RIFF", 4 ) &&
+ !strncmp( &header[8], "WAVE", 4 ) )
+ result = getWavInfo( fileName.c_str() );
+ else if ( !strncmp( header, ".snd", 4 ) )
+ result = getSndInfo( fileName.c_str() );
+ else if ( !strncmp( header, "FORM", 4 ) &&
+ ( !strncmp( &header[8], "AIFF", 4 ) || !strncmp(&header[8], "AIFC", 4) ) )
+ result = getAifInfo( fileName.c_str() );
+ else {
+ if ( fseek( fd_, 126, SEEK_SET ) == -1 ) goto error;
+ if ( fread( &header, 2, 1, fd_ ) != 1 ) goto error;
+ if ( !strncmp( header, "MI", 2 ) ||
+ !strncmp( header, "IM", 2 ) )
+ result = getMatInfo( fileName.c_str() );
+ else {
+ errorString_ << "FileRead::open: file (" << fileName << ") format unknown.";
+ handleError( StkError::FILE_UNKNOWN_FORMAT );
+ }
+ }
+ }
+
+ // If here, we had a file type candidate but something else went wrong.
+ if ( result == false )
+ handleError( StkError::FILE_ERROR );
+
+ // Check for empty files.
+ if ( fileSize_ == 0 ) {
+ errorString_ << "FileRead::open: file (" << fileName << ") data size is zero!";
+ handleError( StkError::FILE_ERROR );
+ }
+
+ return;
+
+ error:
+ errorString_ << "FileRead::open: error reading file (" << fileName << ")!";
+ handleError( StkError::FILE_ERROR );
+}
+
+bool FileRead :: getRawInfo( const char *fileName, unsigned int nChannels, StkFormat format, StkFloat rate )
+{
+ // Use the system call "stat" to determine the file length.
+ struct stat filestat;
+ if ( stat(fileName, &filestat) == -1 ) {
+ errorString_ << "FileRead: Could not stat RAW file (" << fileName << ").";
+ return false;
+ }
+
+ // Rawwave files have no header and by default, are assumed to
+ // contain a monophonic stream of 16-bit signed integers in
+ // big-endian byte order at a sample rate of 22050 Hz. However,
+ // different parameters can be specified if desired.
+ dataOffset_ = 0;
+ channels_ = nChannels;
+ dataType_ = format;
+ fileRate_ = rate;
+ int sampleBytes = 0;
+ if ( format == STK_SINT8 ) sampleBytes = 1;
+ else if ( format == STK_SINT16 ) sampleBytes = 2;
+ else if ( format == STK_SINT32 || format == STK_FLOAT32 ) sampleBytes = 4;
+ else if ( format == STK_FLOAT64 ) sampleBytes = 8;
+
+ fileSize_ = (long) filestat.st_size / sampleBytes / channels_; // length in frames
+
+ byteswap_ = false;
+#ifdef __LITTLE_ENDIAN__
+ byteswap_ = true;
+#endif
+
+ return true;
+}
+
+bool FileRead :: getWavInfo( const char *fileName )
+{
+ // Find "format" chunk ... it must come before the "data" chunk.
+ char id[4];
+ SINT32 chunkSize;
+ if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
+ while ( strncmp(id, "fmt ", 4) ) {
+ if ( fread(&chunkSize, 4, 1, fd_) != 1 ) goto error;
+#ifndef __LITTLE_ENDIAN__
+ swap32((unsigned char *)&chunkSize);
+#endif
+ if ( fseek(fd_, chunkSize, SEEK_CUR) == -1 ) goto error;
+ if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
+ }
+
+ // Check that the data is not compressed.
+ unsigned short format_tag;
+ if ( fread(&chunkSize, 4, 1, fd_) != 1 ) goto error; // Read fmt chunk size.
+ if ( fread(&format_tag, 2, 1, fd_) != 1 ) goto error;
+#ifndef __LITTLE_ENDIAN__
+ swap16((unsigned char *)&format_tag);
+ swap32((unsigned char *)&chunkSize);
+#endif
+ if ( format_tag == 0xFFFE ) { // WAVE_FORMAT_EXTENSIBLE
+ dataOffset_ = ftell(fd_);
+ if ( fseek(fd_, 14, SEEK_CUR) == -1 ) goto error;
+ unsigned short extSize;
+ if ( fread(&extSize, 2, 1, fd_) != 1 ) goto error;
+#ifndef __LITTLE_ENDIAN__
+ swap16((unsigned char *)&extSize);
+#endif
+ if ( extSize == 0 ) goto error;
+ if ( fseek(fd_, 6, SEEK_CUR) == -1 ) goto error;
+ if ( fread(&format_tag, 2, 1, fd_) != 1 ) goto error;
+#ifndef __LITTLE_ENDIAN__
+ swap16((unsigned char *)&format_tag);
+#endif
+ if ( fseek(fd_, dataOffset_, SEEK_SET) == -1 ) goto error;
+ }
+ if (format_tag != 1 && format_tag != 3 ) { // PCM = 1, FLOAT = 3
+ errorString_ << "FileRead: "<< fileName << " contains an unsupported data format type (" << format_tag << ").";
+ return false;
+ }
+
+ // Get number of channels from the header.
+ SINT16 temp;
+ if ( fread(&temp, 2, 1, fd_) != 1 ) goto error;
+#ifndef __LITTLE_ENDIAN__
+ swap16((unsigned char *)&temp);
+#endif
+ channels_ = (unsigned int ) temp;
+
+ // Get file sample rate from the header.
+ SINT32 srate;
+ if ( fread(&srate, 4, 1, fd_) != 1 ) goto error;
+#ifndef __LITTLE_ENDIAN__
+ swap32((unsigned char *)&srate);
+#endif
+ fileRate_ = (StkFloat) srate;
+
+ // Determine the data type.
+ dataType_ = 0;
+ if ( fseek(fd_, 6, SEEK_CUR) == -1 ) goto error; // Locate bits_per_sample info.
+ if ( fread(&temp, 2, 1, fd_) != 1 ) goto error;
+#ifndef __LITTLE_ENDIAN__
+ swap16((unsigned char *)&temp);
+#endif
+ if ( format_tag == 1 ) {
+ if (temp == 8)
+ dataType_ = STK_SINT8;
+ else if (temp == 16)
+ dataType_ = STK_SINT16;
+ else if (temp == 32)
+ dataType_ = STK_SINT32;
+ }
+ else if ( format_tag == 3 ) {
+ if (temp == 32)
+ dataType_ = STK_FLOAT32;
+ else if (temp == 64)
+ dataType_ = STK_FLOAT64;
+ }
+ if ( dataType_ == 0 ) {
+ errorString_ << "FileRead: " << temp << " bits per sample with data format " << format_tag << " are not supported (" << fileName << ").";
+ return false;
+ }
+
+ // Jump over any remaining part of the "fmt" chunk.
+ if ( fseek(fd_, chunkSize-16, SEEK_CUR) == -1 ) goto error;
+
+ // Find "data" chunk ... it must come after the "fmt" chunk.
+ if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
+
+ while ( strncmp(id, "data", 4) ) {
+ if ( fread(&chunkSize, 4, 1, fd_) != 1 ) goto error;
+#ifndef __LITTLE_ENDIAN__
+ swap32((unsigned char *)&chunkSize);
+#endif
+ chunkSize += chunkSize % 2; // chunk sizes must be even
+ if ( fseek(fd_, chunkSize, SEEK_CUR) == -1 ) goto error;
+ if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
+ }
+
+ // Get length of data from the header.
+ SINT32 bytes;
+ if ( fread(&bytes, 4, 1, fd_) != 1 ) goto error;
+#ifndef __LITTLE_ENDIAN__
+ swap32((unsigned char *)&bytes);
+#endif
+ fileSize_ = 8 * bytes / temp / channels_; // sample frames
+
+ dataOffset_ = ftell(fd_);
+ byteswap_ = false;
+#ifndef __LITTLE_ENDIAN__
+ byteswap_ = true;
+#endif
+
+ wavFile_ = true;
+ return true;
+
+ error:
+ errorString_ << "FileRead: error reading WAV file (" << fileName << ").";
+ return false;
+}
+
+bool FileRead :: getSndInfo( const char *fileName )
+{
+ // Determine the data type.
+ UINT32 format;
+ if ( fseek(fd_, 12, SEEK_SET) == -1 ) goto error; // Locate format
+ if ( fread(&format, 4, 1, fd_) != 1 ) goto error;
+#ifdef __LITTLE_ENDIAN__
+ swap32((unsigned char *)&format);
+#endif
+ if (format == 2) dataType_ = STK_SINT8;
+ else if (format == 3) dataType_ = STK_SINT16;
+ else if (format == 4) dataType_ = STK_SINT24;
+ else if (format == 5) dataType_ = STK_SINT32;
+ else if (format == 6) dataType_ = STK_FLOAT32;
+ else if (format == 7) dataType_ = STK_FLOAT64;
+ else {
+ errorString_ << "FileRead: data format in file " << fileName << " is not supported.";
+ return false;
+ }
+
+ // Get file sample rate from the header.
+ UINT32 srate;
+ if ( fread(&srate, 4, 1, fd_) != 1 ) goto error;
+#ifdef __LITTLE_ENDIAN__
+ swap32((unsigned char *)&srate);
+#endif
+ fileRate_ = (StkFloat) srate;
+
+ // Get number of channels from the header.
+ UINT32 chans;
+ if ( fread(&chans, 4, 1, fd_) != 1 ) goto error;
+#ifdef __LITTLE_ENDIAN__
+ swap32((unsigned char *)&chans);
+#endif
+ channels_ = chans;
+
+ if ( fseek(fd_, 4, SEEK_SET) == -1 ) goto error;
+ if ( fread(&dataOffset_, 4, 1, fd_) != 1 ) goto error;
+#ifdef __LITTLE_ENDIAN__
+ swap32((unsigned char *)&dataOffset_);
+#endif
+
+ // Get length of data from the header.
+ if ( fread(&fileSize_, 4, 1, fd_) != 1 ) goto error;
+#ifdef __LITTLE_ENDIAN__
+ swap32((unsigned char *)&fileSize_);
+#endif
+ // Convert to sample frames.
+ if ( dataType_ == STK_SINT8 )
+ fileSize_ /= channels_;
+ if ( dataType_ == STK_SINT16 )
+ fileSize_ /= 2 * channels_;
+ else if ( dataType_ == STK_SINT24 )
+ fileSize_ /= 3 * channels_;
+ else if ( dataType_ == STK_SINT32 || dataType_ == STK_FLOAT32 )
+ fileSize_ /= 4 * channels_;
+ else if ( dataType_ == STK_FLOAT64 )
+ fileSize_ /= 8 * channels_;
+
+ byteswap_ = false;
+#ifdef __LITTLE_ENDIAN__
+ byteswap_ = true;
+#endif
+
+ return true;
+
+ error:
+ errorString_ << "FileRead: Error reading SND file (" << fileName << ").";
+ return false;
+}
+
+bool FileRead :: getAifInfo( const char *fileName )
+{
+ bool aifc = false;
+ char id[4];
+
+ // Determine whether this is AIFF or AIFC.
+ if ( fseek(fd_, 8, SEEK_SET) == -1 ) goto error;
+ if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
+ if ( !strncmp(id, "AIFC", 4) ) aifc = true;
+
+ // Find "common" chunk
+ SINT32 chunkSize;
+ if ( fread(&id, 4, 1, fd_) != 1) goto error;
+ while ( strncmp(id, "COMM", 4) ) {
+ if ( fread(&chunkSize, 4, 1, fd_) != 1 ) goto error;
+#ifdef __LITTLE_ENDIAN__
+ swap32((unsigned char *)&chunkSize);
+#endif
+ chunkSize += chunkSize % 2; // chunk sizes must be even
+ if ( fseek(fd_, chunkSize, SEEK_CUR) == -1 ) goto error;
+ if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
+ }
+
+ // Get number of channels from the header.
+ SINT16 temp;
+ if ( fseek(fd_, 4, SEEK_CUR) == -1 ) goto error; // Jump over chunk size
+ if ( fread(&temp, 2, 1, fd_) != 1 ) goto error;
+#ifdef __LITTLE_ENDIAN__
+ swap16((unsigned char *)&temp);
+#endif
+ channels_ = temp;
+
+ // Get length of data from the header.
+ SINT32 frames;
+ if ( fread(&frames, 4, 1, fd_) != 1 ) goto error;
+#ifdef __LITTLE_ENDIAN__
+ swap32((unsigned char *)&frames);
+#endif
+ fileSize_ = frames; // sample frames
+
+ // Read the number of bits per sample.
+ if ( fread(&temp, 2, 1, fd_) != 1 ) goto error;
+#ifdef __LITTLE_ENDIAN__
+ swap16((unsigned char *)&temp);
+#endif
+
+ // Get file sample rate from the header. For AIFF files, this value
+ // is stored in a 10-byte, IEEE Standard 754 floating point number,
+ // so we need to convert it first.
+ unsigned char srate[10];
+ unsigned char exp;
+ unsigned long mantissa;
+ unsigned long last;
+ if ( fread(&srate, 10, 1, fd_) != 1 ) goto error;
+ mantissa = (unsigned long) *(unsigned long *)(srate+2);
+#ifdef __LITTLE_ENDIAN__
+ swap32((unsigned char *)&mantissa);
+#endif
+ exp = 30 - *(srate+1);
+ last = 0;
+ while (exp--) {
+ last = mantissa;
+ mantissa >>= 1;
+ }
+ if (last & 0x00000001) mantissa++;
+ fileRate_ = (StkFloat) mantissa;
+
+ // Determine the data format.
+ dataType_ = 0;
+ if ( aifc == false ) {
+ if ( temp <= 8 ) dataType_ = STK_SINT8;
+ else if ( temp <= 16 ) dataType_ = STK_SINT16;
+ else if ( temp <= 24 ) dataType_ = STK_SINT24;
+ else if ( temp <= 32 ) dataType_ = STK_SINT32;
+ }
+ else {
+ if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
+ if ( !strncmp(id, "NONE", 4) ) {
+ if ( temp <= 8 ) dataType_ = STK_SINT8;
+ else if ( temp <= 16 ) dataType_ = STK_SINT16;
+ else if ( temp <= 24 ) dataType_ = STK_SINT24;
+ else if ( temp <= 32 ) dataType_ = STK_SINT32;
+ }
+ else if ( (!strncmp(id, "fl32", 4) || !strncmp(id, "FL32", 4)) && temp == 32 ) dataType_ = STK_FLOAT32;
+ else if ( (!strncmp(id, "fl64", 4) || !strncmp(id, "FL64", 4)) && temp == 64 ) dataType_ = STK_FLOAT64;
+ }
+ if ( dataType_ == 0 ) {
+ errorString_ << "FileRead: AIFF/AIFC file (" << fileName << ") has unsupported data type (" << id << ").";
+ return false;
+ }
+
+ // Start at top to find data (SSND) chunk ... chunk order is undefined.
+ if ( fseek(fd_, 12, SEEK_SET) == -1 ) goto error;
+
+ // Find data (SSND) chunk
+ if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
+ while ( strncmp(id, "SSND", 4) ) {
+ if ( fread(&chunkSize, 4, 1, fd_) != 1 ) goto error;
+#ifdef __LITTLE_ENDIAN__
+ swap32((unsigned char *)&chunkSize);
+#endif
+ chunkSize += chunkSize % 2; // chunk sizes must be even
+ if ( fseek(fd_, chunkSize, SEEK_CUR) == -1 ) goto error;
+ if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
+ }
+
+ // Skip over chunk size, offset, and blocksize fields
+ if ( fseek(fd_, 12, SEEK_CUR) == -1 ) goto error;
+
+ dataOffset_ = ftell(fd_);
+ byteswap_ = false;
+#ifdef __LITTLE_ENDIAN__
+ byteswap_ = true;
+#endif
+
+ return true;
+
+ error:
+ errorString_ << "FileRead: Error reading AIFF file (" << fileName << ").";
+ return false;
+}
+
+bool FileRead :: getMatInfo( const char *fileName )
+{
+ // MAT-file formatting information is available at:
+ // http://www.mathworks.com/access/helpdesk/help/pdf_doc/matlab/matfile_format.pdf
+
+ // Verify this is a version 5 MAT-file format.
+ char head[5];
+ if ( fseek(fd_, 0, SEEK_SET) == -1 ) goto error;
+ if ( fread(&head, 4, 1, fd_) != 1 ) goto error;
+ // If any of the first 4 characters of the header = 0, then this is
+ // a Version 4 MAT-file.
+ head[4] = '\0';
+ if ( strstr(head, "0") ) {
+ errorString_ << "FileRead: " << fileName << " appears to be a Version 4 MAT-file, which is not currently supported.";
+ return false;
+ }
+
+ // Determine the endian-ness of the file.
+ char mi[2];
+ byteswap_ = false;
+ // Locate "M" and "I" characters in header.
+ if ( fseek(fd_, 126, SEEK_SET) == -1 ) goto error;
+ if ( fread(&mi, 2, 1, fd_) != 1) goto error;
+#ifdef __LITTLE_ENDIAN__
+ if ( !strncmp(mi, "MI", 2) )
+ byteswap_ = true;
+ else if ( strncmp(mi, "IM", 2) ) goto error;
+#else
+ if ( !strncmp(mi, "IM", 2))
+ byteswap_ = true;
+ else if ( strncmp(mi, "MI", 2) ) goto error;
+#endif
+
+ // Check the data element type
+ SINT32 datatype;
+ if ( fread(&datatype, 4, 1, fd_) != 1 ) goto error;
+ if ( byteswap_ ) swap32((unsigned char *)&datatype);
+ if (datatype != 14) {
+ errorString_ << "FileRead: The file does not contain a single Matlab array (or matrix) data element.";
+ return false;
+ }
+
+ // Determine the array data type.
+ SINT32 tmp;
+ SINT32 size;
+ if ( fseek(fd_, 168, SEEK_SET) == -1 ) goto error;
+ if ( fread(&tmp, 4, 1, fd_) != 1 ) goto error;
+ if (byteswap_) swap32((unsigned char *)&tmp);
+ if (tmp == 1) { // array name > 4 characters
+ if ( fread(&tmp, 4, 1, fd_) != 1 ) goto error; // get array name length
+ if (byteswap_) swap32((unsigned char *)&tmp);
+ size = (SINT32) ceil((float)tmp / 8);
+ if ( fseek(fd_, size*8, SEEK_CUR) == -1 ) goto error; // jump over array name
+ }
+ else { // array name <= 4 characters, compressed data element
+ if ( fseek(fd_, 4, SEEK_CUR) == -1 ) goto error;
+ }
+ if ( fread(&tmp, 4, 1, fd_) != 1 ) goto error;
+ if (byteswap_) swap32((unsigned char *)&tmp);
+ if ( tmp == 1 ) dataType_ = STK_SINT8;
+ else if ( tmp == 3 ) dataType_ = STK_SINT16;
+ else if ( tmp == 5 ) dataType_ = STK_SINT32;
+ else if ( tmp == 7 ) dataType_ = STK_FLOAT32;
+ else if ( tmp == 9 ) dataType_ = STK_FLOAT64;
+ else {
+ errorString_ << "FileRead: The MAT-file array data format (" << tmp << ") is not supported.";
+ return false;
+ }
+
+ // Get number of rows from the header.
+ SINT32 rows;
+ if ( fseek(fd_, 160, SEEK_SET) == -1 ) goto error;
+ if ( fread(&rows, 4, 1, fd_) != 1 ) goto error;
+ if (byteswap_) swap32((unsigned char *)&rows);
+
+ // Get number of columns from the header.
+ SINT32 columns;
+ if ( fread(&columns, 4, 1, fd_) != 1 ) goto error;
+ if (byteswap_) swap32((unsigned char *)&columns);
+
+ // Assume channels = smaller of rows or columns.
+ if (rows < columns) {
+ channels_ = rows;
+ fileSize_ = columns;
+ }
+ else {
+ errorString_ << "FileRead: Transpose the MAT-file array so that audio channels fill matrix rows (not columns).";
+ return false;
+ }
+
+ // Move read pointer to the data in the file.
+ SINT32 headsize;
+ if ( fseek(fd_, 132, SEEK_SET) == -1 ) goto error;
+ if ( fread(&headsize, 4, 1, fd_) != 1 ) goto error; // file size from 132nd byte
+ if (byteswap_) swap32((unsigned char *)&headsize);
+ headsize -= fileSize_ * 8 * channels_;
+ if ( fseek(fd_, headsize, SEEK_CUR) == -1 ) goto error;
+ dataOffset_ = ftell(fd_);
+
+ // Assume MAT-files have 44100 Hz sample rate.
+ fileRate_ = 44100.0;
+
+ return true;
+
+ error:
+ errorString_ << "FileRead: Error reading MAT-file (" << fileName << ").";
+ return false;
+}
+
+void FileRead :: read( StkFrames& buffer, unsigned long startFrame, bool doNormalize )
+{
+ // Make sure we have an open file.
+ if ( fd_ == 0 ) {
+ errorString_ << "FileRead::read: a file is not open!";
+ Stk::handleError( StkError::WARNING );
+ return;
+ }
+
+ // Check the buffer size.
+ unsigned int nFrames = buffer.frames();
+ if ( nFrames == 0 ) {
+ errorString_ << "FileRead::read: StkFrames buffer size is zero ... no data read!";
+ Stk::handleError( StkError::WARNING );
+ return;
+ }
+
+ if ( buffer.channels() != channels_ ) {
+ errorString_ << "FileRead::read: StkFrames argument has incompatible number of channels!";
+ Stk::handleError( StkError::FUNCTION_ARGUMENT );
+ }
+
+ // Check for file end.
+ if ( startFrame + nFrames >= fileSize_ )
+ nFrames = fileSize_ - startFrame;
+
+ long i, nSamples = (long) ( nFrames * channels_ );
+ unsigned long offset = startFrame * channels_;
+
+ // Read samples into StkFrames data buffer.
+ if ( dataType_ == STK_SINT16 ) {
+ SINT16 *buf = (SINT16 *) &buffer[0];
+ if ( fseek( fd_, dataOffset_+(offset*2), SEEK_SET ) == -1 ) goto error;
+ if ( fread( buf, nSamples * 2, 1, fd_ ) != 1 ) goto error;
+ if ( byteswap_ ) {
+ SINT16 *ptr = buf;
+ for ( i=nSamples-1; i>=0; i-- )
+ swap16( (unsigned char *) ptr++ );
+ }
+ if ( doNormalize ) {
+ StkFloat gain = 1.0 / 32768.0;
+ for ( i=nSamples-1; i>=0; i-- )
+ buffer[i] = buf[i] * gain;
+ }
+ else {
+ for ( i=nSamples-1; i>=0; i-- )
+ buffer[i] = buf[i];
+ }
+ }
+ else if ( dataType_ == STK_SINT32 ) {
+ SINT32 *buf = (SINT32 *) &buffer[0];
+ if ( fseek( fd_, dataOffset_+(offset*4 ), SEEK_SET ) == -1 ) goto error;
+ if ( fread( buf, nSamples * 4, 1, fd_ ) != 1 ) goto error;
+ if ( byteswap_ ) {
+ SINT32 *ptr = buf;
+ for ( i=nSamples-1; i>=0; i-- )
+ swap32( (unsigned char *) ptr++ );
+ }
+ if ( doNormalize ) {
+ StkFloat gain = 1.0 / 2147483648.0;
+ for ( i=nSamples-1; i>=0; i-- )
+ buffer[i] = buf[i] * gain;
+ }
+ else {
+ for ( i=nSamples-1; i>=0; i-- )
+ buffer[i] = buf[i];
+ }
+ }
+ else if ( dataType_ == STK_FLOAT32 ) {
+ FLOAT32 *buf = (FLOAT32 *) &buffer[0];
+ if ( fseek( fd_, dataOffset_+(offset*4), SEEK_SET ) == -1 ) goto error;
+ if ( fread( buf, nSamples * 4, 1, fd_ ) != 1 ) goto error;
+ if ( byteswap_ ) {
+ FLOAT32 *ptr = buf;
+ for ( i=nSamples-1; i>=0; i-- )
+ swap32( (unsigned char *) ptr++ );
+ }
+ for ( i=nSamples-1; i>=0; i-- )
+ buffer[i] = buf[i];
+ }
+ else if ( dataType_ == STK_FLOAT64 ) {
+ FLOAT64 *buf = (FLOAT64 *) &buffer[0];
+ if ( fseek( fd_, dataOffset_+(offset*8), SEEK_SET ) == -1 ) goto error;
+ if ( fread( buf, nSamples * 8, 1, fd_ ) != 1 ) goto error;
+ if ( byteswap_ ) {
+ FLOAT64 *ptr = buf;
+ for ( i=nSamples-1; i>=0; i-- )
+ swap64( (unsigned char *) ptr++ );
+ }
+ for ( i=nSamples-1; i>=0; i-- )
+ buffer[i] = buf[i];
+ }
+ else if ( dataType_ == STK_SINT8 && wavFile_ ) { // 8-bit WAV data is unsigned!
+ unsigned char *buf = (unsigned char *) &buffer[0];
+ if ( fseek( fd_, dataOffset_+offset, SEEK_SET ) == -1 ) goto error;
+ if ( fread( buf, nSamples, 1, fd_) != 1 ) goto error;
+ if ( doNormalize ) {
+ StkFloat gain = 1.0 / 128.0;
+ for ( i=nSamples-1; i>=0; i-- )
+ buffer[i] = ( buf[i] - 128 ) * gain;
+ }
+ else {
+ for ( i=nSamples-1; i>=0; i-- )
+ buffer[i] = buf[i] - 128.0;
+ }
+ }
+ else if ( dataType_ == STK_SINT8 ) { // signed 8-bit data
+ char *buf = (char *) &buffer[0];
+ if ( fseek( fd_, dataOffset_+offset, SEEK_SET ) == -1 ) goto error;
+ if ( fread( buf, nSamples, 1, fd_ ) != 1 ) goto error;
+ if ( doNormalize ) {
+ StkFloat gain = 1.0 / 128.0;
+ for ( i=nSamples-1; i>=0; i-- )
+ buffer[i] = buf[i] * gain;
+ }
+ else {
+ for ( i=nSamples-1; i>=0; i-- )
+ buffer[i] = buf[i];
+ }
+ }
+ else if ( dataType_ == STK_SINT24 ) {
+ // 24-bit values are harder to import efficiently since there is
+ // no native 24-bit type. The following routine works but is much
+ // less efficient that that used for the other data types.
+ SINT32 buf;
+ StkFloat gain = 1.0 / 8388608.0;
+ if ( fseek(fd_, dataOffset_+(offset*3), SEEK_SET ) == -1 ) goto error;
+ for ( i=0; i<nSamples; i++ ) {
+ if ( fread( &buf, 3, 1, fd_ ) != 1 ) goto error;
+ buf >>= 8;
+ if ( byteswap_ )
+ swap32( (unsigned char *) &buf );
+ if ( doNormalize )
+ buffer[i] = buf * gain;
+ else
+ buffer[i] = buf;
+ }
+ }
+
+ buffer.setDataRate( fileRate_ );
+
+ return;
+
+ error:
+ errorString_ << "FileRead: Error reading file data.";
+ handleError( StkError::FILE_ERROR);
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class FileWrite
+ \brief STK audio file output class.
+
+ This class provides output support for various
+ audio file formats.
+
+ FileWrite writes samples to an audio file. It supports
+ multi-channel data.
+
+ FileWrite currently supports uncompressed WAV, AIFF, AIFC, SND
+ (AU), MAT-file (Matlab), and STK RAW file formats. Signed integer
+ (8-, 16-, and 32-bit) and floating- point (32- and 64-bit) data
+ types are supported. STK RAW files use 16-bit integers by
+ definition. MAT-files will always be written as 64-bit floats.
+ If a data type specification does not match the specified file
+ type, the data type will automatically be modified. Compressed
+ data types are not supported.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "FileWrite.h"
+#include <cstring>
+#include <cstdio>
+#include <cmath>
+
+namespace stk {
+
+const FileWrite::FILE_TYPE FileWrite :: FILE_RAW = 1;
+const FileWrite::FILE_TYPE FileWrite :: FILE_WAV = 2;
+const FileWrite::FILE_TYPE FileWrite :: FILE_SND = 3;
+const FileWrite::FILE_TYPE FileWrite :: FILE_AIF = 4;
+const FileWrite::FILE_TYPE FileWrite :: FILE_MAT = 5;
+
+// WAV header structure. See ftp://ftp.isi.edu/in-notes/rfc2361.txt
+// for information regarding format codes.
+struct wavhdr {
+ char riff[4]; // "RIFF"
+ SINT32 file_size; // in bytes
+ char wave[4]; // "WAVE"
+ char fmt[4]; // "fmt "
+ SINT32 chunk_size; // in bytes (16 for PCM)
+ SINT16 format_tag; // 1=PCM, 2=ADPCM, 3=IEEE float, 6=A-Law, 7=Mu-Law
+ SINT16 num_chans; // 1=mono, 2=stereo
+ SINT32 sample_rate;
+ SINT32 bytes_per_sec;
+ SINT16 bytes_per_samp; // 2=16-bit mono, 4=16-bit stereo
+ SINT16 bits_per_samp;
+ char data[4]; // "data"
+ SINT32 data_length; // in bytes
+};
+
+// SND (AU) header structure (NeXT and Sun).
+struct sndhdr {
+ char pref[4];
+ SINT32 hdr_length;
+ SINT32 data_length;
+ SINT32 format;
+ SINT32 sample_rate;
+ SINT32 num_channels;
+ char comment[16];
+};
+
+// AIFF/AIFC header structure ... only the part common to both
+// formats.
+struct aifhdr {
+ char form[4]; // "FORM"
+ SINT32 form_size; // in bytes
+ char aiff[4]; // "AIFF" or "AIFC"
+ char comm[4]; // "COMM"
+ SINT32 comm_size; // "COMM" chunk size (18 for AIFF, 24 for AIFC)
+ SINT16 num_chans; // number of channels
+ unsigned long sample_frames; // sample frames of audio data
+ SINT16 sample_size; // in bits
+ unsigned char srate[10]; // IEEE 754 floating point format
+};
+
+struct aifssnd {
+ char ssnd[4]; // "SSND"
+ SINT32 ssnd_size; // "SSND" chunk size
+ unsigned long offset; // data offset in data block (should be 0)
+ unsigned long block_size; // not used by STK (should be 0)
+};
+
+// MAT-file 5 header structure.
+struct mathdr {
+ char heading[124]; // Header text field
+ SINT16 hff[2]; // Header flag fields
+ SINT32 adf[11]; // Array data format fields
+ // There's more, but it's of variable length
+};
+
+FileWrite :: FileWrite()
+ : fd_( 0 )
+{
+}
+
+FileWrite::FileWrite( std::string fileName, unsigned int nChannels, FILE_TYPE type, Stk::StkFormat format )
+ : fd_( 0 )
+{
+ this->open( fileName, nChannels, type, format );
+}
+
+FileWrite :: ~FileWrite()
+{
+ this->close();
+}
+
+void FileWrite :: close( void )
+{
+ if ( fd_ == 0 ) return;
+
+ if ( fileType_ == FILE_RAW )
+ fclose( fd_ );
+ else if ( fileType_ == FILE_WAV )
+ this->closeWavFile();
+ else if ( fileType_ == FILE_SND )
+ this->closeSndFile();
+ else if ( fileType_ == FILE_AIF )
+ this->closeAifFile();
+ else if ( fileType_ == FILE_MAT )
+ this->closeMatFile();
+
+ fd_ = 0;
+}
+
+bool FileWrite :: isOpen( void )
+{
+ if ( fd_ ) return true;
+ else return false;
+}
+
+void FileWrite :: open( std::string fileName, unsigned int nChannels, FileWrite::FILE_TYPE type, Stk::StkFormat format )
+{
+ // Call close() in case another file is already open.
+ this->close();
+
+ if ( nChannels < 1 ) {
+ errorString_ << "FileWrite::open: then channels argument must be greater than zero!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+
+ channels_ = nChannels;
+ fileType_ = type;
+
+ if ( format != STK_SINT8 && format != STK_SINT16 &&
+ format != STK_SINT32 && format != STK_FLOAT32 &&
+ format != STK_FLOAT64 ) {
+ errorString_ << "FileWrite::open: unknown data type (" << format << ") specified!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+ dataType_ = format;
+
+ bool result = false;
+ if ( fileType_ == FILE_RAW ) {
+ if ( channels_ != 1 ) {
+ errorString_ << "FileWrite::open: STK RAW files are, by definition, always monaural (channels = " << nChannels << " not supported)!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+ result = setRawFile( fileName.c_str() );
+ }
+ else if ( fileType_ == FILE_WAV )
+ result = setWavFile( fileName.c_str() );
+ else if ( fileType_ == FILE_SND )
+ result = setSndFile( fileName.c_str() );
+ else if ( fileType_ == FILE_AIF )
+ result = setAifFile( fileName.c_str() );
+ else if ( fileType_ == FILE_MAT )
+ result = setMatFile( fileName.c_str() );
+ else {
+ errorString_ << "FileWrite::open: unknown file type (" << fileType_ << ") specified!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+
+ if ( result == false )
+ handleError( StkError::FILE_ERROR );
+
+ frameCounter_ = 0;
+}
+
+bool FileWrite :: setRawFile( const char *fileName )
+{
+ char name[8192];
+ strncpy(name, fileName, 8192);
+ if ( strstr(name, ".raw") == NULL) strcat(name, ".raw");
+ fd_ = fopen(name, "wb");
+ if ( !fd_ ) {
+ errorString_ << "FileWrite: could not create RAW file: " << name << '.';
+ return false;
+ }
+
+ if ( dataType_ != STK_SINT16 ) {
+ dataType_ = STK_SINT16;
+ errorString_ << "FileWrite: using 16-bit signed integer data format for file " << name << '.';
+ handleError( StkError::DEBUG_WARNING );
+ }
+
+ byteswap_ = false;
+#ifdef __LITTLE_ENDIAN__
+ byteswap_ = true;
+#endif
+
+ errorString_ << "FileWrite: creating RAW file: " << name;
+ handleError( StkError::STATUS );
+ return true;
+}
+
+bool FileWrite :: setWavFile( const char *fileName )
+{
+ char name[8192];
+ strncpy(name, fileName, 8192);
+ if ( strstr(name, ".wav") == NULL) strcat(name, ".wav");
+ fd_ = fopen(name, "wb");
+ if ( !fd_ ) {
+ errorString_ << "FileWrite: could not create WAV file: " << name;
+ return false;
+ }
+
+ struct wavhdr hdr = {"RIF", 44, "WAV", "fmt", 16, 1, 1,
+ (SINT32) Stk::sampleRate(), 0, 2, 16, "dat", 0};
+ hdr.riff[3] = 'F';
+ hdr.wave[3] = 'E';
+ hdr.fmt[3] = ' ';
+ hdr.data[3] = 'a';
+ hdr.num_chans = (SINT16) channels_;
+ if ( dataType_ == STK_SINT8 )
+ hdr.bits_per_samp = 8;
+ else if ( dataType_ == STK_SINT16 )
+ hdr.bits_per_samp = 16;
+ else if ( dataType_ == STK_SINT32 )
+ hdr.bits_per_samp = 32;
+ else if ( dataType_ == STK_FLOAT32 ) {
+ hdr.format_tag = 3;
+ hdr.bits_per_samp = 32;
+ }
+ else if ( dataType_ == STK_FLOAT64 ) {
+ hdr.format_tag = 3;
+ hdr.bits_per_samp = 64;
+ }
+ hdr.bytes_per_samp = (SINT16) (channels_ * hdr.bits_per_samp / 8);
+ hdr.bytes_per_sec = (SINT32) (hdr.sample_rate * hdr.bytes_per_samp);
+
+ byteswap_ = false;
+#ifndef __LITTLE_ENDIAN__
+ byteswap_ = true;
+ swap32((unsigned char *)&hdr.file_size);
+ swap32((unsigned char *)&hdr.chunk_size);
+ swap16((unsigned char *)&hdr.format_tag);
+ swap16((unsigned char *)&hdr.num_chans);
+ swap32((unsigned char *)&hdr.sample_rate);
+ swap32((unsigned char *)&hdr.bytes_per_sec);
+ swap16((unsigned char *)&hdr.bytes_per_samp);
+ swap16((unsigned char *)&hdr.bits_per_samp);
+#endif
+
+ if ( fwrite(&hdr, 4, 11, fd_) != 11 ) {
+ errorString_ << "FileWrite: could not write WAV header for file " << name << '.';
+ return false;
+ }
+
+ errorString_ << "FileWrite: creating WAV file: " << name;
+ handleError( StkError::STATUS );
+ return true;
+}
+
+void FileWrite :: closeWavFile( void )
+{
+ int bytes_per_sample = 1;
+ if ( dataType_ == STK_SINT16 )
+ bytes_per_sample = 2;
+ else if ( dataType_ == STK_SINT32 || dataType_ == STK_FLOAT32 )
+ bytes_per_sample = 4;
+ else if ( dataType_ == STK_FLOAT64 )
+ bytes_per_sample = 8;
+
+ SINT32 bytes = frameCounter_ * channels_ * bytes_per_sample;
+#ifndef __LITTLE_ENDIAN__
+ swap32((unsigned char *)&bytes);
+#endif
+ fseek(fd_, 40, SEEK_SET); // jump to data length
+ fwrite(&bytes, 4, 1, fd_);
+
+ bytes = frameCounter_ * channels_ * bytes_per_sample + 44;
+#ifndef __LITTLE_ENDIAN__
+ swap32((unsigned char *)&bytes);
+#endif
+ fseek(fd_, 4, SEEK_SET); // jump to file size
+ fwrite(&bytes, 4, 1, fd_);
+ fclose( fd_ );
+}
+
+bool FileWrite :: setSndFile( const char *fileName )
+{
+ char name[8192];
+ strncpy(name, fileName, 8192);
+ if ( strstr(name, ".snd") == NULL) strcat(name, ".snd");
+ fd_ = fopen(name, "wb");
+ if ( !fd_ ) {
+ errorString_ << "FileWrite: could not create SND file: " << name;
+ return false;
+ }
+
+ struct sndhdr hdr = {".sn", 40, 0, 3, (SINT32) Stk::sampleRate(), 1, "Created by STK"};
+ hdr.pref[3] = 'd';
+ hdr.num_channels = channels_;
+ if ( dataType_ == STK_SINT8 )
+ hdr.format = 2;
+ else if ( dataType_ == STK_SINT16 )
+ hdr.format = 3;
+ else if ( dataType_ == STK_SINT32 )
+ hdr.format = 5;
+ else if ( dataType_ == STK_FLOAT32 )
+ hdr.format = 6;
+ else if ( dataType_ == STK_FLOAT64 )
+ hdr.format = 7;
+
+ byteswap_ = false;
+#ifdef __LITTLE_ENDIAN__
+ byteswap_ = true;
+ swap32 ((unsigned char *)&hdr.hdr_length);
+ swap32 ((unsigned char *)&hdr.format);
+ swap32 ((unsigned char *)&hdr.sample_rate);
+ swap32 ((unsigned char *)&hdr.num_channels);
+#endif
+
+ if ( fwrite(&hdr, 4, 10, fd_) != 10 ) {
+ errorString_ << "FileWrite: Could not write SND header for file " << name << '.';
+ return false;
+ }
+
+ errorString_ << "FileWrite: creating SND file: " << name;
+ handleError( StkError::STATUS );
+ return true;
+}
+
+void FileWrite :: closeSndFile( void )
+{
+ int bytes_per_sample = 1;
+ if ( dataType_ == STK_SINT16 )
+ bytes_per_sample = 2;
+ else if ( dataType_ == STK_SINT32 )
+ bytes_per_sample = 4;
+ else if ( dataType_ == STK_FLOAT32 )
+ bytes_per_sample = 4;
+ else if ( dataType_ == STK_FLOAT64 )
+ bytes_per_sample = 8;
+
+ SINT32 bytes = frameCounter_ * bytes_per_sample * channels_;
+#ifdef __LITTLE_ENDIAN__
+ swap32 ((unsigned char *)&bytes);
+#endif
+ fseek(fd_, 8, SEEK_SET); // jump to data size
+ fwrite(&bytes, 4, 1, fd_);
+ fclose(fd_);
+}
+
+bool FileWrite :: setAifFile( const char *fileName )
+{
+ char name[8192];
+ strncpy(name, fileName, 8192);
+ if ( strstr(name, ".aif") == NULL) strcat(name, ".aif");
+ fd_ = fopen(name, "wb");
+ if ( !fd_ ) {
+ errorString_ << "FileWrite: could not create AIF file: " << name;
+ return false;
+ }
+
+ // Common parts of AIFF/AIFC header.
+ struct aifhdr hdr = {"FOR", 46, "AIF", "COM", 18, 0, 0, 16, "0"};
+ struct aifssnd ssnd = {"SSN", 8, 0, 0};
+ hdr.form[3] = 'M';
+ hdr.aiff[3] = 'F';
+ hdr.comm[3] = 'M';
+ ssnd.ssnd[3] = 'D';
+ hdr.num_chans = channels_;
+ if ( dataType_ == STK_SINT8 )
+ hdr.sample_size = 8;
+ else if ( dataType_ == STK_SINT16 )
+ hdr.sample_size = 16;
+ else if ( dataType_ == STK_SINT32 )
+ hdr.sample_size = 32;
+ else if ( dataType_ == STK_FLOAT32 ) {
+ hdr.aiff[3] = 'C';
+ hdr.sample_size = 32;
+ hdr.comm_size = 24;
+ }
+ else if ( dataType_ == STK_FLOAT64 ) {
+ hdr.aiff[3] = 'C';
+ hdr.sample_size = 64;
+ hdr.comm_size = 24;
+ }
+
+ // For AIFF files, the sample rate is stored in a 10-byte,
+ // IEEE Standard 754 floating point number, so we need to
+ // convert to that.
+ SINT16 i;
+ unsigned long exp;
+ unsigned long rate = (unsigned long) Stk::sampleRate();
+ memset(hdr.srate, 0, 10);
+ exp = rate;
+ for (i=0; i<32; i++) {
+ exp >>= 1;
+ if (!exp) break;
+ }
+ i += 16383;
+#ifdef __LITTLE_ENDIAN__
+ swap16((unsigned char *)&i);
+#endif
+ *(SINT16 *)(hdr.srate) = (SINT16) i;
+
+ for (i=32; i; i--) {
+ if (rate & 0x80000000) break;
+ rate <<= 1;
+ }
+
+#ifdef __LITTLE_ENDIAN__
+ swap32((unsigned char *)&rate);
+#endif
+ *(unsigned long *)(hdr.srate+2) = (unsigned long) rate;
+
+ byteswap_ = false;
+#ifdef __LITTLE_ENDIAN__
+ byteswap_ = true;
+ swap32((unsigned char *)&hdr.form_size);
+ swap32((unsigned char *)&hdr.comm_size);
+ swap16((unsigned char *)&hdr.num_chans);
+ swap16((unsigned char *)&hdr.sample_size);
+ swap32((unsigned char *)&ssnd.ssnd_size);
+ swap32((unsigned char *)&ssnd.offset);
+ swap32((unsigned char *)&ssnd.block_size);
+#endif
+
+ // The structure boundaries don't allow a single write of 54 bytes.
+ if ( fwrite(&hdr, 4, 5, fd_) != 5 ) goto error;
+ if ( fwrite(&hdr.num_chans, 2, 1, fd_) != 1 ) goto error;
+ if ( fwrite(&hdr.sample_frames, 4, 1, fd_) != 1 ) goto error;
+ if ( fwrite(&hdr.sample_size, 2, 1, fd_) != 1 ) goto error;
+ if ( fwrite(&hdr.srate, 10, 1, fd_) != 1 ) goto error;
+
+ if ( dataType_ == STK_FLOAT32 ) {
+ char type[4] = {'f','l','3','2'};
+ char zeroes[2] = { 0, 0 };
+ if ( fwrite(&type, 4, 1, fd_) != 1 ) goto error;
+ if ( fwrite(&zeroes, 2, 1, fd_) != 1 ) goto error;
+ }
+ else if ( dataType_ == STK_FLOAT64 ) {
+ char type[4] = {'f','l','6','4'};
+ char zeroes[2] = { 0, 0 };
+ if ( fwrite(&type, 4, 1, fd_) != 1 ) goto error;
+ if ( fwrite(&zeroes, 2, 1, fd_) != 1 ) goto error;
+ }
+
+ if ( fwrite(&ssnd, 4, 4, fd_) != 4 ) goto error;
+
+ errorString_ << "FileWrite: creating AIF file: " << name;
+ handleError( StkError::STATUS );
+ return true;
+
+ error:
+ errorString_ << "FileWrite: could not write AIF header for file: " << name;
+ return false;
+}
+
+void FileWrite :: closeAifFile( void )
+{
+ unsigned long frames = (unsigned long) frameCounter_;
+#ifdef __LITTLE_ENDIAN__
+ swap32((unsigned char *)&frames);
+#endif
+ fseek(fd_, 22, SEEK_SET); // jump to "COMM" sample_frames
+ fwrite(&frames, 4, 1, fd_);
+
+ int bytes_per_sample = 1;
+ if ( dataType_ == STK_SINT16 )
+ bytes_per_sample = 2;
+ else if ( dataType_ == STK_SINT32 || dataType_ == STK_FLOAT32 )
+ bytes_per_sample = 4;
+ else if ( dataType_ == STK_FLOAT64 )
+ bytes_per_sample = 8;
+
+ unsigned long bytes = frameCounter_ * bytes_per_sample * channels_ + 46;
+ if ( dataType_ == STK_FLOAT32 || dataType_ == STK_FLOAT64 ) bytes += 6;
+#ifdef __LITTLE_ENDIAN__
+ swap32((unsigned char *)&bytes);
+#endif
+ fseek(fd_, 4, SEEK_SET); // jump to file size
+ fwrite(&bytes, 4, 1, fd_);
+
+ bytes = frameCounter_ * bytes_per_sample * channels_ + 8;
+ if ( dataType_ == STK_FLOAT32 || dataType_ == STK_FLOAT64 ) bytes += 6;
+#ifdef __LITTLE_ENDIAN__
+ swap32((unsigned char *)&bytes);
+#endif
+ if ( dataType_ == STK_FLOAT32 || dataType_ == STK_FLOAT64 )
+ fseek(fd_, 48, SEEK_SET); // jump to "SSND" chunk size
+ else
+ fseek(fd_, 42, SEEK_SET); // jump to "SSND" chunk size
+ fwrite(&bytes, 4, 1, fd_);
+
+ fclose( fd_ );
+}
+
+bool FileWrite :: setMatFile( const char *fileName )
+{
+ char name[8192];
+ strncpy(name, fileName, 8192);
+ if ( strstr(name, ".mat") == NULL) strcat(name, ".mat");
+ fd_ = fopen(name, "w+b");
+ if ( !fd_ ) {
+ errorString_ << "FileWrite: could not create MAT file: " << name;
+ return false;
+ }
+
+ if ( dataType_ != STK_FLOAT64 ) {
+ dataType_ = STK_FLOAT64;
+ errorString_ << "FileWrite: using 64-bit floating-point data format for file " << name << '.';
+ handleError( StkError::DEBUG_WARNING );
+ }
+
+ struct mathdr hdr;
+ strcpy(hdr.heading,"MATLAB 5.0 MAT-file, Generated using the Synthesis ToolKit in C++ (STK). By Perry R. Cook and Gary P. Scavone.");
+
+ int i;
+ for (i=strlen(hdr.heading);i<124;i++) hdr.heading[i] = ' ';
+
+ // Header Flag Fields
+ hdr.hff[0] = (SINT16) 0x0100; // Version field
+ hdr.hff[1] = (SINT16) 'M'; // Endian indicator field ("MI")
+ hdr.hff[1] <<= 8;
+ hdr.hff[1] += 'I';
+
+ hdr.adf[0] = (SINT32) 14; // Matlab array data type value
+ hdr.adf[1] = (SINT32) 0; // Size of file after this point to end (in bytes)
+ // Don't know size yet.
+
+ // Numeric Array Subelements (4):
+ // 1. Array Flags
+ hdr.adf[2] = (SINT32) 6; // Matlab 32-bit unsigned integer data type value
+ hdr.adf[3] = (SINT32) 8; // 8 bytes of data to follow
+ hdr.adf[4] = (SINT32) 6; // Double-precision array, no array flags set
+ hdr.adf[5] = (SINT32) 0; // 4 bytes undefined
+ // 2. Array Dimensions
+ hdr.adf[6] = (SINT32) 5; // Matlab 32-bit signed integer data type value
+ hdr.adf[7] = (SINT32) 8; // 8 bytes of data to follow (2D array)
+ hdr.adf[8] = (SINT32) channels_; // This is the number of rows
+ hdr.adf[9] = (SINT32) 0; // This is the number of columns
+
+ // 3. Array Name
+ // We'll use fileName for the matlab array name (as well as the file name).
+ // If fileName is 4 characters or less, we have to use a compressed data element
+ // format for the array name data element. Otherwise, the array name must
+ // be formatted in 8-byte increments (up to 31 characters + NULL).
+ SINT32 namelength = (SINT32) strlen(fileName);
+ if (strstr(fileName, ".mat")) namelength -= 4;
+ if (namelength > 31) namelength = 31; // Truncate name to 31 characters.
+ char arrayName[64];
+ strncpy(arrayName, fileName, namelength);
+ arrayName[namelength] = '\0';
+ if (namelength > 4) {
+ hdr.adf[10] = (SINT32) 1; // Matlab 8-bit signed integer data type value
+ }
+ else { // Compressed data element format
+ hdr.adf[10] = namelength;
+ hdr.adf[10] <<= 16;
+ hdr.adf[10] += 1;
+ }
+ SINT32 headsize = 40; // Number of bytes in data element so far.
+
+ // Write the fixed portion of the header
+ if ( fwrite(&hdr, 172, 1, fd_) != 1 ) goto error;
+
+ // Write MATLAB array name
+ SINT32 tmp;
+ if (namelength > 4) {
+ if ( fwrite(&namelength, 4, 1, fd_) != 1) goto error;
+ if ( fwrite(arrayName, namelength, 1, fd_) != 1 ) goto error;
+ tmp = (SINT32) ceil((float)namelength / 8);
+ if ( fseek(fd_, tmp*8-namelength, SEEK_CUR) == -1 ) goto error;
+ headsize += tmp * 8;
+ }
+ else { // Compressed data element format
+ if ( fwrite(arrayName, namelength, 1, fd_) != 1 ) goto error;
+ tmp = 4 - namelength;
+ if ( fseek(fd_, tmp, SEEK_CUR) == -1 ) goto error;
+ }
+
+ // Finish writing known header information
+ tmp = 9; // Matlab IEEE 754 double data type
+ if ( fwrite(&tmp, 4, 1, fd_) != 1 ) goto error;
+ tmp = 0; // Size of real part subelement in bytes (8 per sample)
+ if ( fwrite(&tmp, 4, 1, fd_) != 1 ) goto error;
+ headsize += 8; // Total number of bytes in data element so far
+
+ if ( fseek(fd_, 132, SEEK_SET) == -1 ) goto error;
+ if ( fwrite(&headsize, 4, 1, fd_) != 1 ) goto error; // Write header size ... will update at end
+ if ( fseek(fd_, 0, SEEK_END) == -1 ) goto error;
+
+ byteswap_ = false;
+ errorString_ << "FileWrite: creating MAT-file (" << name << ") containing MATLAB array: " << arrayName;
+ handleError( StkError::STATUS );
+
+ return true;
+
+ error:
+ errorString_ << "FileWrite: could not write MAT-file header for file " << name << '.';
+ return false;
+}
+
+void FileWrite :: closeMatFile( void )
+{
+ fseek(fd_, 164, SEEK_SET); // jump to number of columns
+ fwrite(&frameCounter_, 4, 1, fd_);
+
+ SINT32 headsize, temp;
+ fseek(fd_, 132, SEEK_SET); // jump to header size
+ fread(&headsize, 4, 1, fd_);
+ temp = headsize;
+ headsize += (SINT32) (frameCounter_ * 8 * channels_);
+ fseek(fd_, 132, SEEK_SET);
+ // Write file size (minus some header info)
+ fwrite(&headsize, 4, 1, fd_);
+
+ fseek(fd_, temp+132, SEEK_SET); // jumpt to data size (in bytes)
+ temp = frameCounter_ * 8 * channels_;
+ fwrite(&temp, 4, 1, fd_);
+
+ fclose(fd_);
+}
+
+void FileWrite :: write( StkFrames& buffer )
+{
+ if ( fd_ == 0 ) {
+ errorString_ << "FileWrite::write(): a file has not yet been opened!";
+ handleError( StkError::WARNING );
+ return;
+ }
+
+ if ( buffer.channels() != channels_ ) {
+ errorString_ << "FileWrite::write(): number of channels in the StkFrames argument does not match that specified to open() function!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ return;
+ }
+
+ unsigned long nSamples = buffer.size();
+ if ( dataType_ == STK_SINT16 ) {
+ SINT16 sample;
+ for ( unsigned long k=0; k<nSamples; k++ ) {
+ sample = (SINT16) (buffer[k] * 32767.0);
+ //sample = ((SINT16) (( buffer[k] + 1.0 ) * 32767.5 + 0.5)) - 32768;
+ if ( byteswap_ ) swap16( (unsigned char *)&sample );
+ if ( fwrite(&sample, 2, 1, fd_) != 1 ) goto error;
+ }
+ }
+ else if ( dataType_ == STK_SINT8 ) {
+ if ( fileType_ == FILE_WAV ) { // 8-bit WAV data is unsigned!
+ unsigned char sample;
+ for ( unsigned long k=0; k<nSamples; k++ ) {
+ sample = (unsigned char) (buffer[k] * 127.0 + 128.0);
+ if ( fwrite(&sample, 1, 1, fd_) != 1 ) goto error;
+ }
+ }
+ else {
+ signed char sample;
+ for ( unsigned long k=0; k<nSamples; k++ ) {
+ sample = (signed char) (buffer[k] * 127.0);
+ //sample = ((signed char) (( buffer[k] + 1.0 ) * 127.5 + 0.5)) - 128;
+ if ( fwrite(&sample, 1, 1, fd_) != 1 ) goto error;
+ }
+ }
+ }
+ else if ( dataType_ == STK_SINT32 ) {
+ SINT32 sample;
+ for ( unsigned long k=0; k<nSamples; k++ ) {
+ sample = (SINT32) (buffer[k] * 2147483647.0);
+ //sample = ((SINT32) (( buffer[k] + 1.0 ) * 2147483647.5 + 0.5)) - 2147483648;
+ if ( byteswap_ ) swap32( (unsigned char *)&sample );
+ if ( fwrite(&sample, 4, 1, fd_) != 1 ) goto error;
+ }
+ }
+ else if ( dataType_ == STK_FLOAT32 ) {
+ FLOAT32 sample;
+ for ( unsigned long k=0; k<nSamples; k++ ) {
+ sample = (FLOAT32) (buffer[k]);
+ if ( byteswap_ ) swap32( (unsigned char *)&sample );
+ if ( fwrite(&sample, 4, 1, fd_) != 1 ) goto error;
+ }
+ }
+ else if ( dataType_ == STK_FLOAT64 ) {
+ FLOAT64 sample;
+ for ( unsigned long k=0; k<nSamples; k++ ) {
+ sample = (FLOAT64) (buffer[k]);
+ if ( byteswap_ ) swap64( (unsigned char *)&sample );
+ if ( fwrite(&sample, 8, 1, fd_) != 1 ) goto error;
+ }
+ }
+
+ frameCounter_ += buffer.frames();
+ return;
+
+ error:
+ errorString_ << "FileWrite::write(): error writing data to file!";
+ handleError( StkError::FILE_ERROR );
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class FileWvIn
+ \brief STK audio file input class.
+
+ This class inherits from WvIn. It provides a "tick-level"
+ interface to the FileRead class. It also provides variable-rate
+ playback functionality. Audio file support is provided by the
+ FileRead class. Linear interpolation is used for fractional read
+ rates.
+
+ FileWvIn supports multi-channel data. It is important to
+ distinguish the tick() method that computes a single frame (and
+ returns only the specified sample of a multi-channel frame) from
+ the overloaded one that takes an StkFrames object for
+ multi-channel and/or multi-frame data.
+
+ FileWvIn will either load the entire content of an audio file into
+ local memory or incrementally read file data from disk in chunks.
+ This behavior is controlled by the optional constructor arguments
+ \e chunkThreshold and \e chunkSize. File sizes greater than \e
+ chunkThreshold (in sample frames) will be read incrementally in
+ chunks of \e chunkSize each (also in sample frames).
+
+ When the file end is reached, subsequent calls to the tick()
+ functions return zeros and isFinished() returns \e true.
+
+ See the FileRead class for a description of the supported audio
+ file formats.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "FileWvIn.h"
+#include <cmath>
+
+namespace stk {
+
+FileWvIn :: FileWvIn( unsigned long chunkThreshold, unsigned long chunkSize )
+ : finished_(true), interpolate_(false), time_(0.0),
+ chunkThreshold_(chunkThreshold), chunkSize_(chunkSize)
+{
+ Stk::addSampleRateAlert( this );
+}
+
+FileWvIn :: FileWvIn( std::string fileName, bool raw, bool doNormalize,
+ unsigned long chunkThreshold, unsigned long chunkSize )
+ : finished_(true), interpolate_(false), time_(0.0),
+ chunkThreshold_(chunkThreshold), chunkSize_(chunkSize)
+{
+ openFile( fileName, raw, doNormalize );
+ Stk::addSampleRateAlert( this );
+}
+
+FileWvIn :: ~FileWvIn()
+{
+ this->closeFile();
+ Stk::removeSampleRateAlert( this );
+}
+
+void FileWvIn :: sampleRateChanged( StkFloat newRate, StkFloat oldRate )
+{
+ if ( !ignoreSampleRateChange_ )
+ this->setRate( oldRate * rate_ / newRate );
+}
+
+void FileWvIn :: closeFile( void )
+{
+ if ( file_.isOpen() ) file_.close();
+ finished_ = true;
+ lastFrame_.resize( 0, 0 );
+}
+
+void FileWvIn :: openFile( std::string fileName, bool raw, bool doNormalize )
+{
+ // Call close() in case another file is already open.
+ this->closeFile();
+
+ // Attempt to open the file ... an error might be thrown here.
+ file_.open( fileName, raw );
+
+ // Determine whether chunking or not.
+ if ( file_.fileSize() > chunkThreshold_ ) {
+ chunking_ = true;
+ chunkPointer_ = 0;
+ data_.resize( chunkSize_, file_.channels() );
+ if ( doNormalize ) normalizing_ = true;
+ else normalizing_ = false;
+ }
+ else {
+ chunking_ = false;
+ data_.resize( (size_t) file_.fileSize(), file_.channels() );
+ }
+
+ // Load all or part of the data.
+ file_.read( data_, 0, doNormalize );
+
+ // Resize our lastFrame container.
+ lastFrame_.resize( 1, file_.channels() );
+
+ // Set default rate based on file sampling rate.
+ this->setRate( data_.dataRate() / Stk::sampleRate() );
+
+ if ( doNormalize & !chunking_ ) this->normalize();
+
+ this->reset();
+}
+
+void FileWvIn :: reset(void)
+{
+ time_ = (StkFloat) 0.0;
+ for ( unsigned int i=0; i<lastFrame_.size(); i++ ) lastFrame_[i] = 0.0;
+ finished_ = false;
+}
+
+void FileWvIn :: normalize(void)
+{
+ this->normalize( 1.0 );
+}
+
+// Normalize all channels equally by the greatest magnitude in all of the data.
+void FileWvIn :: normalize( StkFloat peak )
+{
+ // When chunking, the "normalization" scaling is performed by FileRead.
+ if ( chunking_ ) return;
+
+ size_t i;
+ StkFloat max = 0.0;
+
+ for ( i=0; i<data_.size(); i++ ) {
+ if ( fabs( data_[i] ) > max )
+ max = (StkFloat) fabs((double) data_[i]);
+ }
+
+ if ( max > 0.0 ) {
+ max = 1.0 / max;
+ max *= peak;
+ for ( i=0; i<data_.size(); i++ )
+ data_[i] *= max;
+ }
+}
+
+void FileWvIn :: setRate( StkFloat rate )
+{
+#if defined(_STK_DEBUG_)
+ errorString_ << "FileWvIn::setRate: changing file read rate from " << rate_ << " to " << rate << '.';
+ handleError( StkError::DEBUG_WARNING );
+#endif
+
+ rate_ = rate;
+
+ // If negative rate and at beginning of sound, move pointer to end
+ // of sound.
+ if ( (rate_ < 0) && (time_ == 0.0) ) time_ = file_.fileSize() - 1.0;
+
+ if ( fmod( rate_, 1.0 ) != 0.0 ) interpolate_ = true;
+ else interpolate_ = false;
+}
+
+void FileWvIn :: addTime( StkFloat time )
+{
+ // Add an absolute time in samples
+ time_ += time;
+
+ if ( time_ < 0.0 ) time_ = 0.0;
+ if ( time_ > file_.fileSize() - 1.0 ) {
+ time_ = file_.fileSize() - 1.0;
+ for ( unsigned int i=0; i<lastFrame_.size(); i++ ) lastFrame_[i] = 0.0;
+ finished_ = true;
+ }
+}
+
+StkFloat FileWvIn :: tick( unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel >= data_.channels() ) {
+ errorString_ << "FileWvIn::tick(): channel argument and soundfile data are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ if ( finished_ ) return 0.0;
+
+ if ( time_ < 0.0 || time_ > (StkFloat) ( file_.fileSize() - 1.0 ) ) {
+ for ( unsigned int i=0; i<lastFrame_.size(); i++ ) lastFrame_[i] = 0.0;
+ finished_ = true;
+ return 0.0;
+ }
+
+ StkFloat tyme = time_;
+ if ( chunking_ ) {
+
+ // Check the time address vs. our current buffer limits.
+ if ( ( time_ < (StkFloat) chunkPointer_ ) ||
+ ( time_ > (StkFloat) ( chunkPointer_ + chunkSize_ - 1 ) ) ) {
+
+ while ( time_ < (StkFloat) chunkPointer_ ) { // negative rate
+ chunkPointer_ -= chunkSize_ - 1; // overlap chunks by one frame
+ if ( chunkPointer_ < 0 ) chunkPointer_ = 0;
+ }
+ while ( time_ > (StkFloat) ( chunkPointer_ + chunkSize_ - 1 ) ) { // positive rate
+ chunkPointer_ += chunkSize_ - 1; // overlap chunks by one frame
+ if ( chunkPointer_ + chunkSize_ > file_.fileSize() ) // at end of file
+ chunkPointer_ = file_.fileSize() - chunkSize_;
+ }
+
+ // Load more data.
+ file_.read( data_, chunkPointer_, normalizing_ );
+ }
+
+ // Adjust index for the current buffer.
+ tyme -= chunkPointer_;
+ }
+
+ if ( interpolate_ ) {
+ for ( unsigned int i=0; i<lastFrame_.size(); i++ )
+ lastFrame_[i] = data_.interpolate( tyme, i );
+ }
+ else {
+ for ( unsigned int i=0; i<lastFrame_.size(); i++ )
+ lastFrame_[i] = data_( (size_t) tyme, i );
+ }
+
+ // Increment time, which can be negative.
+ time_ += rate_;
+
+ return lastFrame_[channel];
+}
+
+StkFrames& FileWvIn :: tick( StkFrames& frames )
+{
+ if ( !file_.isOpen() ) {
+#if defined(_STK_DEBUG_)
+ errorString_ << "FileWvIn::tick(): no file data is loaded!";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+ return frames;
+ }
+
+ unsigned int nChannels = lastFrame_.channels();
+#if defined(_STK_DEBUG_)
+ if ( nChannels != frames.channels() ) {
+ errorString_ << "FileWvIn::tick(): StkFrames argument is incompatible with file data!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ unsigned int j, counter = 0;
+ for ( unsigned int i=0; i<frames.frames(); i++ ) {
+ this->tick();
+ for ( j=0; j<nChannels; j++ )
+ frames[counter++] = lastFrame_[j];
+ }
+
+ return frames;
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class FileWvOut
+ \brief STK audio file output class.
+
+ This class inherits from WvOut. It provides a "tick-level"
+ interface to the FileWrite class.
+
+ FileWvOut writes samples to an audio file and supports
+ multi-channel data. It is important to distinguish the tick()
+ method that outputs a single sample to all channels in a sample
+ frame from the overloaded one that takes a reference to an
+ StkFrames object for multi-channel and/or multi-frame data.
+
+ See the FileWrite class for a description of the supported audio
+ file formats.
+
+ Currently, FileWvOut is non-interpolating and the output rate is
+ always Stk::sampleRate().
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "FileWvOut.h"
+
+namespace stk {
+
+FileWvOut :: FileWvOut( unsigned int bufferFrames )
+ :bufferFrames_( bufferFrames )
+{
+}
+
+FileWvOut::FileWvOut( std::string fileName, unsigned int nChannels, FileWrite::FILE_TYPE type, Stk::StkFormat format, unsigned int bufferFrames )
+ :bufferFrames_( bufferFrames )
+{
+ this->openFile( fileName, nChannels, type, format );
+}
+
+FileWvOut :: ~FileWvOut()
+{
+ this->closeFile();
+}
+
+void FileWvOut :: closeFile( void )
+{
+ if ( file_.isOpen() ) {
+
+ // Output any remaining samples in the buffer before closing.
+ if ( bufferIndex_ > 0 ) {
+ data_.resize( bufferIndex_, data_.channels() );
+ file_.write( data_ );
+ }
+
+ file_.close();
+ frameCounter_ = 0;
+ }
+}
+
+void FileWvOut :: openFile( std::string fileName,
+ unsigned int nChannels,
+ FileWrite::FILE_TYPE type,
+ Stk::StkFormat format )
+{
+ closeFile();
+
+ if ( nChannels < 1 ) {
+ errorString_ << "FileWvOut::openFile: the channels argument must be greater than zero!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+
+ // An StkError can be thrown by the FileWrite class here.
+ file_.open( fileName, nChannels, type, format );
+
+ // Allocate new memory if necessary.
+ data_.resize( bufferFrames_, nChannels );
+
+ bufferIndex_ = 0;
+ iData_ = 0;
+}
+
+void FileWvOut :: incrementFrame( void )
+{
+ frameCounter_++;
+ bufferIndex_++;
+
+ if ( bufferIndex_ == bufferFrames_ ) {
+ file_.write( data_ );
+ bufferIndex_ = 0;
+ iData_ = 0;
+ }
+}
+
+void FileWvOut :: tick( const StkFloat sample )
+{
+#if defined(_STK_DEBUG_)
+ if ( !file_.isOpen() ) {
+ errorString_ << "FileWvOut::tick(): no file open!";
+ handleError( StkError::WARNING );
+ return;
+ }
+#endif
+
+ unsigned int nChannels = data_.channels();
+ StkFloat input = sample;
+ clipTest( input );
+ for ( unsigned int j=0; j<nChannels; j++ )
+ data_[iData_++] = input;
+
+ this->incrementFrame();
+}
+
+void FileWvOut :: tick( const StkFrames& frames )
+{
+#if defined(_STK_DEBUG_)
+ if ( !file_.isOpen() ) {
+ errorString_ << "FileWvOut::tick(): no file open!";
+ handleError( StkError::WARNING );
+ return;
+ }
+
+ if ( data_.channels() != frames.channels() ) {
+ errorString_ << "FileWvOut::tick(): incompatible channel value in StkFrames argument!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ unsigned int iFrames = 0;
+ unsigned int j, nChannels = data_.channels();
+ for ( unsigned int i=0; i<frames.frames(); i++ ) {
+
+ for ( j=0; j<nChannels; j++ ) {
+ data_[iData_] = frames[iFrames++];
+ clipTest( data_[iData_++] );
+ }
+
+ this->incrementFrame();
+ }
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class Fir
+ \brief STK general finite impulse response filter class.
+
+ This class provides a generic digital filter structure that can be
+ used to implement FIR filters. For filters with feedback terms,
+ the Iir class should be used.
+
+ In particular, this class implements the standard difference
+ equation:
+
+ y[n] = b[0]*x[n] + ... + b[nb]*x[n-nb]
+
+ The \e gain parameter is applied at the filter input and does not
+ affect the coefficient values. The default gain value is 1.0.
+ This structure results in one extra multiply per computed sample,
+ but allows easy control of the overall filter gain.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "Fir.h"
+
+namespace stk {
+
+Fir :: Fir()
+{
+ // The default constructor should setup for pass-through.
+ b_.push_back( 1.0 );
+
+ inputs_.resize( 1, 1, 0.0 );
+}
+
+Fir :: Fir( std::vector<StkFloat> &coefficients )
+{
+ // Check the arguments.
+ if ( coefficients.size() == 0 ) {
+ errorString_ << "Fir: coefficient vector must have size > 0!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+
+ gain_ = 1.0;
+ b_ = coefficients;
+
+ inputs_.resize( b_.size(), 1, 0.0 );
+ this->clear();
+}
+
+Fir :: ~Fir()
+{
+}
+
+void Fir :: setCoefficients( std::vector<StkFloat> &coefficients, bool clearState )
+{
+ // Check the argument.
+ if ( coefficients.size() == 0 ) {
+ errorString_ << "Fir::setCoefficients: coefficient vector must have size > 0!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+
+ if ( b_.size() != coefficients.size() ) {
+ b_ = coefficients;
+ inputs_.resize( b_.size(), 1, 0.0 );
+ }
+ else {
+ for ( unsigned int i=0; i<b_.size(); i++ ) b_[i] = coefficients[i];
+ }
+
+ if ( clearState ) this->clear();
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class Flute
+ \brief STK flute physical model class.
+
+ This class implements a simple flute
+ physical model, as discussed by Karjalainen,
+ Smith, Waryznyk, etc. The jet model uses
+ a polynomial, a la Cook.
+
+ This is a digital waveguide model, making its
+ use possibly subject to patents held by Stanford
+ University, Yamaha, and others.
+
+ Control Change Numbers:
+ - Jet Delay = 2
+ - Noise Gain = 4
+ - Vibrato Frequency = 11
+ - Vibrato Gain = 1
+ - Breath Pressure = 128
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "Flute.h"
+#include "Skini_msg.h"
+
+namespace stk {
+
+Flute :: Flute( StkFloat lowestFrequency )
+{
+ length_ = (unsigned long) ( Stk::sampleRate() / lowestFrequency + 1 );
+ boreDelay_.setMaximumDelay( length_ );
+ boreDelay_.setDelay( 100.0 );
+
+ jetDelay_.setMaximumDelay( length_ );
+ jetDelay_.setDelay( 49.0 );
+
+ vibrato_.setFrequency( 5.925 );
+
+ this->clear();
+
+ filter_.setPole( 0.7 - ((StkFloat) 0.1 * 22050.0 / Stk::sampleRate() ) );
+ filter_.setGain( -1.0 );
+
+ dcBlock_.setBlockZero();
+
+ adsr_.setAllTimes( 0.005, 0.01, 0.8, 0.010);
+ endReflection_ = 0.5;
+ jetReflection_ = 0.5;
+ noiseGain_ = 0.15; // Breath pressure random component.
+ vibratoGain_ = 0.05; // Breath periodic vibrato component.
+ jetRatio_ = 0.32;
+
+ maxPressure_ = 0.0;
+ lastFrequency_ = 220.0;
+}
+
+Flute :: ~Flute( void )
+{
+}
+
+void Flute :: clear( void )
+{
+ jetDelay_.clear();
+ boreDelay_.clear();
+ filter_.clear();
+ dcBlock_.clear();
+}
+
+void Flute :: setFrequency( StkFloat frequency )
+{
+ lastFrequency_ = frequency;
+ if ( frequency <= 0.0 ) {
+ errorString_ << "Flute::setFrequency: parameter is less than or equal to zero!";
+ handleError( StkError::WARNING );
+ lastFrequency_ = 220.0;
+ }
+
+ // We're overblowing here.
+ lastFrequency_ *= 0.66666;
+
+ // delay = length - approximate filter delay.
+ StkFloat delay = Stk::sampleRate() / lastFrequency_ - (StkFloat) 2.0;
+ if ( delay <= 0.0 ) delay = 0.3;
+ else if ( delay > length_ ) delay = length_;
+
+ boreDelay_.setDelay(delay);
+ jetDelay_.setDelay(delay * jetRatio_);
+}
+
+void Flute :: startBlowing( StkFloat amplitude, StkFloat rate )
+{
+ adsr_.setAttackRate( rate );
+ maxPressure_ = amplitude / (StkFloat) 0.8;
+ adsr_.keyOn();
+}
+
+void Flute :: stopBlowing( StkFloat rate )
+{
+ adsr_.setReleaseRate( rate );
+ adsr_.keyOff();
+}
+
+void Flute :: noteOn( StkFloat frequency, StkFloat amplitude )
+{
+ this->setFrequency( frequency );
+ this->startBlowing( 1.1 + (amplitude * 0.20), amplitude * 0.02 );
+ outputGain_ = amplitude + 0.001;
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Flute::NoteOn: frequency = " << frequency << ", amplitude = " << amplitude << ".";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+void Flute :: noteOff( StkFloat amplitude )
+{
+ this->stopBlowing( amplitude * 0.02 );
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Flute::NoteOff: amplitude = " << amplitude << ".";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+void Flute :: setJetReflection( StkFloat coefficient )
+{
+ jetReflection_ = coefficient;
+}
+
+void Flute :: setEndReflection( StkFloat coefficient )
+{
+ endReflection_ = coefficient;
+}
+
+void Flute :: setJetDelay( StkFloat aRatio )
+{
+ // Delay = length - approximate filter delay.
+ StkFloat temp = Stk::sampleRate() / lastFrequency_ - (StkFloat) 2.0;
+ jetRatio_ = aRatio;
+ jetDelay_.setDelay(temp * aRatio); // Scaled by ratio.
+}
+
+void Flute :: controlChange( int number, StkFloat value )
+{
+ StkFloat norm = value * ONE_OVER_128;
+ if ( norm < 0 ) {
+ norm = 0.0;
+ errorString_ << "Flute::controlChange: control value less than zero ... setting to zero!";
+ handleError( StkError::WARNING );
+ }
+ else if ( norm > 1.0 ) {
+ norm = 1.0;
+ errorString_ << "Flute::controlChange: control value greater than 128.0 ... setting to 128.0!";
+ handleError( StkError::WARNING );
+ }
+
+ if (number == __SK_JetDelay_) // 2
+ this->setJetDelay( (StkFloat) (0.08 + (0.48 * norm)) );
+ else if (number == __SK_NoiseLevel_) // 4
+ noiseGain_ = ( norm * 0.4);
+ else if (number == __SK_ModFrequency_) // 11
+ vibrato_.setFrequency( norm * 12.0);
+ else if (number == __SK_ModWheel_) // 1
+ vibratoGain_ = ( norm * 0.4 );
+ else if (number == __SK_AfterTouch_Cont_) // 128
+ adsr_.setTarget( norm );
+ else {
+ errorString_ << "Flute::controlChange: undefined control number (" << number << ")!";
+ handleError( StkError::WARNING );
+ }
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Flute::controlChange: number = " << number << ", value = " << value << ".";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class FormSwep
+ \brief STK sweepable formant filter class.
+
+ This class implements a formant (resonance) which can be "swept"
+ over time from one frequency setting to another. It provides
+ methods for controlling the sweep rate and target frequency.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "FormSwep.h"
+#include <cmath>
+
+namespace stk {
+
+FormSwep :: FormSwep( void )
+{
+ frequency_ = 0.0;
+ radius_ = 0.0;
+ targetGain_ = 1.0;
+ targetFrequency_ = 0.0;
+ targetRadius_ = 0.0;
+ deltaGain_ = 0.0;
+ deltaFrequency_ = 0.0;
+ deltaRadius_ = 0.0;
+ sweepState_ = 0.0;
+ sweepRate_ = 0.002;
+ dirty_ = false;
+
+ b_.resize( 3, 0.0 );
+ a_.resize( 3, 0.0 );
+ a_[0] = 1.0;
+ inputs_.resize( 3, 1, 0.0 );
+ outputs_.resize( 3, 1, 0.0 );
+
+ Stk::addSampleRateAlert( this );
+}
+
+FormSwep :: ~FormSwep()
+{
+ Stk::removeSampleRateAlert( this );
+}
+
+void FormSwep :: sampleRateChanged( StkFloat newRate, StkFloat oldRate )
+{
+ if ( !ignoreSampleRateChange_ ) {
+ errorString_ << "FormSwep::sampleRateChanged: you may need to recompute filter coefficients!";
+ handleError( StkError::WARNING );
+ }
+}
+
+void FormSwep :: setResonance( StkFloat frequency, StkFloat radius )
+{
+ radius_ = radius;
+ frequency_ = frequency;
+
+ a_[2] = radius * radius;
+ a_[1] = -2.0 * radius * cos( TWO_PI * frequency / Stk::sampleRate() );
+
+ // Use zeros at +- 1 and normalize the filter peak gain.
+ b_[0] = 0.5 - 0.5 * a_[2];
+ b_[1] = 0.0;
+ b_[2] = -b_[0];
+}
+
+void FormSwep :: setStates( StkFloat frequency, StkFloat radius, StkFloat gain )
+{
+ dirty_ = false;
+
+ if ( frequency_ != frequency || radius_ != radius )
+ this->setResonance( frequency, radius );
+
+ gain_ = gain;
+ targetFrequency_ = frequency;
+ targetRadius_ = radius;
+ targetGain_ = gain;
+}
+
+void FormSwep :: setTargets( StkFloat frequency, StkFloat radius, StkFloat gain )
+{
+ dirty_ = true;
+ startFrequency_ = frequency_;
+ startRadius_ = radius_;
+ startGain_ = gain_;
+ targetFrequency_ = frequency;
+ targetRadius_ = radius;
+ targetGain_ = gain;
+ deltaFrequency_ = frequency - frequency_;
+ deltaRadius_ = radius - radius_;
+ deltaGain_ = gain - gain_;
+ sweepState_ = 0.0;
+}
+
+void FormSwep :: setSweepRate( StkFloat rate )
+{
+ sweepRate_ = rate;
+ if ( sweepRate_ > 1.0 ) sweepRate_ = 1.0;
+ if ( sweepRate_ < 0.0 ) sweepRate_ = 0.0;
+}
+
+void FormSwep :: setSweepTime( StkFloat time )
+{
+ sweepRate_ = 1.0 / ( time * Stk::sampleRate() );
+ if ( sweepRate_ > 1.0 ) sweepRate_ = 1.0;
+ if ( sweepRate_ < 0.0 ) sweepRate_ = 0.0;
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class Granulate
+ \brief STK granular synthesis class.
+
+ This class implements a real-time granular synthesis algorithm
+ that operates on an input soundfile. Multi-channel files are
+ supported. Various functions are provided to allow control over
+ voice and grain parameters.
+
+ The functionality of this class is based on the program MacPod by
+ Chris Rolfe and Damian Keller, though there are likely to be a
+ number of differences in the actual implementation.
+
+ by Gary Scavone, 2005 - 2010.
+*/
+/***************************************************/
+
+#include "Granulate.h"
+#include "FileRead.h"
+#include <cmath>
+
+namespace stk {
+
+Granulate :: Granulate( void )
+{
+ this->setGrainParameters(); // use default values
+ this->setRandomFactor();
+ gStretch_ = 0;
+ stretchCounter_ = 0;
+ gain_ = 1.0;
+}
+
+Granulate :: Granulate( unsigned int nVoices, std::string fileName, bool typeRaw )
+{
+ this->setGrainParameters(); // use default values
+ this->setRandomFactor();
+ gStretch_ = 0;
+ stretchCounter_ = 0;
+ this->openFile( fileName, typeRaw );
+ this->setVoices( nVoices );
+}
+
+Granulate :: ~Granulate( void )
+{
+}
+
+void Granulate :: setStretch( unsigned int stretchFactor )
+{
+ if ( stretchFactor <= 1 )
+ gStretch_ = 0;
+ else if ( gStretch_ >= 1000 )
+ gStretch_ = 1000;
+ else
+ gStretch_ = stretchFactor - 1;
+}
+
+void Granulate :: setGrainParameters( unsigned int duration, unsigned int rampPercent,
+ int offset, unsigned int delay )
+{
+ gDuration_ = duration;
+ if ( gDuration_ == 0 ) {
+ gDuration_ = 1;
+ errorString_ << "Granulate::setGrainParameters: duration argument cannot be zero ... setting to 1 millisecond.";
+ handleError( StkError::WARNING );
+ }
+
+ gRampPercent_ = rampPercent;
+ if ( gRampPercent_ > 100 ) {
+ gRampPercent_ = 100;
+ errorString_ << "Granulate::setGrainParameters: rampPercent argument cannot be greater than 100 ... setting to 100.";
+ handleError( StkError::WARNING );
+ }
+
+ gOffset_ = offset;
+ gDelay_ = delay;
+}
+
+void Granulate :: setRandomFactor( StkFloat randomness )
+{
+ if ( randomness < 0.0 ) gRandomFactor_ = 0.0;
+ else if ( randomness > 1.0 ) gRandomFactor_ = 0.97;
+
+ gRandomFactor_ = 0.97 * randomness;
+};
+
+void Granulate :: openFile( std::string fileName, bool typeRaw )
+{
+ // Attempt to load the soundfile data.
+ FileRead file( fileName, typeRaw );
+ data_.resize( file.fileSize(), file.channels() );
+ file.read( data_ );
+ lastFrame_.resize( 1, file.channels(), 0.0 );
+
+ this->reset();
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Granulate::openFile: file = " << fileName << ", file frames = " << file.fileSize() << '.';
+ handleError( StkError::DEBUG_WARNING );
+#endif
+
+}
+
+void Granulate :: reset( void )
+{
+ gPointer_ = 0;
+
+ // Reset grain parameters.
+ unsigned int count, nVoices = grains_.size();
+ for ( unsigned int i=0; i<grains_.size(); i++ ) {
+ grains_[i].repeats = 0;
+ count = (unsigned int ) ( i * gDuration_ * 0.001 * Stk::sampleRate() / nVoices );
+ grains_[i].counter = count;
+ grains_[i].state = GRAIN_STOPPED;
+ }
+
+ for ( unsigned int i=0; i<lastFrame_.channels(); i++ )
+ lastFrame_[i] = 0.0;
+}
+
+void Granulate :: setVoices( unsigned int nVoices )
+{
+#if defined(_STK_DEBUG_)
+ errorString_ << "Granulate::setVoices: nVoices = " << nVoices << ", existing voices = " << grains_.size() << '.';
+ handleError( StkError::DEBUG_WARNING );
+#endif
+
+ unsigned int oldSize = grains_.size();
+ grains_.resize( nVoices );
+
+ // Initialize new grain voices.
+ unsigned int count;
+ for ( unsigned int i=oldSize; i<nVoices; i++ ) {
+ grains_[i].repeats = 0;
+ count = (unsigned int ) ( i * gDuration_ * 0.001 * Stk::sampleRate() / nVoices );
+ grains_[i].counter = count;
+ grains_[i].pointer = gPointer_;
+ grains_[i].state = GRAIN_STOPPED;
+ }
+
+ gain_ = 1.0 / grains_.size();
+}
+
+void Granulate :: calculateGrain( Granulate::Grain& grain )
+{
+ if ( grain.repeats > 0 ) {
+ grain.repeats--;
+ grain.pointer = grain.startPointer;
+ if ( grain.attackCount > 0 ) {
+ grain.eScaler = 0.0;
+ grain.eRate = -grain.eRate;
+ grain.counter = grain.attackCount;
+ grain.state = GRAIN_FADEIN;
+ }
+ else {
+ grain.counter = grain.sustainCount;
+ grain.state = GRAIN_SUSTAIN;
+ }
+ return;
+ }
+
+ // Calculate duration and envelope parameters.
+ StkFloat seconds = gDuration_ * 0.001;
+ seconds += ( seconds * gRandomFactor_ * noise.tick() );
+ unsigned int count = (unsigned long) ( seconds * Stk::sampleRate() );
+ grain.attackCount = (unsigned int) ( gRampPercent_ * 0.005 * count );
+ grain.decayCount = grain.attackCount;
+ grain.sustainCount = count - 2 * grain.attackCount;
+ grain.eScaler = 0.0;
+ if ( grain.attackCount > 0 ) {
+ grain.eRate = 1.0 / grain.attackCount;
+ grain.counter = grain.attackCount;
+ grain.state = GRAIN_FADEIN;
+ }
+ else {
+ grain.counter = grain.sustainCount;
+ grain.state = GRAIN_SUSTAIN;
+ }
+
+ // Calculate delay parameter.
+ seconds = gDelay_ * 0.001;
+ seconds += ( seconds * gRandomFactor_ * noise.tick() );
+ count = (unsigned long) ( seconds * Stk::sampleRate() );
+ grain.delayCount = count;
+
+ // Save stretch parameter.
+ grain.repeats = gStretch_;
+
+ // Calculate offset parameter.
+ seconds = gOffset_ * 0.001;
+ seconds += ( seconds * gRandomFactor_ * std::abs( noise.tick() ) );
+ int offset = (int) ( seconds * Stk::sampleRate() );
+
+ // Add some randomization to the pointer start position.
+ seconds = gDuration_ * 0.001 * gRandomFactor_ * noise.tick();
+ offset += (int) ( seconds * Stk::sampleRate() );
+ grain.pointer += offset;
+ while ( grain.pointer >= data_.frames() ) grain.pointer -= data_.frames();
+ if ( grain.pointer < 0 ) grain.pointer = 0;
+ grain.startPointer = grain.pointer;
+}
+
+StkFloat Granulate :: tick( unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel >= data_.channels() ) {
+ errorString_ << "Granulate::tick(): channel argument and soundfile data are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ unsigned int i, j, nChannels = lastFrame_.channels();
+ for ( j=0; j<nChannels; j++ ) lastFrame_[j] = 0.0;
+
+ if ( data_.size() == 0 ) return 0.0;
+
+ StkFloat sample;
+ for ( i=0; i<grains_.size(); i++ ) {
+
+ if ( grains_[i].counter == 0 ) { // Update the grain state.
+
+ switch ( grains_[i].state ) {
+
+ case GRAIN_STOPPED:
+ // We're done waiting between grains ... setup for new grain
+ this->calculateGrain( grains_[i] );
+ break;
+
+ case GRAIN_FADEIN:
+ // We're done ramping up the envelope
+ if ( grains_[i].sustainCount > 0 ) {
+ grains_[i].counter = grains_[i].sustainCount;
+ grains_[i].state = GRAIN_SUSTAIN;
+ break;
+ }
+ // else no sustain state (i.e. perfect triangle window)
+
+ case GRAIN_SUSTAIN:
+ // We're done with flat part of envelope ... setup to ramp down
+ if ( grains_[i].decayCount > 0 ) {
+ grains_[i].counter = grains_[i].decayCount;
+ grains_[i].eRate = -grains_[i].eRate;
+ grains_[i].state = GRAIN_FADEOUT;
+ break;
+ }
+ // else no fade out state (gRampPercent = 0)
+
+ case GRAIN_FADEOUT:
+ // We're done ramping down ... setup for wait between grains
+ if ( grains_[i].delayCount > 0 ) {
+ grains_[i].counter = grains_[i].delayCount;
+ grains_[i].state = GRAIN_STOPPED;
+ break;
+ }
+ // else no delay (gDelay = 0)
+
+ this->calculateGrain( grains_[i] );
+ }
+ }
+
+ // Accumulate the grain outputs.
+ if ( grains_[i].state > 0 ) {
+ for ( j=0; j<nChannels; j++ ) {
+ sample = data_[ nChannels * grains_[i].pointer + j ];
+
+ if ( grains_[i].state == GRAIN_FADEIN || grains_[i].state == GRAIN_FADEOUT ) {
+ sample *= grains_[i].eScaler;
+ grains_[i].eScaler += grains_[i].eRate;
+ }
+
+ lastFrame_[j] += sample;
+ }
+
+
+ // Increment and check pointer limits.
+ grains_[i].pointer++;
+ if ( grains_[i].pointer >= data_.frames() )
+ grains_[i].pointer = 0;
+ }
+
+ // Decrement counter for all states.
+ grains_[i].counter--;
+ }
+
+ // Increment our global file pointer at the stretch rate.
+ if ( stretchCounter_++ == gStretch_ ) {
+ gPointer_++;
+ if ( (unsigned long) gPointer_ >= data_.frames() ) gPointer_ = 0;
+ stretchCounter_ = 0;
+ }
+
+ return lastFrame_[channel];
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class HevyMetl
+ \brief STK heavy metal FM synthesis instrument.
+
+ This class implements 3 cascade operators with
+ feedback modulation, also referred to as
+ algorithm 3 of the TX81Z.
+
+ Algorithm 3 is : 4--\
+ 3-->2-- + -->1-->Out
+
+ Control Change Numbers:
+ - Total Modulator Index = 2
+ - Modulator Crossfade = 4
+ - LFO Speed = 11
+ - LFO Depth = 1
+ - ADSR 2 & 4 Target = 128
+
+ The basic Chowning/Stanford FM patent expired
+ in 1995, but there exist follow-on patents,
+ mostly assigned to Yamaha. If you are of the
+ type who should worry about this (making
+ money) worry away.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "HevyMetl.h"
+
+namespace stk {
+
+HevyMetl :: HevyMetl( void )
+ : FM()
+{
+ // Concatenate the STK rawwave path to the rawwave files
+ for ( unsigned int i=0; i<3; i++ )
+ waves_[i] = new FileLoop( (Stk::rawwavePath() + "sinewave.raw").c_str(), true );
+ waves_[3] = new FileLoop( (Stk::rawwavePath() + "fwavblnk.raw").c_str(), true );
+
+ this->setRatio(0, 1.0 * 1.000);
+ this->setRatio(1, 4.0 * 0.999);
+ this->setRatio(2, 3.0 * 1.001);
+ this->setRatio(3, 0.5 * 1.002);
+
+ gains_[0] = fmGains_[92];
+ gains_[1] = fmGains_[76];
+ gains_[2] = fmGains_[91];
+ gains_[3] = fmGains_[68];
+
+ adsr_[0]->setAllTimes( 0.001, 0.001, 1.0, 0.01);
+ adsr_[1]->setAllTimes( 0.001, 0.010, 1.0, 0.50);
+ adsr_[2]->setAllTimes( 0.010, 0.005, 1.0, 0.20);
+ adsr_[3]->setAllTimes( 0.030, 0.010, 0.2, 0.20);
+
+ twozero_.setGain( 2.0 );
+ vibrato_.setFrequency( 5.5 );
+ modDepth_ = 0.0;
+}
+
+HevyMetl :: ~HevyMetl( void )
+{
+}
+
+void HevyMetl :: noteOn( StkFloat frequency, StkFloat amplitude )
+{
+ gains_[0] = amplitude * fmGains_[92];
+ gains_[1] = amplitude * fmGains_[76];
+ gains_[2] = amplitude * fmGains_[91];
+ gains_[3] = amplitude * fmGains_[68];
+ this->setFrequency( frequency );
+ this->keyOn();
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "HevyMetl::NoteOn: frequency = " << frequency << ", amplitude = " << amplitude << '.';
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class Iir
+ \brief STK general infinite impulse response filter class.
+
+ This class provides a generic digital filter structure that can be
+ used to implement IIR filters. For filters containing only
+ feedforward terms, the Fir class is slightly more efficient.
+
+ In particular, this class implements the standard difference
+ equation:
+
+ a[0]*y[n] = b[0]*x[n] + ... + b[nb]*x[n-nb] -
+ a[1]*y[n-1] - ... - a[na]*y[n-na]
+
+ If a[0] is not equal to 1, the filter coeffcients are normalized
+ by a[0].
+
+ The \e gain parameter is applied at the filter input and does not
+ affect the coefficient values. The default gain value is 1.0.
+ This structure results in one extra multiply per computed sample,
+ but allows easy control of the overall filter gain.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "Iir.h"
+
+namespace stk {
+
+Iir :: Iir()
+{
+ // The default constructor should setup for pass-through.
+ b_.push_back( 1.0 );
+ a_.push_back( 1.0 );
+
+ inputs_.resize( 1, 1, 0.0 );
+ outputs_.resize( 1, 1, 0.0 );
+}
+
+Iir :: Iir( std::vector<StkFloat> &bCoefficients, std::vector<StkFloat> &aCoefficients )
+{
+ // Check the arguments.
+ if ( bCoefficients.size() == 0 || aCoefficients.size() == 0 ) {
+ errorString_ << "Iir: a and b coefficient vectors must both have size > 0!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+
+ if ( aCoefficients[0] == 0.0 ) {
+ errorString_ << "Iir: a[0] coefficient cannot == 0!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+
+ gain_ = 1.0;
+ b_ = bCoefficients;
+ a_ = aCoefficients;
+
+ inputs_.resize( b_.size(), 1, 0.0 );
+ outputs_.resize( a_.size(), 1, 0.0 );
+ this->clear();
+}
+
+Iir :: ~Iir()
+{
+}
+
+void Iir :: setCoefficients( std::vector<StkFloat> &bCoefficients, std::vector<StkFloat> &aCoefficients, bool clearState )
+{
+ this->setNumerator( bCoefficients, false );
+ this->setDenominator( aCoefficients, false );
+
+ if ( clearState ) this->clear();
+}
+
+void Iir :: setNumerator( std::vector<StkFloat> &bCoefficients, bool clearState )
+{
+ // Check the argument.
+ if ( bCoefficients.size() == 0 ) {
+ errorString_ << "Iir::setNumerator: coefficient vector must have size > 0!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+
+ if ( b_.size() != bCoefficients.size() ) {
+ b_ = bCoefficients;
+ inputs_.resize( b_.size(), 1, 0.0 );
+ }
+ else {
+ for ( unsigned int i=0; i<b_.size(); i++ ) b_[i] = bCoefficients[i];
+ }
+
+ if ( clearState ) this->clear();
+}
+
+void Iir :: setDenominator( std::vector<StkFloat> &aCoefficients, bool clearState )
+{
+ // Check the argument.
+ if ( aCoefficients.size() == 0 ) {
+ errorString_ << "Iir::setDenominator: coefficient vector must have size > 0!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+
+ if ( aCoefficients[0] == 0.0 ) {
+ errorString_ << "Iir::setDenominator: a[0] coefficient cannot == 0!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+
+ if ( a_.size() != aCoefficients.size() ) {
+ a_ = aCoefficients;
+ outputs_.resize( a_.size(), 1, 0.0 );
+ }
+ else {
+ for ( unsigned int i=0; i<a_.size(); i++ ) a_[i] = aCoefficients[i];
+ }
+
+ if ( clearState ) this->clear();
+
+ // Scale coefficients by a[0] if necessary
+ if ( a_[0] != 1.0 ) {
+ unsigned int i;
+ for ( i=0; i<b_.size(); i++ ) b_[i] /= a_[0];
+ for ( i=1; i<a_.size(); i++ ) a_[i] /= a_[0];
+ }
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class InetWvIn
+ \brief STK internet streaming input class.
+
+ This Wvin subclass reads streamed audio data over a network via a
+ TCP or UDP socket connection. The data is assumed in big-endian,
+ or network, byte order. Only a single socket connection is
+ supported.
+
+ InetWvIn supports multi-channel data. It is important to
+ distinguish the tick() method that computes a single frame (and
+ returns only the specified sample of a multi-channel frame) from
+ the overloaded one that takes an StkFrames object for
+ multi-channel and/or multi-frame data.
+
+ This class implements a socket server. When using the TCP
+ protocol, the server "listens" for a single remote connection
+ within the InetWvIn::start() function. For the UDP protocol, no
+ attempt is made to verify packet delivery or order. The default
+ data type for the incoming stream is signed 16-bit integers,
+ though any of the defined StkFormats are permissible.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "InetWvIn.h"
+
+namespace stk {
+
+extern "C" THREAD_RETURN THREAD_TYPE inputThread( void * ptr )
+{
+ ThreadInfo *info = (ThreadInfo *)ptr;
+
+ while ( !info->finished ) {
+ ((InetWvIn *) info->object)->receive();
+ }
+
+ return 0;
+}
+
+InetWvIn :: InetWvIn( unsigned long bufferFrames, unsigned int nBuffers )
+ :soket_(0), buffer_(0), bufferFrames_(bufferFrames), bufferBytes_(0), nBuffers_(nBuffers), connected_(false)
+{
+ threadInfo_.finished = false;
+ threadInfo_.object = (void *) this;
+
+ // Start the input thread.
+ if ( !thread_.start( &inputThread, &threadInfo_ ) ) {
+ errorString_ << "InetWvIn(): unable to start input thread in constructor!";
+ handleError( StkError::PROCESS_THREAD );
+ }
+}
+
+InetWvIn :: ~InetWvIn()
+{
+ // Close down the thread.
+ connected_ = false;
+ threadInfo_.finished = true;
+
+ if ( soket_ ) delete soket_;
+ if ( buffer_ ) delete [] buffer_;
+}
+
+void InetWvIn :: listen( int port, unsigned int nChannels,
+ Stk::StkFormat format, Socket::ProtocolType protocol )
+{
+ mutex_.lock();
+
+ if ( connected_ ) delete soket_;
+
+ if ( nChannels < 1 ) {
+ errorString_ << "InetWvIn()::listen(): the channel argument (" << nChannels << ") must be greater than zero.";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+
+ if ( format == STK_SINT16 ) dataBytes_ = 2;
+ else if ( format == STK_SINT32 || format == STK_FLOAT32 ) dataBytes_ = 4;
+ else if ( format == STK_FLOAT64 ) dataBytes_ = 8;
+ else if ( format == STK_SINT8 ) dataBytes_ = 1;
+ else {
+ errorString_ << "InetWvIn(): unknown data type specified (" << format << ").";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+ dataType_ = format;
+
+ unsigned long bufferBytes = bufferFrames_ * nBuffers_ * nChannels * dataBytes_;
+ if ( bufferBytes > bufferBytes_ ) {
+ if ( buffer_) delete [] buffer_;
+ buffer_ = (char *) new char[ bufferBytes ];
+ bufferBytes_ = bufferBytes;
+ }
+
+ data_.resize( bufferFrames_, nChannels );
+ lastFrame_.resize( 1, nChannels, 0.0 );
+
+ bufferCounter_ = 0;
+ writePoint_ = 0;
+ readPoint_ = 0;
+ bytesFilled_ = 0;
+
+ if ( protocol == Socket::PROTO_TCP ) {
+ TcpServer *socket = new TcpServer( port );
+ errorString_ << "InetWvIn:listen(): waiting for TCP connection on port " << socket->port() << " ... ";
+ handleError( StkError::STATUS );
+ fd_ = socket->accept();
+ if ( fd_ < 0) {
+ errorString_ << "InetWvIn::listen(): Error accepting TCP connection request!";
+ handleError( StkError::PROCESS_SOCKET );
+ }
+ errorString_ << "InetWvIn::listen(): TCP socket connection made!";
+ handleError( StkError::STATUS );
+ soket_ = (Socket *) socket;
+ }
+ else {
+ soket_ = new StkUdpSocket( port );
+ fd_ = soket_->id();
+ }
+
+ connected_ = true;
+
+ mutex_.unlock();
+}
+
+void InetWvIn :: receive( void )
+{
+ if ( !connected_ ) {
+ Stk::sleep(100);
+ return;
+ }
+
+ fd_set mask;
+ FD_ZERO( &mask );
+ FD_SET( fd_, &mask );
+
+ // The select function will block until data is available for reading.
+ select( fd_+1, &mask, (fd_set *)0, (fd_set *)0, NULL );
+
+ if ( FD_ISSET( fd_, &mask ) ) {
+ mutex_.lock();
+ unsigned long unfilled = bufferBytes_ - bytesFilled_;
+ if ( unfilled > 0 ) {
+ // There's room in our buffer for more data.
+ unsigned long endPoint = writePoint_ + unfilled;
+ if ( endPoint > bufferBytes_ ) unfilled -= endPoint - bufferBytes_;
+ int i = soket_->readBuffer( fd_, (void *)&buffer_[writePoint_], unfilled, 0 );
+ //int i = Socket::readBuffer( fd_, (void *)&buffer_[writePoint_], unfilled, 0 );
+ if ( i <= 0 ) {
+ errorString_ << "InetWvIn::receive(): the remote InetWvIn socket has closed.";
+ handleError( StkError::STATUS );
+ connected_ = false;
+ mutex_.unlock();
+ return;
+ }
+ bytesFilled_ += i;
+ writePoint_ += i;
+ if ( writePoint_ == bufferBytes_ )
+ writePoint_ = 0;
+ mutex_.unlock();
+ }
+ else {
+ // Sleep 10 milliseconds AFTER unlocking mutex.
+ mutex_.unlock();
+ Stk::sleep( 10 );
+ }
+ }
+}
+
+int InetWvIn :: readData( void )
+{
+ // We have two potential courses of action should this method
+ // be called and the input buffer isn't sufficiently filled.
+ // One solution is to fill the data buffer with zeros and return.
+ // The other solution is to wait until the necessary data exists.
+ // I chose the latter, as it works for both streamed files
+ // (non-realtime data transport) and realtime playback (given
+ // adequate network bandwidth and speed).
+
+ // Wait until data is ready.
+ unsigned long bytes = data_.size() * dataBytes_;
+ while ( connected_ && bytesFilled_ < bytes )
+ Stk::sleep( 10 );
+
+ if ( !connected_ && bytesFilled_ == 0 ) return 0;
+ bytes = ( bytesFilled_ < bytes ) ? bytesFilled_ : bytes;
+
+ // Copy samples from buffer to data.
+ StkFloat gain;
+ long samples = bytes / dataBytes_;
+ mutex_.lock();
+ if ( dataType_ == STK_SINT16 ) {
+ gain = 1.0 / 32767.0;
+ SINT16 *buf = (SINT16 *) (buffer_+readPoint_);
+ for (int i=0; i<samples; i++ ) {
+#ifdef __LITTLE_ENDIAN__
+ swap16((unsigned char *) buf);
+#endif
+ data_[i] = (StkFloat) *buf++;
+ data_[i] *= gain;
+ }
+ }
+ else if ( dataType_ == STK_SINT32 ) {
+ gain = 1.0 / 2147483647.0;
+ SINT32 *buf = (SINT32 *) (buffer_+readPoint_);
+ for (int i=0; i<samples; i++ ) {
+#ifdef __LITTLE_ENDIAN__
+ swap32((unsigned char *) buf);
+#endif
+ data_[i] = (StkFloat) *buf++;
+ data_[i] *= gain;
+ }
+ }
+ else if ( dataType_ == STK_FLOAT32 ) {
+ FLOAT32 *buf = (FLOAT32 *) (buffer_+readPoint_);
+ for (int i=0; i<samples; i++ ) {
+#ifdef __LITTLE_ENDIAN__
+ swap32((unsigned char *) buf);
+#endif
+ data_[i] = (StkFloat) *buf++;
+ }
+ }
+ else if ( dataType_ == STK_FLOAT64 ) {
+ FLOAT64 *buf = (FLOAT64 *) (buffer_+readPoint_);
+ for (int i=0; i<samples; i++ ) {
+#ifdef __LITTLE_ENDIAN__
+ swap64((unsigned char *) buf);
+#endif
+ data_[i] = (StkFloat) *buf++;
+ }
+ }
+ else if ( dataType_ == STK_SINT8 ) {
+ gain = 1.0 / 127.0;
+ signed char *buf = (signed char *) (buffer_+readPoint_);
+ for (int i=0; i<samples; i++ ) {
+ data_[i] = (StkFloat) *buf++;
+ data_[i] *= gain;
+ }
+ }
+
+ readPoint_ += bytes;
+ if ( readPoint_ == bufferBytes_ )
+ readPoint_ = 0;
+ bytesFilled_ -= bytes;
+ if ( bytesFilled_ < 0 )
+ bytesFilled_ = 0;
+
+ mutex_.unlock();
+ return samples / data_.channels();
+}
+
+bool InetWvIn :: isConnected( void )
+{
+ if ( bytesFilled_ > 0 || bufferCounter_ > 0 )
+ return true;
+ else
+ return connected_;
+}
+
+StkFloat InetWvIn :: tick( unsigned int channel )
+{
+ // If no connection and we've output all samples in the queue, return 0.0.
+ if ( !connected_ && bytesFilled_ == 0 && bufferCounter_ == 0 ) {
+#if defined(_STK_DEBUG_)
+ errorString_ << "InetWvIn::tick(): a valid socket connection does not exist!";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+ return 0.0;
+ }
+
+#if defined(_STK_DEBUG_)
+ if ( channel >= data_.channels() ) {
+ errorString_ << "InetWvIn::tick(): channel argument is incompatible with data stream!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ if ( bufferCounter_ == 0 )
+ bufferCounter_ = readData();
+
+ unsigned int nChannels = lastFrame_.channels();
+ long index = ( bufferFrames_ - bufferCounter_ ) * nChannels;
+ for ( unsigned int i=0; i<nChannels; i++ )
+ lastFrame_[i] = data_[index++];
+
+ bufferCounter_--;
+ if ( bufferCounter_ < 0 )
+ bufferCounter_ = 0;
+
+ return lastFrame_[channel];
+}
+
+StkFrames& InetWvIn :: tick( StkFrames& frames )
+{
+#if defined(_STK_DEBUG_)
+ if ( data_.channels() != frames.channels() ) {
+ errorString_ << "InetWvIn::tick(): StkFrames argument is incompatible with streamed channels!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ // If no connection and we've output all samples in the queue, return.
+ if ( !connected_ && bytesFilled_ == 0 && bufferCounter_ == 0 ) {
+#if defined(_STK_DEBUG_)
+ errorString_ << "InetWvIn::tick(): a valid socket connection does not exist!";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+ return frames;
+ }
+
+ unsigned int j, counter = 0;
+ for ( unsigned int i=0; i<frames.frames(); i++ ) {
+ this->tick();
+ for ( j=0; j<lastFrame_.channels(); j++ )
+ frames[counter++] = lastFrame_[j];
+ }
+
+ return frames;
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class InetWvOut
+ \brief STK internet streaming output class.
+
+ This WvOut subclass can stream data over a network via a TCP or
+ UDP socket connection. The data is converted to big-endian byte
+ order, if necessary, before being transmitted.
+
+ InetWvOut supports multi-channel data. It is important to
+ distinguish the tick() method that outputs a single sample to all
+ channels in a sample frame from the overloaded one that takes a
+ reference to an StkFrames object for multi-channel and/or
+ multi-frame data.
+
+ This class connects to a socket server, the port and IP address of
+ which must be specified as constructor arguments. The default
+ data type is signed 16-bit integers but any of the defined
+ StkFormats are permissible.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "InetWvOut.h"
+#include "TcpClient.h"
+#include "StkUdpSocket.h"
+
+namespace stk {
+
+InetWvOut :: InetWvOut( unsigned long packetFrames )
+ : buffer_(0), soket_(0), bufferFrames_(packetFrames), bufferBytes_(0)
+{
+}
+
+InetWvOut :: InetWvOut( int port, Socket::ProtocolType protocol, std::string hostname,
+ unsigned int nChannels, Stk::StkFormat format, unsigned long packetFrames )
+ : buffer_(0), soket_(0), bufferFrames_(packetFrames), bufferBytes_(0)
+{
+ connect( port, protocol, hostname, nChannels, format );
+}
+
+InetWvOut :: ~InetWvOut()
+{
+ disconnect();
+ if ( soket_ ) delete soket_;
+ if ( buffer_ ) delete [] buffer_;
+}
+
+void InetWvOut :: connect( int port, Socket::ProtocolType protocol, std::string hostname,
+ unsigned int nChannels, Stk::StkFormat format )
+{
+ if ( soket_ && soket_->isValid( soket_->id() ) )
+ disconnect();
+
+ if ( nChannels == 0 ) {
+ errorString_ << "InetWvOut::connect: the channel argument (" << nChannels << ") must be greater than zero!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+
+ if ( format == STK_SINT8 ) dataBytes_ = 1;
+ else if ( format == STK_SINT16 ) dataBytes_ = 2;
+ else if ( format == STK_SINT32 || format == STK_FLOAT32 ) dataBytes_ = 4;
+ else if ( format == STK_FLOAT64 ) dataBytes_ = 8;
+ else {
+ errorString_ << "InetWvOut::connect: unknown data type specified (" << format << ").";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+ dataType_ = format;
+
+ if ( protocol == Socket::PROTO_TCP ) {
+ soket_ = new TcpClient( port, hostname );
+ }
+ else {
+ // For UDP sockets, the sending and receiving sockets cannot have
+ // the same port number. Since the port argument corresponds to
+ // the destination port, we will associate this socket instance
+ // with a different port number (arbitrarily determined as port -
+ // 1).
+ StkUdpSocket *socket = new StkUdpSocket( port - 1 );
+ socket->setDestination( port, hostname );
+ soket_ = (Socket *) socket;
+ }
+
+ // Allocate new memory if necessary.
+ data_.resize( bufferFrames_, nChannels );
+ unsigned long bufferBytes = dataBytes_ * bufferFrames_ * nChannels;
+ if ( bufferBytes > bufferBytes_ ) {
+ if ( buffer_) delete [] buffer_;
+ buffer_ = (char *) new char[ bufferBytes ];
+ bufferBytes_ = bufferBytes;
+ }
+ frameCounter_ = 0;
+ bufferIndex_ = 0;
+ iData_ = 0;
+}
+
+void InetWvOut :: disconnect(void)
+{
+ if ( soket_ ) {
+ writeData( bufferIndex_ );
+ soket_->close( soket_->id() );
+ delete soket_;
+ soket_ = 0;
+ }
+}
+
+void InetWvOut :: writeData( unsigned long frames )
+{
+ unsigned long samples = frames * data_.channels();
+ if ( dataType_ == STK_SINT8 ) {
+ signed char *ptr = (signed char *) buffer_;
+ for ( unsigned long k=0; k<samples; k++ ) {
+ this->clipTest( data_[k] );
+ *ptr++ = (signed char) (data_[k] * 127.0);
+ }
+ }
+ else if ( dataType_ == STK_SINT16 ) {
+ SINT16 *ptr = (SINT16 *) buffer_;
+ for ( unsigned long k=0; k<samples; k++ ) {
+ this->clipTest( data_[k] );
+ *ptr = (SINT16) (data_[k] * 32767.0);
+#ifdef __LITTLE_ENDIAN__
+ swap16 ((unsigned char *)ptr);
+#endif
+ ptr++;
+ }
+ }
+ else if ( dataType_ == STK_SINT32 ) {
+ SINT32 *ptr = (SINT32 *) buffer_;
+ for ( unsigned long k=0; k<samples; k++ ) {
+ this->clipTest( data_[k] );
+ *ptr = (SINT32) (data_[k] * 2147483647.0);
+#ifdef __LITTLE_ENDIAN__
+ swap32 ((unsigned char *)ptr);
+#endif
+ ptr++;
+ }
+ }
+ else if ( dataType_ == STK_FLOAT32 ) {
+ FLOAT32 *ptr = (FLOAT32 *) buffer_;
+ for ( unsigned long k=0; k<samples; k++ ) {
+ this->clipTest( data_[k] );
+ *ptr = (FLOAT32) data_[k];
+#ifdef __LITTLE_ENDIAN__
+ swap32 ((unsigned char *)ptr);
+#endif
+ ptr++;
+ }
+ }
+ else if ( dataType_ == STK_FLOAT64 ) {
+ FLOAT64 *ptr = (FLOAT64 *) buffer_;
+ for ( unsigned long k=0; k<samples; k++ ) {
+ this->clipTest( data_[k] );
+ *ptr = (FLOAT64) data_[k];
+#ifdef __LITTLE_ENDIAN__
+ swap64 ((unsigned char *)ptr);
+#endif
+ ptr++;
+ }
+ }
+
+ long bytes = dataBytes_ * samples;
+ if ( soket_->writeBuffer( (const void *)buffer_, bytes, 0 ) < 0 ) {
+ errorString_ << "InetWvOut: connection to socket server failed!";
+ handleError( StkError::PROCESS_SOCKET );
+ }
+}
+
+void InetWvOut :: incrementFrame( void )
+{
+ frameCounter_++;
+ bufferIndex_++;
+
+ if ( bufferIndex_ == bufferFrames_ ) {
+ writeData( bufferFrames_ );
+ bufferIndex_ = 0;
+ iData_ = 0;
+ }
+}
+
+void InetWvOut :: tick( const StkFloat sample )
+{
+ if ( !soket_ || !soket_->isValid( soket_->id() ) ) {
+#if defined(_STK_DEBUG_)
+ errorString_ << "InetWvOut::tick(): a valid socket connection does not exist!";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+ return;
+ }
+
+ unsigned int nChannels = data_.channels();
+ StkFloat input = sample;
+ clipTest( input );
+ for ( unsigned int j=0; j<nChannels; j++ )
+ data_[iData_++] = input;
+
+ this->incrementFrame();
+}
+
+void InetWvOut :: tick( const StkFrames& frames )
+{
+ if ( !soket_ || !soket_->isValid( soket_->id() ) ) {
+#if defined(_STK_DEBUG_)
+ errorString_ << "InetWvOut::tick(): a valid socket connection does not exist!";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+ return;
+ }
+
+#if defined(_STK_DEBUG_)
+ if ( data_.channels() != frames.channels() ) {
+ errorString_ << "InetWvOut::tick(): incompatible channel value in StkFrames argument!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ unsigned int j, nChannels = data_.channels();
+ unsigned int iFrames = 0;
+ for ( unsigned int i=0; i<frames.frames(); i++ ) {
+
+ for ( j=0; j<nChannels; j++ ) {
+ data_[iData_] = frames[iFrames++];
+ clipTest( data_[iData_++] );
+ }
+
+ this->incrementFrame();
+ }
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class JCRev
+ \brief John Chowning's reverberator class.
+
+ This class takes a monophonic input signal and produces a stereo
+ output signal. It is derived from the CLM JCRev function, which
+ is based on the use of networks of simple allpass and comb delay
+ filters. This class implements three series allpass units,
+ followed by four parallel comb filters, and two decorrelation
+ delay lines in parallel at the output.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "JCRev.h"
+#include <cmath>
+
+namespace stk {
+
+JCRev :: JCRev( StkFloat T60 )
+{
+ lastFrame_.resize( 1, 2, 0.0 ); // resize lastFrame_ for stereo output
+
+ // Delay lengths for 44100 Hz sample rate.
+ int lengths[9] = {1777, 1847, 1993, 2137, 389, 127, 43, 211, 179};
+ double scaler = Stk::sampleRate() / 44100.0;
+
+ int delay, i;
+ if ( scaler != 1.0 ) {
+ for ( i=0; i<9; i++ ) {
+ delay = (int) floor( scaler * lengths[i] );
+ if ( (delay & 1) == 0) delay++;
+ while ( !this->isPrime(delay) ) delay += 2;
+ lengths[i] = delay;
+ }
+ }
+
+ for ( i=0; i<3; i++ ) {
+ allpassDelays_[i].setMaximumDelay( lengths[i+4] );
+ allpassDelays_[i].setDelay( lengths[i+4] );
+ }
+
+ for ( i=0; i<4; i++ ) {
+ combDelays_[i].setMaximumDelay( lengths[i] );
+ combDelays_[i].setDelay( lengths[i] );
+ }
+
+ this->setT60( T60 );
+ outLeftDelay_.setMaximumDelay( lengths[7] );
+ outLeftDelay_.setDelay( lengths[7] );
+ outRightDelay_.setMaximumDelay( lengths[8] );
+ outRightDelay_.setDelay( lengths[8] );
+ allpassCoefficient_ = 0.7;
+ effectMix_ = 0.3;
+ this->clear();
+}
+
+void JCRev :: clear()
+{
+ allpassDelays_[0].clear();
+ allpassDelays_[1].clear();
+ allpassDelays_[2].clear();
+ combDelays_[0].clear();
+ combDelays_[1].clear();
+ combDelays_[2].clear();
+ combDelays_[3].clear();
+ outRightDelay_.clear();
+ outLeftDelay_.clear();
+ lastFrame_[0] = 0.0;
+ lastFrame_[1] = 0.0;
+}
+
+void JCRev :: setT60( StkFloat T60 )
+{
+ for ( int i=0; i<4; i++ )
+ combCoefficient_[i] = pow(10.0, (-3.0 * combDelays_[i].getDelay() / (T60 * Stk::sampleRate())));
+}
+
+StkFrames& JCRev :: tick( StkFrames& frames, unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel >= frames.channels() - 1 ) {
+ errorString_ << "JCRev::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *samples = &frames[channel];
+ unsigned int hop = frames.channels();
+ for ( unsigned int i=0; i<frames.frames(); i++, samples += hop ) {
+ *samples = tick( *samples );
+ *samples++;
+ *samples = lastFrame_[1];
+ }
+
+ return frames;
+}
+
+StkFrames& JCRev :: tick( StkFrames& iFrames, StkFrames& oFrames, unsigned int iChannel, unsigned int oChannel )
+{
+#if defined(_STK_DEBUG_)
+ if ( iChannel >= iFrames.channels() || oChannel >= oFrames.channels() - 1 ) {
+ errorString_ << "JCRev::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *iSamples = &iFrames[iChannel];
+ StkFloat *oSamples = &oFrames[oChannel];
+ unsigned int iHop = iFrames.channels(), oHop = oFrames.channels();
+ for ( unsigned int i=0; i<iFrames.frames(); i++, iSamples += iHop, oSamples += oHop ) {
+ *oSamples++ = tick( *iSamples );
+ *oSamples = lastFrame_[1];
+ }
+
+ return iFrames;
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/\r
+/*! \class LentPitShift\r
+ \brief Pitch shifter effect class based on the Lent algorithm.\r
+\r
+ This class implements a pitch shifter using pitch \r
+ tracking and sample windowing and shifting.\r
+\r
+ by Francois Germain, 2009.\r
+*/\r
+/***************************************************/\r
+\r
+#include "LentPitShift.h"\r
+\r
+namespace stk {\r
+\r
+LentPitShift::LentPitShift( StkFloat periodRatio, int tMax )\r
+ : inputFrames(0.,tMax,1), outputFrames(0.,tMax,1), ptrFrames(0), inputPtr(0), outputPtr(0.), tMax_(tMax), periodRatio_(periodRatio), zeroFrame(0., tMax, 1)\r
+{\r
+ window = new StkFloat[2*tMax_]; // Allocation of the array for the hamming window\r
+ threshold_ = 0.1; // Default threshold for pitch tracking\r
+\r
+ dt = new StkFloat[tMax+1]; // Allocation of the euclidian distance coefficient array. The first one is never used.\r
+ cumDt = new StkFloat[tMax+1]; // Allocation of the cumulative sum array\r
+ cumDt[0] = 0.; // Initialization of the first coefficient of the cumulative sum\r
+ dpt = new StkFloat[tMax+1]; // Allocation of the pitch tracking function coefficient array\r
+ dpt[0] = 1.; // Initialization of the first coefficient of dpt which is always the same\r
+\r
+ // Initialisation of the input and output delay lines\r
+ inputLine_.setMaximumDelay( 3 * tMax_ );\r
+ // The delay is choosed such as the coefficients are not read before being finalised.\r
+ outputLine_.setMaximumDelay( 3 * tMax_ );\r
+ outputLine_.setDelay( 3 * tMax_ );\r
+\r
+ //Initialization of the delay line of pitch tracking coefficients\r
+ //coeffLine_ = new Delay[512];\r
+ //for(int i=0;i<tMax_;i++)\r
+ // coeffLine_[i] = new Delay( tMax_, tMax_ );\r
+}\r
+\r
+void LentPitShift :: clear()\r
+{\r
+ inputLine_.clear();\r
+ outputLine_.clear();\r
+}\r
+\r
+void LentPitShift :: setShift( StkFloat shift )\r
+{\r
+ if ( shift <= 0.0 ) periodRatio_ = 1.0;\r
+ periodRatio_ = 1.0 / shift; \r
+}\r
+\r
+} // stk namespace\r
--- /dev/null
+/***************************************************/
+/*! \class Mandolin
+ \brief STK mandolin instrument model class.
+
+ This class inherits from PluckTwo and uses
+ "commuted synthesis" techniques to model a
+ mandolin instrument.
+
+ This is a digital waveguide model, making its
+ use possibly subject to patents held by
+ Stanford University, Yamaha, and others.
+ Commuted Synthesis, in particular, is covered
+ by patents, granted, pending, and/or
+ applied-for. All are assigned to the Board of
+ Trustees, Stanford University. For
+ information, contact the Office of Technology
+ Licensing, Stanford University.
+
+ Control Change Numbers:
+ - Body Size = 2
+ - Pluck Position = 4
+ - String Sustain = 11
+ - String Detuning = 1
+ - Microphone Position = 128
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "Mandolin.h"
+#include "Skini_msg.h"
+
+namespace stk {
+
+Mandolin :: Mandolin( StkFloat lowestFrequency )
+ : PluckTwo( lowestFrequency )
+{
+ // Concatenate the STK rawwave path to the rawwave files
+ soundfile_[0] = new FileWvIn( (Stk::rawwavePath() + "mand1.raw").c_str(), true );
+ soundfile_[1] = new FileWvIn( (Stk::rawwavePath() + "mand2.raw").c_str(), true );
+ soundfile_[2] = new FileWvIn( (Stk::rawwavePath() + "mand3.raw").c_str(), true );
+ soundfile_[3] = new FileWvIn( (Stk::rawwavePath() + "mand4.raw").c_str(), true );
+ soundfile_[4] = new FileWvIn( (Stk::rawwavePath() + "mand5.raw").c_str(), true );
+ soundfile_[5] = new FileWvIn( (Stk::rawwavePath() + "mand6.raw").c_str(), true );
+ soundfile_[6] = new FileWvIn( (Stk::rawwavePath() + "mand7.raw").c_str(), true );
+ soundfile_[7] = new FileWvIn( (Stk::rawwavePath() + "mand8.raw").c_str(), true );
+ soundfile_[8] = new FileWvIn( (Stk::rawwavePath() + "mand9.raw").c_str(), true );
+ soundfile_[9] = new FileWvIn( (Stk::rawwavePath() + "mand10.raw").c_str(), true );
+ soundfile_[10] = new FileWvIn( (Stk::rawwavePath() + "mand11.raw").c_str(), true );
+ soundfile_[11] = new FileWvIn( (Stk::rawwavePath() + "mand12.raw").c_str(), true );
+
+ mic_ = 0;
+ dampTime_ = 0;
+ waveDone_ = soundfile_[mic_]->isFinished();
+}
+
+Mandolin :: ~Mandolin( void )
+{
+ for ( int i=0; i<12; i++ )
+ delete soundfile_[i];
+}
+
+void Mandolin :: pluck( StkFloat amplitude )
+{
+ // This function gets interesting, because pluck
+ // may be longer than string length, so we just
+ // reset the soundfile and add in the pluck in
+ // the tick method.
+ soundfile_[mic_]->reset();
+ waveDone_ = false;
+ pluckAmplitude_ = amplitude;
+ if ( amplitude < 0.0 ) {
+ errorString_ << "Mandolin::pluck: amplitude parameter less than zero ... setting to 0.0!";
+ handleError( StkError::WARNING );
+ pluckAmplitude_ = 0.0;
+ }
+ else if ( amplitude > 1.0 ) {
+ errorString_ << "Mandolin::pluck: amplitude parameter greater than one ... setting to 1.0!";
+ handleError( StkError::WARNING );
+ pluckAmplitude_ = 1.0;
+ }
+
+ // Set the pick position, which puts zeroes at position * length.
+ combDelay_.setDelay( 0.5 * pluckPosition_ * lastLength_ );
+ dampTime_ = (long) lastLength_; // See tick method below.
+}
+
+void Mandolin :: pluck( StkFloat amplitude, StkFloat position )
+{
+ // Pluck position puts zeroes at position * length.
+ pluckPosition_ = position;
+ if ( position < 0.0 ) {
+ std::cerr << "Mandolin::pluck: position parameter less than zero ... setting to 0.0!";
+ handleError( StkError::WARNING );
+ pluckPosition_ = 0.0;
+ }
+ else if ( position > 1.0 ) {
+ errorString_ << "Mandolin::pluck: amplitude parameter greater than one ... setting to 1.0!";
+ handleError( StkError::WARNING );
+ pluckPosition_ = 1.0;
+ }
+
+ this->pluck( amplitude );
+}
+
+void Mandolin :: noteOn( StkFloat frequency, StkFloat amplitude )
+{
+ this->setFrequency( frequency );
+ this->pluck( amplitude );
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Mandolin::NoteOn: frequency = " << frequency << ", amplitude = " << amplitude << ".";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+void Mandolin :: setBodySize( StkFloat size )
+{
+ // Scale the commuted body response by its sample rate (22050).
+ StkFloat rate = size * 22050.0 / Stk::sampleRate();
+ for ( int i=0; i<12; i++ )
+ soundfile_[i]->setRate( rate );
+}
+
+void Mandolin :: controlChange( int number, StkFloat value )
+{
+ StkFloat norm = value * ONE_OVER_128;
+ if ( norm < 0 ) {
+ norm = 0.0;
+ errorString_ << "Mandolin::controlChange: control value less than zero ... setting to zero!";
+ handleError( StkError::WARNING );
+ }
+ else if ( norm > 1.0 ) {
+ norm = 1.0;
+ errorString_ << "Mandolin::controlChange: control value greater than 128.0 ... setting to 128.0!";
+ handleError( StkError::WARNING );
+ }
+
+ if (number == __SK_BodySize_) // 2
+ this->setBodySize( norm * 2.0 );
+ else if (number == __SK_PickPosition_) // 4
+ this->setPluckPosition( norm );
+ else if (number == __SK_StringDamping_) // 11
+ this->setBaseLoopGain( 0.97 + (norm * 0.03));
+ else if (number == __SK_StringDetune_) // 1
+ this->setDetune( 1.0 - (norm * 0.1) );
+ else if (number == __SK_AfterTouch_Cont_) // 128
+ mic_ = (int) (norm * 11.0);
+ else {
+ errorString_ << "Mandolin::controlChange: undefined control number (" << number << ")!";
+ handleError( StkError::WARNING );
+ }
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Mandolin::controlChange: number = " << number << ", value = " << value << ".";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class Mesh2D
+ \brief Two-dimensional rectilinear waveguide mesh class.
+
+ This class implements a rectilinear,
+ two-dimensional digital waveguide mesh
+ structure. For details, see Van Duyne and
+ Smith, "Physical Modeling with the 2-D Digital
+ Waveguide Mesh", Proceedings of the 1993
+ International Computer Music Conference.
+
+ This is a digital waveguide model, making its
+ use possibly subject to patents held by Stanford
+ University, Yamaha, and others.
+
+ Control Change Numbers:
+ - X Dimension = 2
+ - Y Dimension = 4
+ - Mesh Decay = 11
+ - X-Y Input Position = 1
+
+ by Julius Smith, 2000 - 2002.
+ Revised by Gary Scavone for STK, 2002.
+*/
+/***************************************************/
+
+#include "Mesh2D.h"
+#include "Skini_msg.h"
+
+namespace stk {
+
+Mesh2D :: Mesh2D( short nX, short nY )
+{
+ this->setNX(nX);
+ this->setNY(nY);
+
+ StkFloat pole = 0.05;
+
+ short i;
+ for (i=0; i<NYMAX; i++) {
+ filterY_[i].setPole( pole );
+ filterY_[i].setGain( 0.99 );
+ }
+
+ for (i=0; i<NXMAX; i++) {
+ filterX_[i].setPole( pole );
+ filterX_[i].setGain( 0.99 );
+ }
+
+ this->clearMesh();
+
+ counter_=0;
+ xInput_ = 0;
+ yInput_ = 0;
+}
+
+Mesh2D :: ~Mesh2D( void )
+{
+}
+
+void Mesh2D :: clear( void )
+{
+ this->clearMesh();
+
+ short i;
+ for (i=0; i<NY_; i++)
+ filterY_[i].clear();
+
+ for (i=0; i<NX_; i++)
+ filterX_[i].clear();
+
+ counter_=0;
+}
+
+void Mesh2D :: clearMesh( void )
+{
+ int x, y;
+ for (x=0; x<NXMAX-1; x++) {
+ for (y=0; y<NYMAX-1; y++) {
+ v_[x][y] = 0;
+ }
+ }
+ for (x=0; x<NXMAX; x++) {
+ for (y=0; y<NYMAX; y++) {
+
+ vxp_[x][y] = 0;
+ vxm_[x][y] = 0;
+ vyp_[x][y] = 0;
+ vym_[x][y] = 0;
+
+ vxp1_[x][y] = 0;
+ vxm1_[x][y] = 0;
+ vyp1_[x][y] = 0;
+ vym1_[x][y] = 0;
+ }
+ }
+}
+
+StkFloat Mesh2D :: energy( void )
+{
+ // Return total energy contained in wave variables Note that some
+ // energy is also contained in any filter delay elements.
+
+ int x, y;
+ StkFloat t;
+ StkFloat e = 0;
+ if ( counter_ & 1 ) { // Ready for Mesh2D::tick1() to be called.
+ for (x=0; x<NX_; x++) {
+ for (y=0; y<NY_; y++) {
+ t = vxp1_[x][y];
+ e += t*t;
+ t = vxm1_[x][y];
+ e += t*t;
+ t = vyp1_[x][y];
+ e += t*t;
+ t = vym1_[x][y];
+ e += t*t;
+ }
+ }
+ }
+ else { // Ready for Mesh2D::tick0() to be called.
+ for (x=0; x<NX_; x++) {
+ for (y=0; y<NY_; y++) {
+ t = vxp_[x][y];
+ e += t*t;
+ t = vxm_[x][y];
+ e += t*t;
+ t = vyp_[x][y];
+ e += t*t;
+ t = vym_[x][y];
+ e += t*t;
+ }
+ }
+ }
+
+ return(e);
+}
+
+void Mesh2D :: setNX( short lenX )
+{
+ NX_ = lenX;
+ if ( lenX < 2 ) {
+ errorString_ << "Mesh2D::setNX(" << lenX << "): Minimum length is 2!";
+ handleError( StkError::WARNING );
+ NX_ = 2;
+ }
+ else if ( lenX > NXMAX ) {
+ errorString_ << "Mesh2D::setNX(" << lenX << "): Maximum length is " << NXMAX << '!';;
+ handleError( StkError::WARNING );
+ NX_ = NXMAX;
+ }
+}
+
+void Mesh2D :: setNY( short lenY )
+{
+ NY_ = lenY;
+ if ( lenY < 2 ) {
+ errorString_ << "Mesh2D::setNY(" << lenY << "): Minimum length is 2!";
+ handleError( StkError::WARNING );
+ NY_ = 2;
+ }
+ else if ( lenY > NYMAX ) {
+ errorString_ << "Mesh2D::setNY(" << lenY << "): Maximum length is " << NXMAX << '!';;
+ handleError( StkError::WARNING );
+ NY_ = NYMAX;
+ }
+}
+
+void Mesh2D :: setDecay( StkFloat decayFactor )
+{
+ StkFloat gain = decayFactor;
+ if ( decayFactor < 0.0 ) {
+ errorString_ << "Mesh2D::setDecay: decayFactor value is less than 0.0!";
+ handleError( StkError::WARNING );
+ gain = 0.0;
+ }
+ else if ( decayFactor > 1.0 ) {
+ errorString_ << "Mesh2D::setDecay decayFactor value is greater than 1.0!";
+ handleError( StkError::WARNING );
+ gain = 1.0;
+ }
+
+ int i;
+ for (i=0; i<NYMAX; i++)
+ filterY_[i].setGain( gain );
+
+ for (i=0; i<NXMAX; i++)
+ filterX_[i].setGain( gain );
+}
+
+void Mesh2D :: setInputPosition( StkFloat xFactor, StkFloat yFactor )
+{
+ if ( xFactor < 0.0 ) {
+ errorString_ << "Mesh2D::setInputPosition xFactor value is less than 0.0!";
+ handleError( StkError::WARNING );
+ xInput_ = 0;
+ }
+ else if ( xFactor > 1.0 ) {
+ errorString_ << "Mesh2D::setInputPosition xFactor value is greater than 1.0!";
+ handleError( StkError::WARNING );
+ xInput_ = NX_ - 1;
+ }
+ else
+ xInput_ = (short) (xFactor * (NX_ - 1));
+
+ if ( yFactor < 0.0 ) {
+ errorString_ << "Mesh2D::setInputPosition yFactor value is less than 0.0!";
+ handleError( StkError::WARNING );
+ yInput_ = 0;
+ }
+ else if ( yFactor > 1.0 ) {
+ errorString_ << "Mesh2D::setInputPosition yFactor value is greater than 1.0!";
+ handleError( StkError::WARNING );
+ yInput_ = NY_ - 1;
+ }
+ else
+ yInput_ = (short) (yFactor * (NY_ - 1));
+}
+
+void Mesh2D :: noteOn( StkFloat frequency, StkFloat amplitude )
+{
+ // Input at corner.
+ if ( counter_ & 1 ) {
+ vxp1_[xInput_][yInput_] += amplitude;
+ vyp1_[xInput_][yInput_] += amplitude;
+ }
+ else {
+ vxp_[xInput_][yInput_] += amplitude;
+ vyp_[xInput_][yInput_] += amplitude;
+ }
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Mesh2D::NoteOn: frequency = " << frequency << ", amplitude = " << amplitude << ".";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+void Mesh2D :: noteOff( StkFloat amplitude )
+{
+#if defined(_STK_DEBUG_)
+ errorString_ << "Mesh2D::NoteOff: amplitude = " << amplitude << ".";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+StkFloat Mesh2D :: inputTick( StkFloat input )
+{
+ if ( counter_ & 1 ) {
+ vxp1_[xInput_][yInput_] += input;
+ vyp1_[xInput_][yInput_] += input;
+ lastFrame_[0] = tick1();
+ }
+ else {
+ vxp_[xInput_][yInput_] += input;
+ vyp_[xInput_][yInput_] += input;
+ lastFrame_[0] = tick0();
+ }
+
+ counter_++;
+ return lastFrame_[0];
+}
+
+StkFloat Mesh2D :: tick( unsigned int )
+{
+ lastFrame_[0] = ((counter_ & 1) ? this->tick1() : this->tick0());
+ counter_++;
+ return lastFrame_[0];
+}
+
+const StkFloat VSCALE = 0.5;
+
+StkFloat Mesh2D :: tick0( void )
+{
+ int x, y;
+ StkFloat outsamp = 0;
+
+ // Update junction velocities.
+ for (x=0; x<NX_-1; x++) {
+ for (y=0; y<NY_-1; y++) {
+ v_[x][y] = ( vxp_[x][y] + vxm_[x+1][y] +
+ vyp_[x][y] + vym_[x][y+1] ) * VSCALE;
+ }
+ }
+
+ // Update junction outgoing waves, using alternate wave-variable buffers.
+ for (x=0; x<NX_-1; x++) {
+ for (y=0; y<NY_-1; y++) {
+ StkFloat vxy = v_[x][y];
+ // Update positive-going waves.
+ vxp1_[x+1][y] = vxy - vxm_[x+1][y];
+ vyp1_[x][y+1] = vxy - vym_[x][y+1];
+ // Update minus-going waves.
+ vxm1_[x][y] = vxy - vxp_[x][y];
+ vym1_[x][y] = vxy - vyp_[x][y];
+ }
+ }
+
+ // Loop over velocity-junction boundary faces, update edge
+ // reflections, with filtering. We're only filtering on one x and y
+ // edge here and even this could be made much sparser.
+ for (y=0; y<NY_-1; y++) {
+ vxp1_[0][y] = filterY_[y].tick(vxm_[0][y]);
+ vxm1_[NX_-1][y] = vxp_[NX_-1][y];
+ }
+ for (x=0; x<NX_-1; x++) {
+ vyp1_[x][0] = filterX_[x].tick(vym_[x][0]);
+ vym1_[x][NY_-1] = vyp_[x][NY_-1];
+ }
+
+ // Output = sum of outgoing waves at far corner. Note that the last
+ // index in each coordinate direction is used only with the other
+ // coordinate indices at their next-to-last values. This is because
+ // the "unit strings" attached to each velocity node to terminate
+ // the mesh are not themselves connected together.
+ outsamp = vxp_[NX_-1][NY_-2] + vyp_[NX_-2][NY_-1];
+
+ return outsamp;
+}
+
+StkFloat Mesh2D :: tick1( void )
+{
+ int x, y;
+ StkFloat outsamp = 0;
+
+ // Update junction velocities.
+ for (x=0; x<NX_-1; x++) {
+ for (y=0; y<NY_-1; y++) {
+ v_[x][y] = ( vxp1_[x][y] + vxm1_[x+1][y] +
+ vyp1_[x][y] + vym1_[x][y+1] ) * VSCALE;
+ }
+ }
+
+ // Update junction outgoing waves,
+ // using alternate wave-variable buffers.
+ for (x=0; x<NX_-1; x++) {
+ for (y=0; y<NY_-1; y++) {
+ StkFloat vxy = v_[x][y];
+
+ // Update positive-going waves.
+ vxp_[x+1][y] = vxy - vxm1_[x+1][y];
+ vyp_[x][y+1] = vxy - vym1_[x][y+1];
+
+ // Update minus-going waves.
+ vxm_[x][y] = vxy - vxp1_[x][y];
+ vym_[x][y] = vxy - vyp1_[x][y];
+ }
+ }
+
+ // Loop over velocity-junction boundary faces, update edge
+ // reflections, with filtering. We're only filtering on one x and y
+ // edge here and even this could be made much sparser.
+ for (y=0; y<NY_-1; y++) {
+ vxp_[0][y] = filterY_[y].tick(vxm1_[0][y]);
+ vxm_[NX_-1][y] = vxp1_[NX_-1][y];
+ }
+ for (x=0; x<NX_-1; x++) {
+ vyp_[x][0] = filterX_[x].tick(vym1_[x][0]);
+ vym_[x][NY_-1] = vyp1_[x][NY_-1];
+ }
+
+ // Output = sum of outgoing waves at far corner.
+ outsamp = vxp1_[NX_-1][NY_-2] + vyp1_[NX_-2][NY_-1];
+
+ return outsamp;
+}
+
+void Mesh2D :: controlChange( int number, StkFloat value )
+{
+ StkFloat norm = value * ONE_OVER_128;
+ if ( norm < 0 ) {
+ norm = 0.0;
+ errorString_ << "Mesh2D::controlChange: control value less than zero ... setting to zero!";
+ handleError( StkError::WARNING );
+ }
+ else if ( norm > 1.0 ) {
+ norm = 1.0;
+ errorString_ << "Mesh2D::controlChange: control value greater than 128.0 ... setting to 128.0!";
+ handleError( StkError::WARNING );
+ }
+
+ if (number == 2) // 2
+ this->setNX( (short) (norm * (NXMAX-2) + 2) );
+ else if (number == 4) // 4
+ this->setNY( (short) (norm * (NYMAX-2) + 2) );
+ else if (number == 11) // 11
+ this->setDecay( 0.9 + (norm * 0.1) );
+ else if (number == __SK_ModWheel_) // 1
+ this->setInputPosition( norm, norm );
+ else {
+ errorString_ << "Mesh2D::controlChange: undefined control number (" << number << ")!";
+ handleError( StkError::WARNING );
+ }
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Mesh2D::controlChange: number = " << number << ", value = " << value << ".";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class Messager
+ \brief STK input control message parser.
+
+ This class reads and parses control messages from a variety of
+ sources, such as a scorefile, MIDI port, socket connection, or
+ stdin. MIDI messages are retrieved using the RtMidi class. All
+ other input sources (scorefile, socket, or stdin) are assumed to
+ provide SKINI formatted messages. This class can be compiled with
+ generic, non-realtime support, in which case only scorefile
+ reading is possible.
+
+ The various \e realtime message acquisition mechanisms (from MIDI,
+ socket, or stdin) take place asynchronously, filling the message
+ queue. A call to popMessage() will pop the next available control
+ message from the queue and return it via the referenced Message
+ structure. When a \e non-realtime scorefile is set, it is not
+ possible to start reading realtime input messages (from MIDI,
+ socket, or stdin). Likewise, it is not possible to read from a
+ scorefile when a realtime input mechanism is running.
+
+ When MIDI input is started, input is also automatically read from
+ stdin. This allows for program termination via the terminal
+ window. An __SK_Exit_ message is pushed onto the stack whenever
+ an "exit" or "Exit" message is received from stdin or when all
+ socket connections close and no stdin thread is running.
+
+ This class is primarily for use in STK example programs but it is
+ generic enough to work in many other contexts.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "Messager.h"
+#include <iostream>
+#include <algorithm>
+#include "Skini_msg.h"
+
+namespace stk {
+
+#if defined(__STK_REALTIME__)
+
+extern "C" THREAD_RETURN THREAD_TYPE stdinHandler(void * ptr);
+extern "C" THREAD_RETURN THREAD_TYPE socketHandler(void * ptr);
+
+#endif // __STK_REALTIME__
+
+static const int STK_FILE = 0x1;
+static const int STK_MIDI = 0x2;
+static const int STK_STDIN = 0x4;
+static const int STK_SOCKET = 0x8;
+
+Messager :: Messager()
+{
+ data_.sources = 0;
+ data_.queueLimit = DEFAULT_QUEUE_LIMIT;
+#if defined(__STK_REALTIME__)
+ data_.socket = 0;
+ data_.midi = 0;
+#endif
+}
+
+Messager :: ~Messager()
+{
+ // Clear the queue in case any thread is waiting on its limit.
+#if defined(__STK_REALTIME__)
+ data_.mutex.lock();
+#endif
+ while ( data_.queue.size() ) data_.queue.pop();
+ data_.sources = 0;
+
+#if defined(__STK_REALTIME__)
+ data_.mutex.unlock();
+ if ( data_.socket ) {
+ socketThread_.wait();
+ delete data_.socket;
+ }
+
+ if ( data_.midi ) delete data_.midi;
+#endif
+}
+
+bool Messager :: setScoreFile( const char* filename )
+{
+ if ( data_.sources ) {
+ if ( data_.sources == STK_FILE ) {
+ errorString_ << "Messager::setScoreFile: already reading a scorefile!";
+ handleError( StkError::WARNING );
+ }
+ else {
+ errorString_ << "Messager::setScoreFile: already reading realtime control input ... cannot do scorefile input too!";
+ handleError( StkError::WARNING );
+ }
+ return false;
+ }
+
+ if ( !data_.skini.setFile( filename ) ) return false;
+ data_.sources = STK_FILE;
+ return true;
+}
+
+void Messager :: popMessage( Skini::Message& message )
+{
+ if ( data_.sources == STK_FILE ) { // scorefile input
+ if ( !data_.skini.nextMessage( message ) )
+ message.type = __SK_Exit_;
+ return;
+ }
+
+ if ( data_.queue.size() == 0 ) {
+ // An empty (or invalid) message is indicated by a type = 0.
+ message.type = 0;
+ return;
+ }
+
+ // Copy queued message to the message pointer structure and then "pop" it.
+#if defined(__STK_REALTIME__)
+ data_.mutex.lock();
+#endif
+ message = data_.queue.front();
+ data_.queue.pop();
+#if defined(__STK_REALTIME__)
+ data_.mutex.unlock();
+#endif
+}
+
+void Messager :: pushMessage( Skini::Message& message )
+{
+#if defined(__STK_REALTIME__)
+ data_.mutex.lock();
+#endif
+ data_.queue.push( message );
+#if defined(__STK_REALTIME__)
+ data_.mutex.unlock();
+#endif
+}
+
+#if defined(__STK_REALTIME__)
+
+bool Messager :: startStdInput()
+{
+ if ( data_.sources == STK_FILE ) {
+ errorString_ << "Messager::startStdInput: already reading a scorefile ... cannot do realtime control input too!";
+ handleError( StkError::WARNING );
+ return false;
+ }
+
+ if ( data_.sources & STK_STDIN ) {
+ errorString_ << "Messager::startStdInput: stdin input thread already started.";
+ handleError( StkError::WARNING );
+ return false;
+ }
+
+ // Start the stdin input thread.
+ if ( !stdinThread_.start( (THREAD_FUNCTION)&stdinHandler, &data_ ) ) {
+ errorString_ << "Messager::startStdInput: unable to start stdin input thread!";
+ handleError( StkError::WARNING );
+ return false;
+ }
+ data_.sources |= STK_STDIN;
+ return true;
+}
+
+THREAD_RETURN THREAD_TYPE stdinHandler(void *ptr)
+{
+ Messager::MessagerData *data = (Messager::MessagerData *) ptr;
+ Skini::Message message;
+
+ std::string line;
+ while ( !std::getline( std::cin, line).eof() ) {
+ if ( line.empty() ) continue;
+ if ( line.compare(0, 4, "Exit") == 0 || line.compare(0, 4, "exit") == 0 )
+ break;
+
+ data->mutex.lock();
+ if ( data->skini.parseString( line, message ) )
+ data->queue.push( message );
+ data->mutex.unlock();
+
+ while ( data->queue.size() >= data->queueLimit ) Stk::sleep( 50 );
+ }
+
+ // We assume here that if someone types an "exit" message in the
+ // terminal window, all processing should stop.
+ message.type = __SK_Exit_;
+ data->queue.push( message );
+ data->sources &= ~STK_STDIN;
+
+ return NULL;
+}
+
+void midiHandler( double timeStamp, std::vector<unsigned char> *bytes, void *ptr )
+{
+ if ( bytes->size() < 2 ) return;
+
+ // Parse the MIDI bytes ... only keep MIDI channel messages.
+ if ( bytes->at(0) > 239 ) return;
+
+ Messager::MessagerData *data = (Messager::MessagerData *) ptr;
+ Skini::Message message;
+
+ message.type = bytes->at(0) & 0xF0;
+ message.channel = bytes->at(0) & 0x0F;
+ message.time = 0.0; // realtime messages should have delta time = 0.0
+ message.intValues[0] = bytes->at(1);
+ message.floatValues[0] = (StkFloat) message.intValues[0];
+ if ( ( message.type != 0xC0 ) && ( message.type != 0xD0 ) ) {
+ if ( bytes->size() < 3 ) return;
+ message.intValues[1] = bytes->at(2);
+ message.floatValues[1] = (StkFloat) message.intValues[1];
+ }
+
+ while ( data->queue.size() >= data->queueLimit ) Stk::sleep( 50 );
+
+ data->mutex.lock();
+ data->queue.push( message );
+ data->mutex.unlock();
+}
+
+bool Messager :: startMidiInput( int port )
+{
+ if ( data_.sources == STK_FILE ) {
+ errorString_ << "Messager::startMidiInput: already reading a scorefile ... cannot do realtime control input too!";
+ handleError( StkError::WARNING );
+ return false;
+ }
+
+ if ( data_.sources & STK_MIDI ) {
+ errorString_ << "Messager::startMidiInput: MIDI input already started.";
+ handleError( StkError::WARNING );
+ return false;
+ }
+
+ // First start the stdin input thread if it isn't already running
+ // (to allow the user to exit).
+ if ( !( data_.sources & STK_STDIN ) ) {
+ if ( this->startStdInput() == false ) {
+ errorString_ << "Messager::startMidiInput: unable to start input from stdin.";
+ handleError( StkError::WARNING );
+ return false;
+ }
+ }
+
+ try {
+ data_.midi = new RtMidiIn();
+ data_.midi->setCallback( &midiHandler, (void *) &data_ );
+ if ( port == -1 ) data_.midi->openVirtualPort();
+ else data_.midi->openPort( (unsigned int)port );
+ }
+ catch ( RtError &error ) {
+ errorString_ << "Messager::startMidiInput: error creating RtMidiIn instance (" << error.getMessage() << ").";
+ handleError( StkError::WARNING );
+ return false;
+ }
+
+ data_.sources |= STK_MIDI;
+ return true;
+}
+
+bool Messager :: startSocketInput( int port )
+{
+ if ( data_.sources == STK_FILE ) {
+ errorString_ << "Messager::startSocketInput: already reading a scorefile ... cannot do realtime control input too!";
+ handleError( StkError::WARNING );
+ return false;
+ }
+
+ if ( data_.sources & STK_SOCKET ) {
+ errorString_ << "Messager::startSocketInput: socket input thread already started.";
+ handleError( StkError::WARNING );
+ return false;
+ }
+
+ // Create the socket server.
+ try {
+ data_.socket = new TcpServer( port );
+ }
+ catch ( StkError& ) {
+ return false;
+ }
+
+ errorString_ << "Socket server listening for connection(s) on port " << port << "...";
+ handleError( StkError::STATUS );
+
+ // Initialize socket descriptor information.
+ FD_ZERO(&data_.mask);
+ int fd = data_.socket->id();
+ FD_SET( fd, &data_.mask );
+ data_.fd.push_back( fd );
+
+ // Start the socket thread.
+ if ( !socketThread_.start( (THREAD_FUNCTION)&socketHandler, &data_ ) ) {
+ errorString_ << "Messager::startSocketInput: unable to start socket input thread!";
+ handleError( StkError::WARNING );
+ return false;
+ }
+
+ data_.sources |= STK_SOCKET;
+ return true;
+}
+
+#if (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__))
+ #include <sys/time.h>
+ #include <errno.h>
+#endif
+
+THREAD_RETURN THREAD_TYPE socketHandler(void *ptr)
+{
+ Messager::MessagerData *data = (Messager::MessagerData *) ptr;
+ Skini::Message message;
+ std::vector<int>& fd = data->fd;
+
+ struct timeval timeout;
+ fd_set rmask;
+ int newfd;
+ unsigned int i;
+ const int bufferSize = 1024;
+ char buffer[bufferSize];
+ int index = 0, bytesRead = 0;
+ std::string line;
+ std::vector<int> fdclose;
+
+ while ( data->sources & STK_SOCKET ) {
+
+ // Use select function to periodically poll socket desriptors.
+ rmask = data->mask;
+ timeout.tv_sec = 0; timeout.tv_usec = 50000; // 50 milliseconds
+ if ( select( fd.back()+1, &rmask, (fd_set *)0, (fd_set *)0, &timeout ) <= 0 ) continue;
+
+ // A file descriptor is set. Check if there's a new socket connection available.
+ if ( FD_ISSET( data->socket->id(), &rmask ) ) {
+
+ // Accept and service new connection.
+ newfd = data->socket->accept();
+ if ( newfd >= 0 ) {
+ std::cout << "New socket connection made.\n" << std::endl;
+
+ // Set the socket to non-blocking mode.
+ Socket::setBlocking( newfd, false );
+
+ // Save the descriptor and update the masks.
+ fd.push_back( newfd );
+ std::sort( fd.begin(), data->fd.end() );
+ FD_SET( newfd, &data->mask );
+ FD_CLR( data->socket->id(), &rmask );
+ }
+ else
+ std::cerr << "Messager: Couldn't accept connection request!\n";
+ }
+
+ // Check the other descriptors.
+ for ( i=0; i<fd.size(); i++ ) {
+
+ if ( !FD_ISSET( fd[i], &rmask ) ) continue;
+
+ // This connection has data. Read and parse it.
+ bytesRead = 0;
+ index = 0;
+#if ( defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__) )
+ errno = 0;
+ while (bytesRead != -1 && errno != EAGAIN) {
+#elif defined(__OS_WINDOWS__)
+ while (bytesRead != SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK) {
+#endif
+
+ while ( index < bytesRead ) {
+ line += buffer[index];
+ if ( buffer[index++] == '\n' ) {
+ data->mutex.lock();
+ if ( line.compare(0, 4, "Exit") == 0 || line.compare(0, 4, "exit") == 0 ) {
+ // Ignore this line and assume the connection will be
+ // closed on a subsequent read call.
+ ;
+ }
+ else if ( data->skini.parseString( line, message ) )
+ data->queue.push( message );
+ data->mutex.unlock();
+ line.erase();
+ }
+ }
+ index = 0;
+
+ bytesRead = Socket::readBuffer(fd[i], buffer, bufferSize, 0);
+ if (bytesRead == 0) {
+ // This socket connection closed.
+ FD_CLR( fd[i], &data->mask );
+ Socket::close( fd[i] );
+ fdclose.push_back( fd[i] );
+ }
+ }
+ }
+
+ // Now remove descriptors for closed connections.
+ for ( i=0; i<fdclose.size(); i++ ) {
+ for ( unsigned int j=0; j<fd.size(); j++ ) {
+ if ( fd[j] == fdclose[i] ) {
+ fd.erase( fd.begin() + j );
+ break;
+ }
+ }
+
+ // Check to see whether all connections are closed. Note that
+ // the server descriptor will always remain.
+ if ( fd.size() == 1 ) {
+ data->sources &= ~STK_SOCKET;
+ if ( data->sources & STK_MIDI )
+ std::cout << "MIDI input still running ... type 'exit<cr>' to quit.\n" << std::endl;
+ else if ( !(data->sources & STK_STDIN) ) {
+ // No stdin thread running, so quit now.
+ message.type = __SK_Exit_;
+ data->queue.push( message );
+ }
+ }
+ fdclose.clear();
+ }
+
+ // Wait until we're below the queue limit.
+ while ( data->queue.size() >= data->queueLimit ) Stk::sleep( 50 );
+ }
+
+ return NULL;
+}
+
+#endif
+
+} // stk namespace
+
--- /dev/null
+/**********************************************************************/
+/*! \class MidiFileIn
+ \brief A standard MIDI file reading/parsing class.
+
+ This class can be used to read events from a standard MIDI file.
+ Event bytes are copied to a C++ vector and must be subsequently
+ interpreted by the user. The function getNextMidiEvent() skips
+ meta and sysex events, returning only MIDI channel messages.
+ Event delta-times are returned in the form of "ticks" and a
+ function is provided to determine the current "seconds per tick".
+ Tempo changes are internally tracked by the class and reflected in
+ the values returned by the function getTickSeconds().
+
+ by Gary P. Scavone, 2003 - 2010.
+*/
+/**********************************************************************/
+
+#include "MidiFileIn.h"
+#include <cstring>
+#include <iostream>
+
+namespace stk {
+
+MidiFileIn :: MidiFileIn( std::string fileName )
+{
+ // Attempt to open the file.
+ file_.open( fileName.c_str(), std::ios::in | std::ios::binary );
+ if ( !file_ ) {
+ errorString_ << "MidiFileIn: error opening or finding file (" << fileName << ").";
+ handleError( StkError::FILE_NOT_FOUND );
+ }
+
+ // Parse header info.
+ char chunkType[4];
+ char buffer[4];
+ SINT32 *length;
+ if ( !file_.read( chunkType, 4 ) ) goto error;
+ if ( !file_.read( buffer, 4 ) ) goto error;
+#ifdef __LITTLE_ENDIAN__
+ swap32((unsigned char *)&buffer);
+#endif
+ length = (SINT32 *) &buffer;
+ if ( strncmp( chunkType, "MThd", 4 ) || ( *length != 6 ) ) {
+ errorString_ << "MidiFileIn: file (" << fileName << ") does not appear to be a MIDI file!";
+ handleError( StkError::FILE_UNKNOWN_FORMAT );
+ }
+
+ // Read the MIDI file format.
+ SINT16 *data;
+ if ( !file_.read( buffer, 2 ) ) goto error;
+#ifdef __LITTLE_ENDIAN__
+ swap16((unsigned char *)&buffer);
+#endif
+ data = (SINT16 *) &buffer;
+ if ( *data < 0 || *data > 2 ) {
+ errorString_ << "MidiFileIn: the file (" << fileName << ") format is invalid!";
+ handleError( StkError::FILE_ERROR );
+ }
+ format_ = *data;
+
+ // Read the number of tracks.
+ if ( !file_.read( buffer, 2 ) ) goto error;
+#ifdef __LITTLE_ENDIAN__
+ swap16((unsigned char *)&buffer);
+#endif
+ if ( format_ == 0 && *data != 1 ) {
+ errorString_ << "MidiFileIn: invalid number of tracks (>1) for a file format = 0!";
+ handleError( StkError::FILE_ERROR );
+ }
+ nTracks_ = *data;
+
+ // Read the beat division.
+ if ( !file_.read( buffer, 2 ) ) goto error;
+#ifdef __LITTLE_ENDIAN__
+ swap16((unsigned char *)&buffer);
+#endif
+ division_ = (int) *data;
+ double tickrate;
+ usingTimeCode_ = false;
+ if ( *data & 0x8000 ) {
+ // Determine ticks per second from time-code formats.
+ tickrate = (double) -(*data & 0x7F00);
+ // If frames per second value is 29, it really should be 29.97.
+ if ( tickrate == 29.0 ) tickrate = 29.97;
+ tickrate *= (*data & 0x00FF);
+ usingTimeCode_ = true;
+ }
+ else {
+ tickrate = (double) (*data & 0x7FFF); // ticks per quarter note
+ }
+
+ // Now locate the track offsets and lengths. If not using time
+ // code, we can initialize the "tick time" using a default tempo of
+ // 120 beats per minute. We will then check for tempo meta-events
+ // afterward.
+ unsigned int i;
+ for ( i=0; i<nTracks_; i++ ) {
+ if ( !file_.read( chunkType, 4 ) ) goto error;
+ if ( strncmp( chunkType, "MTrk", 4 ) ) goto error;
+ if ( !file_.read( buffer, 4 ) ) goto error;
+#ifdef __LITTLE_ENDIAN__
+ swap32((unsigned char *)&buffer);
+#endif
+ length = (SINT32 *) &buffer;
+ trackLengths_.push_back( *length );
+ trackOffsets_.push_back( (long) file_.tellg() );
+ trackPointers_.push_back( (long) file_.tellg() );
+ trackStatus_.push_back( 0 );
+ file_.seekg( *length, std::ios_base::cur );
+ if ( usingTimeCode_ ) tickSeconds_.push_back( (double) (1.0 / tickrate) );
+ else tickSeconds_.push_back( (double) (0.5 / tickrate) );
+ }
+
+ // Save the initial tickSeconds parameter.
+ TempoChange tempoEvent;
+ tempoEvent.count = 0;
+ tempoEvent.tickSeconds = tickSeconds_[0];
+ tempoEvents_.push_back( tempoEvent );
+
+ // If format 1 and not using time code, parse and save the tempo map
+ // on track 0.
+ if ( format_ == 1 && !usingTimeCode_ ) {
+ std::vector<unsigned char> event;
+ unsigned long value, count;
+
+ // We need to temporarily change the usingTimeCode_ value here so
+ // that the getNextEvent() function doesn't try to check the tempo
+ // map (which we're creating here).
+ usingTimeCode_ = true;
+ count = getNextEvent( &event, 0 );
+ while ( event.size() ) {
+ if ( ( event.size() == 6 ) && ( event[0] == 0xff ) &&
+ ( event[1] == 0x51 ) && ( event[2] == 0x03 ) ) {
+ tempoEvent.count = count;
+ value = ( event[3] << 16 ) + ( event[4] << 8 ) + event[5];
+ tempoEvent.tickSeconds = (double) (0.000001 * value / tickrate);
+ if ( count > tempoEvents_.back().count )
+ tempoEvents_.push_back( tempoEvent );
+ else
+ tempoEvents_.back() = tempoEvent;
+ }
+ count += getNextEvent( &event, 0 );
+ }
+ rewindTrack( 0 );
+ for ( unsigned int i=0; i<nTracks_; i++ ) {
+ trackCounters_.push_back( 0 );
+ trackTempoIndex_.push_back( 0 );
+ }
+ // Change the time code flag back!
+ usingTimeCode_ = false;
+ }
+
+ return;
+
+ error:
+ errorString_ << "MidiFileIn: error reading from file (" << fileName << ").";
+ handleError( StkError::FILE_ERROR );
+}
+
+MidiFileIn :: ~MidiFileIn()
+{
+ // An ifstream object implicitly closes itself during destruction
+ // but we'll make an explicit call to "close" anyway.
+ file_.close();
+}
+
+int MidiFileIn :: getFileFormat() const
+{
+ return format_;
+}
+
+unsigned int MidiFileIn :: getNumberOfTracks() const
+{
+ return nTracks_;
+}
+
+int MidiFileIn :: getDivision() const
+{
+ return division_;
+}
+
+void MidiFileIn :: rewindTrack( unsigned int track )
+{
+ if ( track >= nTracks_ ) {
+ errorString_ << "MidiFileIn::getNextEvent: invalid track argument (" << track << ").";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+
+ trackPointers_[track] = trackOffsets_[track];
+ trackStatus_[track] = 0;
+ tickSeconds_[track] = tempoEvents_[0].tickSeconds;
+}
+
+double MidiFileIn :: getTickSeconds( unsigned int track )
+{
+ // Return the current tick value in seconds for the given track.
+ if ( track >= nTracks_ ) {
+ errorString_ << "MidiFileIn::getTickSeconds: invalid track argument (" << track << ").";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+
+ return tickSeconds_[track];
+}
+
+unsigned long MidiFileIn :: getNextEvent( std::vector<unsigned char> *event, unsigned int track )
+{
+ // Fill the user-provided vector with the next event in the
+ // specified track (default = 0) and return the event delta time in
+ // ticks. This function assumes that the stored track pointer is
+ // positioned at the start of a track event. If the track has
+ // reached its end, the event vector size will be zero.
+ //
+ // If we have a format 0 or 2 file and we're not using timecode, we
+ // should check every meta-event for tempo changes and make
+ // appropriate updates to the tickSeconds_ parameter if so.
+ //
+ // If we have a format 1 file and we're not using timecode, keep a
+ // running sum of ticks for each track and update the tickSeconds_
+ // parameter as needed based on the stored tempo map.
+
+ if ( track >= nTracks_ ) {
+ errorString_ << "MidiFileIn::getNextEvent: invalid track argument (" << track << ").";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+
+ event->clear();
+ // Check for the end of the track.
+ if ( (trackPointers_[track] - trackOffsets_[track]) >= trackLengths_[track] )
+ return 0;
+
+ unsigned long ticks = 0, bytes = 0;
+ bool isTempoEvent = false;
+
+ // Read the event delta time.
+ file_.seekg( trackPointers_[track], std::ios_base::beg );
+ if ( !readVariableLength( &ticks ) ) goto error;
+
+ // Parse the event stream to determine the event length.
+ unsigned char c;
+ if ( !file_.read( (char *)&c, 1 ) ) goto error;
+ switch ( c ) {
+
+ case 0xFF: // A Meta-Event
+ unsigned long position;
+ trackStatus_[track] = 0;
+ event->push_back( c );
+ if ( !file_.read( (char *)&c, 1 ) ) goto error;
+ event->push_back( c );
+ if ( format_ != 1 && ( c == 0x51 ) ) isTempoEvent = true;
+ position = file_.tellg();
+ if ( !readVariableLength( &bytes ) ) goto error;
+ bytes += ( (unsigned long)file_.tellg() - position );
+ file_.seekg( position, std::ios_base::beg );
+ break;
+
+ case 0xF0:
+ case 0xF7: // The start or continuation of a Sysex event
+ trackStatus_[track] = 0;
+ event->push_back( c );
+ position = file_.tellg();
+ if ( !readVariableLength( &bytes ) ) goto error;
+ bytes += ( (unsigned long)file_.tellg() - position );
+ file_.seekg( position, std::ios_base::beg );
+ break;
+
+ default: // Should be a MIDI channel event
+ if ( c & 0x80 ) { // MIDI status byte
+ if ( c > 0xF0 ) goto error;
+ trackStatus_[track] = c;
+ event->push_back( c );
+ c &= 0xF0;
+ if ( (c == 0xC0) || (c == 0xD0) ) bytes = 1;
+ else bytes = 2;
+ }
+ else if ( trackStatus_[track] & 0x80 ) { // Running status
+ event->push_back( trackStatus_[track] );
+ event->push_back( c );
+ c = trackStatus_[track] & 0xF0;
+ if ( (c != 0xC0) && (c != 0xD0) ) bytes = 1;
+ }
+ else goto error;
+
+ }
+
+ // Read the rest of the event into the event vector.
+ unsigned long i;
+ for ( i=0; i<bytes; i++ ) {
+ if ( !file_.read( (char *)&c, 1 ) ) goto error;
+ event->push_back( c );
+ }
+
+ if ( !usingTimeCode_ ) {
+ if ( isTempoEvent ) {
+ // Parse the tempo event and update tickSeconds_[track].
+ double tickrate = (double) (division_ & 0x7FFF);
+ unsigned long value = ( event->at(3) << 16 ) + ( event->at(4) << 8 ) + event->at(5);
+ tickSeconds_[track] = (double) (0.000001 * value / tickrate);
+ }
+
+ if ( format_ == 1 ) {
+ // Update track counter and check the tempo map.
+ trackCounters_[track] += ticks;
+ TempoChange tempoEvent = tempoEvents_[ trackTempoIndex_[track] ];
+ if ( trackCounters_[track] >= tempoEvent.count && trackTempoIndex_[track] < tempoEvents_.size() - 1 ) {
+ trackTempoIndex_[track]++;
+ tickSeconds_[track] = tempoEvent.tickSeconds;
+ }
+ }
+ }
+
+ // Save the current track pointer value.
+ trackPointers_[track] = file_.tellg();
+
+ return ticks;
+
+ error:
+ errorString_ << "MidiFileIn::getNextEvent: file read error!";
+ handleError( StkError::FILE_ERROR );
+ return 0;
+}
+
+unsigned long MidiFileIn :: getNextMidiEvent( std::vector<unsigned char> *midiEvent, unsigned int track )
+{
+ // Fill the user-provided vector with the next MIDI event in the
+ // specified track (default = 0) and return the event delta time in
+ // ticks. Meta-Events preceeding this event are skipped and ignored.
+ if ( track >= nTracks_ ) {
+ errorString_ << "MidiFileIn::getNextMidiEvent: invalid track argument (" << track << ").";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+
+ unsigned long ticks = getNextEvent( midiEvent, track );
+ while ( midiEvent->size() && ( midiEvent->at(0) >= 0xF0 ) ) {
+ //for ( unsigned int i=0; i<midiEvent->size(); i++ )
+ //std::cout << "event byte = " << i << ", value = " << (int)midiEvent->at(i) << std::endl;
+ ticks = getNextEvent( midiEvent, track );
+ }
+
+ //for ( unsigned int i=0; i<midiEvent->size(); i++ )
+ //std::cout << "event byte = " << i << ", value = " << (int)midiEvent->at(i) << std::endl;
+
+ return ticks;
+}
+
+bool MidiFileIn :: readVariableLength( unsigned long *value )
+{
+ // It is assumed that this function is called with the file read
+ // pointer positioned at the start of a variable-length value. The
+ // function returns "true" if the value is successfully parsed and
+ // "false" otherwise.
+ *value = 0;
+ char c;
+
+ if ( !file_.read( &c, 1 ) ) return false;
+ *value = (unsigned long) c;
+ if ( *value & 0x80 ) {
+ *value &= 0x7f;
+ do {
+ if ( !file_.read( &c, 1 ) ) return false;
+ *value = ( *value << 7 ) + ( c & 0x7f );
+ } while ( c & 0x80 );
+ }
+
+ return true;
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class Modal
+ \brief STK resonance model abstract base class.
+
+ This class contains an excitation wavetable,
+ an envelope, an oscillator, and N resonances
+ (non-sweeping BiQuad filters), where N is set
+ during instantiation.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "Modal.h"
+#include <cstdlib>
+
+namespace stk {
+
+Modal :: Modal( unsigned int modes )
+ : nModes_(modes)
+{
+ if ( nModes_ == 0 ) {
+ errorString_ << "Modal: 'modes' argument to constructor is zero!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+
+ // We don't make the excitation wave here yet, because we don't know
+ // what it's going to be.
+
+ ratios_.resize( nModes_ );
+ radii_.resize( nModes_ );
+ filters_ = (BiQuad **) calloc( nModes_, sizeof(BiQuad *) );
+ for (unsigned int i=0; i<nModes_; i++ ) {
+ filters_[i] = new BiQuad;
+ filters_[i]->setEqualGainZeroes();
+ }
+
+ // Set some default values.
+ vibrato_.setFrequency( 6.0 );
+ vibratoGain_ = 0.0;
+ directGain_ = 0.0;
+ masterGain_ = 1.0;
+ baseFrequency_ = 440.0;
+
+ this->clear();
+
+ stickHardness_ = 0.5;
+ strikePosition_ = 0.561;
+}
+
+Modal :: ~Modal( void )
+{
+ for ( unsigned int i=0; i<nModes_; i++ ) {
+ delete filters_[i];
+ }
+ free( filters_ );
+}
+
+void Modal :: clear( void )
+{
+ onepole_.clear();
+ for ( unsigned int i=0; i<nModes_; i++ )
+ filters_[i]->clear();
+}
+
+void Modal :: setFrequency( StkFloat frequency )
+{
+ baseFrequency_ = frequency;
+ for ( unsigned int i=0; i<nModes_; i++ )
+ this->setRatioAndRadius( i, ratios_[i], radii_[i] );
+}
+
+void Modal :: setRatioAndRadius( unsigned int modeIndex, StkFloat ratio, StkFloat radius )
+{
+ if ( modeIndex >= nModes_ ) {
+ errorString_ << "Modal::setRatioAndRadius: modeIndex parameter is greater than number of modes!";
+ handleError( StkError::WARNING );
+ return;
+ }
+
+ StkFloat nyquist = Stk::sampleRate() / 2.0;
+ StkFloat temp;
+
+ if ( ratio * baseFrequency_ < nyquist ) {
+ ratios_[modeIndex] = ratio;
+ }
+ else {
+ temp = ratio;
+ while (temp * baseFrequency_ > nyquist) temp *= 0.5;
+ ratios_[modeIndex] = temp;
+#if defined(_STK_DEBUG_)
+ errorString_ << "Modal::setRatioAndRadius: aliasing would occur here ... correcting.";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+ }
+ radii_[modeIndex] = radius;
+ if (ratio < 0)
+ temp = -ratio;
+ else
+ temp = ratio * baseFrequency_;
+
+ filters_[modeIndex]->setResonance(temp, radius);
+}
+
+void Modal :: setModeGain( unsigned int modeIndex, StkFloat gain )
+{
+ if ( modeIndex >= nModes_ ) {
+ errorString_ << "Modal::setModeGain: modeIndex parameter is greater than number of modes!";
+ handleError( StkError::WARNING );
+ return;
+ }
+
+ filters_[modeIndex]->setGain( gain );
+}
+
+void Modal :: strike( StkFloat amplitude )
+{
+ StkFloat gain = amplitude;
+ if ( amplitude < 0.0 ) {
+ errorString_ << "Modal::strike: amplitude is less than zero ... setting to zero!";
+ handleError( StkError::WARNING );
+ gain = 0.0;
+ }
+ else if ( amplitude > 1.0 ) {
+ errorString_ << "Modal::strike: amplitude is greater than one ... setting to 1.0!";
+ handleError( StkError::WARNING );
+ gain = 1.0;
+ }
+
+ envelope_.setRate( 1.0 );
+ envelope_.setTarget( gain );
+ onepole_.setPole( 1.0 - gain );
+ envelope_.tick();
+ wave_->reset();
+
+ StkFloat temp;
+ for ( unsigned int i=0; i<nModes_; i++ ) {
+ if (ratios_[i] < 0)
+ temp = -ratios_[i];
+ else
+ temp = ratios_[i] * baseFrequency_;
+ filters_[i]->setResonance(temp, radii_[i]);
+ }
+}
+
+void Modal :: noteOn( StkFloat frequency, StkFloat amplitude )
+{
+ this->strike(amplitude);
+ this->setFrequency(frequency);
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Modal::NoteOn: frequency = " << frequency << ", amplitude = " << amplitude << '.';
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+void Modal :: noteOff( StkFloat amplitude )
+{
+ // This calls damp, but inverts the meaning of amplitude (high
+ // amplitude means fast damping).
+ this->damp( 1.0 - (amplitude * 0.03) );
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Modal::NoteOff: amplitude = " << amplitude << '.';
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+void Modal :: damp( StkFloat amplitude )
+{
+ StkFloat temp;
+ for ( unsigned int i=0; i<nModes_; i++ ) {
+ if ( ratios_[i] < 0 )
+ temp = -ratios_[i];
+ else
+ temp = ratios_[i] * baseFrequency_;
+ filters_[i]->setResonance( temp, radii_[i]*amplitude );
+ }
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class ModalBar
+ \brief STK resonant bar instrument class.
+
+ This class implements a number of different
+ struck bar instruments. It inherits from the
+ Modal class.
+
+ Control Change Numbers:
+ - Stick Hardness = 2
+ - Stick Position = 4
+ - Vibrato Gain = 8
+ - Vibrato Frequency = 11
+ - Direct Stick Mix = 1
+ - Volume = 128
+ - Modal Presets = 16
+ - Marimba = 0
+ - Vibraphone = 1
+ - Agogo = 2
+ - Wood1 = 3
+ - Reso = 4
+ - Wood2 = 5
+ - Beats = 6
+ - Two Fixed = 7
+ - Clump = 8
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "ModalBar.h"
+#include "Skini_msg.h"
+#include <cmath>
+
+namespace stk {
+
+ModalBar :: ModalBar( void )
+ : Modal()
+{
+ // Concatenate the STK rawwave path to the rawwave file
+ wave_ = new FileWvIn( (Stk::rawwavePath() + "marmstk1.raw").c_str(), true );
+ wave_->setRate( 0.5 * 22050.0 / Stk::sampleRate() );
+
+ // Set the resonances for preset 0 (marimba).
+ this->setPreset( 0 );
+}
+
+ModalBar :: ~ModalBar( void )
+{
+ delete wave_;
+}
+
+void ModalBar :: setStickHardness( StkFloat hardness )
+{
+ stickHardness_ = hardness;
+ if ( hardness < 0.0 ) {
+ errorString_ << "ModalBar::setStickHardness: parameter is less than zero ... setting to 0.0!";
+ handleError( StkError::WARNING );
+ stickHardness_ = 0.0;
+ }
+ else if ( hardness > 1.0 ) {
+ errorString_ << "ModalBar::setStickHarness: parameter is greater than one ... setting to 1.0!";
+ handleError( StkError::WARNING );
+ stickHardness_ = 1.0;
+ }
+
+ wave_->setRate( (0.25 * pow(4.0, stickHardness_) ) );
+ masterGain_ = 0.1 + (1.8 * stickHardness_);
+}
+
+void ModalBar :: setStrikePosition( StkFloat position )
+{
+ strikePosition_ = position;
+ if ( position < 0.0 ) {
+ errorString_ << "ModalBar::setStrikePosition: parameter is less than zero ... setting to 0.0!";
+ handleError( StkError::WARNING );
+ strikePosition_ = 0.0;
+ }
+ else if ( position > 1.0 ) {
+ errorString_ << "ModalBar::setStrikePosition: parameter is greater than one ... setting to 1.0!";
+ handleError( StkError::WARNING );
+ strikePosition_ = 1.0;
+ }
+
+ // Hack only first three modes.
+ StkFloat temp2 = position * PI;
+ StkFloat temp = sin(temp2);
+ this->setModeGain(0, 0.12 * temp);
+
+ temp = sin(0.05 + (3.9 * temp2));
+ this->setModeGain(1, -0.03 * temp);
+
+ temp = sin(-0.05 + (11 * temp2));
+ this->setModeGain(2, 0.11 * temp);
+}
+
+void ModalBar :: setPreset( int preset )
+{
+ // Presets:
+ // First line: relative modal frequencies (negative number is
+ // a fixed mode that doesn't scale with frequency
+ // Second line: resonances of the modes
+ // Third line: mode volumes
+ // Fourth line: stickHardness, strikePosition, and direct stick
+ // gain (mixed directly into the output
+ static StkFloat presets[9][4][4] = {
+ {{1.0, 3.99, 10.65, -2443}, // Marimba
+ {0.9996, 0.9994, 0.9994, 0.999},
+ {0.04, 0.01, 0.01, 0.008},
+ {0.429688, 0.445312, 0.093750}},
+ {{1.0, 2.01, 3.9, 14.37}, // Vibraphone
+ {0.99995, 0.99991, 0.99992, 0.9999},
+ {0.025, 0.015, 0.015, 0.015 },
+ {0.390625,0.570312,0.078125}},
+ {{1.0, 4.08, 6.669, -3725.0}, // Agogo
+ {0.999, 0.999, 0.999, 0.999},
+ {0.06, 0.05, 0.03, 0.02},
+ {0.609375,0.359375,0.140625}},
+ {{1.0, 2.777, 7.378, 15.377}, // Wood1
+ {0.996, 0.994, 0.994, 0.99},
+ {0.04, 0.01, 0.01, 0.008},
+ {0.460938,0.375000,0.046875}},
+ {{1.0, 2.777, 7.378, 15.377}, // Reso
+ {0.99996, 0.99994, 0.99994, 0.9999},
+ {0.02, 0.005, 0.005, 0.004},
+ {0.453125,0.250000,0.101562}},
+ {{1.0, 1.777, 2.378, 3.377}, // Wood2
+ {0.996, 0.994, 0.994, 0.99},
+ {0.04, 0.01, 0.01, 0.008},
+ {0.312500,0.445312,0.109375}},
+ {{1.0, 1.004, 1.013, 2.377}, // Beats
+ {0.9999, 0.9999, 0.9999, 0.999},
+ {0.02, 0.005, 0.005, 0.004},
+ {0.398438,0.296875,0.070312}},
+ {{1.0, 4.0, -1320.0, -3960.0}, // 2Fix
+ {0.9996, 0.999, 0.9994, 0.999},
+ {0.04, 0.01, 0.01, 0.008},
+ {0.453125,0.453125,0.070312}},
+ {{1.0, 1.217, 1.475, 1.729}, // Clump
+ {0.999, 0.999, 0.999, 0.999},
+ {0.03, 0.03, 0.03, 0.03 },
+ {0.390625,0.570312,0.078125}},
+ };
+
+ int temp = (preset % 9);
+ for (unsigned int i=0; i<nModes_; i++) {
+ this->setRatioAndRadius(i, presets[temp][0][i], presets[temp][1][i]);
+ this->setModeGain(i, presets[temp][2][i]);
+ }
+
+ this->setStickHardness(presets[temp][3][0]);
+ this->setStrikePosition(presets[temp][3][1]);
+ directGain_ = presets[temp][3][2];
+
+ if (temp == 1) // vibraphone
+ vibratoGain_ = 0.2;
+ else
+ vibratoGain_ = 0.0;
+}
+
+void ModalBar :: controlChange( int number, StkFloat value )
+{
+ StkFloat norm = value * ONE_OVER_128;
+ if ( norm < 0 ) {
+ norm = 0.0;
+ errorString_ << "ModalBar::controlChange: control value less than zero ... setting to zero!";
+ handleError( StkError::WARNING );
+ }
+ else if ( norm > 1.0 ) {
+ norm = 1.0;
+ errorString_ << "ModalBar::controlChange: control value greater than 128.0 ... setting to 128.0!";
+ handleError( StkError::WARNING );
+ }
+
+ if (number == __SK_StickHardness_) // 2
+ this->setStickHardness( norm );
+ else if (number == __SK_StrikePosition_) // 4
+ this->setStrikePosition( norm );
+ else if (number == __SK_ProphesyRibbon_) // 16
+ this->setPreset((int) value);
+ else if (number == __SK_Balance_) // 8
+ vibratoGain_ = norm * 0.3;
+ else if (number == __SK_ModWheel_) // 1
+ directGain_ = norm;
+ else if (number == __SK_ModFrequency_) // 11
+ vibrato_.setFrequency( norm * 12.0 );
+ else if (number == __SK_AfterTouch_Cont_) // 128
+ envelope_.setTarget( norm );
+ else {
+ errorString_ << "ModalBar::controlChange: undefined control number (" << number << ")!";
+ handleError( StkError::WARNING );
+ }
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "ModalBar::controlChange: number = " << number << ", value = " << value << '.';
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class Modulate
+ \brief STK periodic/random modulator.
+
+ This class combines random and periodic
+ modulations to give a nice, natural human
+ modulation function.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "Modulate.h"
+
+namespace stk {
+
+Modulate :: Modulate( void )
+{
+ vibrato_.setFrequency( 6.0 );
+ vibratoGain_ = 0.04;
+
+ noiseRate_ = (unsigned int) ( 330.0 * Stk::sampleRate() / 22050.0 );
+ noiseCounter_ = noiseRate_;
+
+ randomGain_ = 0.05;
+ filter_.setPole( 0.999 );
+ filter_.setGain( randomGain_ );
+
+ Stk::addSampleRateAlert( this );
+}
+
+Modulate :: ~Modulate( void )
+{
+ Stk::removeSampleRateAlert( this );
+}
+
+void Modulate :: sampleRateChanged( StkFloat newRate, StkFloat oldRate )
+{
+ if ( !ignoreSampleRateChange_ )
+ noiseRate_ = (unsigned int ) ( newRate * noiseRate_ / oldRate );
+}
+
+void Modulate :: setRandomGain( StkFloat gain )
+{
+ randomGain_ = gain;
+ filter_.setGain( randomGain_ );
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class Moog
+ \brief STK moog-like swept filter sampling synthesis class.
+
+ This instrument uses one attack wave, one
+ looped wave, and an ADSR envelope (inherited
+ from the Sampler class) and adds two sweepable
+ formant (FormSwep) filters.
+
+ Control Change Numbers:
+ - Filter Q = 2
+ - Filter Sweep Rate = 4
+ - Vibrato Frequency = 11
+ - Vibrato Gain = 1
+ - Gain = 128
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "Moog.h"
+#include "Skini_msg.h"
+
+namespace stk {
+
+Moog :: Moog( void )
+{
+ // Concatenate the STK rawwave path to the rawwave file
+ attacks_.push_back( new FileWvIn( (Stk::rawwavePath() + "mandpluk.raw").c_str(), true ) );
+ loops_.push_back ( new FileLoop( (Stk::rawwavePath() + "impuls20.raw").c_str(), true ) );
+ loops_.push_back ( new FileLoop( (Stk::rawwavePath() + "sinewave.raw").c_str(), true ) ); // vibrato
+ loops_[1]->setFrequency( 6.122 );
+
+ filters_[0].setTargets( 0.0, 0.7 );
+ filters_[1].setTargets( 0.0, 0.7 );
+
+ adsr_.setAllTimes( 0.001, 1.5, 0.6, 0.250 );
+ filterQ_ = 0.85;
+ filterRate_ = 0.0001;
+ modDepth_ = 0.0;
+}
+
+Moog :: ~Moog( void )
+{
+}
+
+void Moog :: setFrequency( StkFloat frequency )
+{
+ baseFrequency_ = frequency;
+ if ( frequency <= 0.0 ) {
+ errorString_ << "Moog::setFrequency: parameter is less than or equal to zero!";
+ handleError( StkError::WARNING );
+ baseFrequency_ = 220.0;
+ }
+
+ StkFloat rate = attacks_[0]->getSize() * 0.01 * baseFrequency_ / Stk::sampleRate();
+ attacks_[0]->setRate( rate );
+ loops_[0]->setFrequency( baseFrequency_ );
+}
+
+void Moog :: noteOn( StkFloat frequency, StkFloat amplitude )
+{
+ StkFloat temp;
+
+ this->setFrequency( frequency );
+ this->keyOn();
+ attackGain_ = amplitude * 0.5;
+ loopGain_ = amplitude;
+
+ temp = filterQ_ + 0.05;
+ filters_[0].setStates( 2000.0, temp );
+ filters_[1].setStates( 2000.0, temp );
+
+ temp = filterQ_ + 0.099;
+ filters_[0].setTargets( frequency, temp );
+ filters_[1].setTargets( frequency, temp );
+
+ filters_[0].setSweepRate( filterRate_ * 22050.0 / Stk::sampleRate() );
+ filters_[1].setSweepRate( filterRate_ * 22050.0 / Stk::sampleRate() );
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Moog::NoteOn: frequency = " << frequency << ", amplitude = " << amplitude << '.';
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+void Moog :: controlChange( int number, StkFloat value )
+{
+ StkFloat norm = value * ONE_OVER_128;
+ if ( norm < 0 ) {
+ norm = 0.0;
+ errorString_ << "Moog::controlChange: control value less than zero ... setting to zero!";
+ handleError( StkError::WARNING );
+ }
+ else if ( norm > 1.0 ) {
+ norm = 1.0;
+ errorString_ << "Moog::controlChange: control value greater than 128.0 ... setting to 128.0!";
+ handleError( StkError::WARNING );
+ }
+
+ if (number == __SK_FilterQ_) // 2
+ filterQ_ = 0.80 + ( 0.1 * norm );
+ else if (number == __SK_FilterSweepRate_) // 4
+ filterRate_ = norm * 0.0002;
+ else if (number == __SK_ModFrequency_) // 11
+ this->setModulationSpeed( norm * 12.0 );
+ else if (number == __SK_ModWheel_) // 1
+ this->setModulationDepth( norm );
+ else if (number == __SK_AfterTouch_Cont_) // 128
+ adsr_.setTarget( norm );
+ else {
+ errorString_ << "Moog::controlChange: undefined control number (" << number << ")!";
+ handleError( StkError::WARNING );
+ }
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Moog::controlChange: number = " << number << ", value = " << value << '.';
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class Mutex
+ \brief STK mutex class.
+
+ This class provides a uniform interface for
+ cross-platform mutex use. On Linux and IRIX
+ systems, the pthread library is used. Under
+ Windows, critical sections are used.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "Mutex.h"
+
+namespace stk {
+
+Mutex :: Mutex()
+{
+
+#if (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__))
+
+ pthread_mutex_init(&mutex_, NULL);
+ pthread_cond_init(&condition_, NULL);
+
+#elif defined(__OS_WINDOWS__)
+
+ InitializeCriticalSection(&mutex_);
+ condition_ = CreateEvent(NULL, // no security
+ true, // manual-reset
+ false, // non-signaled initially
+ NULL); // unnamed
+
+#endif
+}
+
+Mutex :: ~Mutex()
+{
+#if (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__))
+
+ pthread_mutex_destroy(&mutex_);
+ pthread_cond_destroy(&condition_);
+
+#elif defined(__OS_WINDOWS__)
+
+ DeleteCriticalSection(&mutex_);
+ CloseHandle( condition_ );
+
+#endif
+}
+
+void Mutex :: lock()
+{
+#if (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__))
+
+ pthread_mutex_lock(&mutex_);
+
+#elif defined(__OS_WINDOWS__)
+
+ EnterCriticalSection(&mutex_);
+
+#endif
+}
+
+void Mutex :: unlock()
+{
+#if (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__))
+
+ pthread_mutex_unlock(&mutex_);
+
+#elif defined(__OS_WINDOWS__)
+
+ LeaveCriticalSection(&mutex_);
+
+#endif
+}
+
+void Mutex :: wait()
+{
+#if (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__))
+
+ pthread_cond_wait(&condition_, &mutex_);
+
+#elif defined(__OS_WINDOWS__)
+
+ WaitForMultipleObjects(1, &condition_, false, INFINITE);
+
+#endif
+}
+
+void Mutex :: signal()
+{
+#if (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__))
+
+ pthread_cond_signal(&condition_);
+
+#elif defined(__OS_WINDOWS__)
+
+ SetEvent( condition_ );
+
+#endif
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class NRev
+ \brief CCRMA's NRev reverberator class.
+
+ This class takes a monophonic input signal and produces a stereo
+ output signal. It is derived from the CLM NRev function, which is
+ based on the use of networks of simple allpass and comb delay
+ filters. This particular arrangement consists of 6 comb filters
+ in parallel, followed by 3 allpass filters, a lowpass filter, and
+ another allpass in series, followed by two allpass filters in
+ parallel with corresponding right and left outputs.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "NRev.h"
+#include <cmath>
+
+namespace stk {
+
+NRev :: NRev( StkFloat T60 )
+{
+ lastFrame_.resize( 1, 2, 0.0 ); // resize lastFrame_ for stereo output
+
+ int lengths[15] = {1433, 1601, 1867, 2053, 2251, 2399, 347, 113, 37, 59, 53, 43, 37, 29, 19};
+ double scaler = Stk::sampleRate() / 25641.0;
+
+ int delay, i;
+ for ( i=0; i<15; i++ ) {
+ delay = (int) floor(scaler * lengths[i]);
+ if ( (delay & 1) == 0) delay++;
+ while ( !this->isPrime(delay) ) delay += 2;
+ lengths[i] = delay;
+ }
+
+ for ( i=0; i<6; i++ ) {
+ combDelays_[i].setMaximumDelay( lengths[i] );
+ combDelays_[i].setDelay( lengths[i] );
+ combCoefficient_[i] = pow(10.0, (-3 * lengths[i] / (T60 * Stk::sampleRate())));
+ }
+
+ for ( i=0; i<8; i++ ) {
+ allpassDelays_[i].setMaximumDelay( lengths[i+6] );
+ allpassDelays_[i].setDelay( lengths[i+6] );
+ }
+
+ this->setT60( T60 );
+ allpassCoefficient_ = 0.7;
+ effectMix_ = 0.3;
+ this->clear();
+}
+
+void NRev :: clear()
+{
+ int i;
+ for (i=0; i<6; i++) combDelays_[i].clear();
+ for (i=0; i<8; i++) allpassDelays_[i].clear();
+ lastFrame_[0] = 0.0;
+ lastFrame_[1] = 0.0;
+ lowpassState_ = 0.0;
+}
+
+void NRev :: setT60( StkFloat T60 )
+{
+ for ( int i=0; i<6; i++ )
+ combCoefficient_[i] = pow(10.0, (-3.0 * combDelays_[i].getDelay() / (T60 * Stk::sampleRate())));
+}
+
+StkFrames& NRev :: tick( StkFrames& frames, unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel >= frames.channels() - 1 ) {
+ errorString_ << "NRev::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *samples = &frames[channel];
+ unsigned int hop = frames.channels();
+ for ( unsigned int i=0; i<frames.frames(); i++, samples += hop ) {
+ *samples = tick( *samples );
+ samples++;
+ *samples = lastFrame_[1];
+ }
+
+ return frames;
+}
+
+StkFrames& NRev :: tick( StkFrames& iFrames, StkFrames& oFrames, unsigned int iChannel, unsigned int oChannel )
+{
+#if defined(_STK_DEBUG_)
+ if ( iChannel >= iFrames.channels() || oChannel >= oFrames.channels() - 1 ) {
+ errorString_ << "NRev::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *iSamples = &iFrames[iChannel];
+ StkFloat *oSamples = &oFrames[oChannel];
+ unsigned int iHop = iFrames.channels(), oHop = oFrames.channels();
+ for ( unsigned int i=0; i<iFrames.frames(); i++, iSamples += iHop, oSamples += oHop ) {
+ *oSamples++ = tick( *iSamples );
+ *oSamples = lastFrame_[1];
+ }
+
+ return iFrames;
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class Noise
+ \brief STK noise generator.
+
+ Generic random number generation using the
+ C rand() function. The quality of the rand()
+ function varies from one OS to another.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "Noise.h"
+#include <time.h>
+
+namespace stk {
+
+Noise :: Noise( unsigned int seed )
+{
+ // Seed the random number generator
+ this->setSeed( seed );
+}
+
+void Noise :: setSeed( unsigned int seed )
+{
+ if ( seed == 0 )
+ srand( (unsigned int) time( NULL ) );
+ else
+ srand( seed );
+}
+
+} // stk namespace
+
+
--- /dev/null
+/***************************************************/
+/*! \class OnePole
+ \brief STK one-pole filter class.
+
+ This class implements a one-pole digital filter. A method is
+ provided for setting the pole position along the real axis of the
+ z-plane while maintaining a constant peak filter gain.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "OnePole.h"
+
+namespace stk {
+
+OnePole :: OnePole( StkFloat thePole )
+{
+ b_.resize( 1 );
+ a_.resize( 2 );
+ inputs_.resize( 1, 1, 0.0 );
+ outputs_.resize( 2, 1, 0.0 );
+
+ this->setPole( thePole );
+}
+
+OnePole :: ~OnePole()
+{
+}
+
+void OnePole :: setPole( StkFloat thePole )
+{
+ // Normalize coefficients for peak unity gain.
+ if ( thePole > 0.0 )
+ b_[0] = (StkFloat) (1.0 - thePole);
+ else
+ b_[0] = (StkFloat) (1.0 + thePole);
+
+ a_[1] = -thePole;
+}
+
+void OnePole :: setCoefficients( StkFloat b0, StkFloat a1, bool clearState )
+{
+ b_[0] = b0;
+ a_[1] = a1;
+
+ if ( clearState ) this->clear();
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class OneZero
+ \brief STK one-zero filter class.
+
+ This class implements a one-zero digital filter. A method is
+ provided for setting the zero position along the real axis of the
+ z-plane while maintaining a constant filter gain.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "OneZero.h"
+
+namespace stk {
+
+OneZero :: OneZero( StkFloat theZero )
+{
+ b_.resize( 2 );
+ inputs_.resize( 2, 1, 0.0 );
+
+ this->setZero( theZero );
+}
+
+OneZero :: ~OneZero( void )
+{
+}
+
+void OneZero :: setZero( StkFloat theZero )
+{
+ // Normalize coefficients for unity gain.
+ if ( theZero > 0.0 )
+ b_[0] = 1.0 / ((StkFloat) 1.0 + theZero);
+ else
+ b_[0] = 1.0 / ((StkFloat) 1.0 - theZero);
+
+ b_[1] = -theZero * b_[0];
+}
+
+void OneZero :: setCoefficients( StkFloat b0, StkFloat b1, bool clearState )
+{
+ b_[0] = b0;
+ b_[1] = b1;
+
+ if ( clearState ) this->clear();
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class PRCRev
+ \brief Perry's simple reverberator class.
+
+ This class is based on some of the famous
+ Stanford/CCRMA reverbs (NRev, KipRev), which
+ were based on the Chowning/Moorer/Schroeder
+ reverberators using networks of simple allpass
+ and comb delay filters. This class implements
+ two series allpass units and two parallel comb
+ filters.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "PRCRev.h"
+#include <cmath>
+
+namespace stk {
+
+PRCRev :: PRCRev( StkFloat T60 )
+{
+ lastFrame_.resize( 1, 2, 0.0 ); // resize lastFrame_ for stereo output
+
+ // Delay lengths for 44100 Hz sample rate.
+ int lengths[4]= {353, 1097, 1777, 2137};
+ double scaler = Stk::sampleRate() / 44100.0;
+
+ // Scale the delay lengths if necessary.
+ int delay, i;
+ if ( scaler != 1.0 ) {
+ for (i=0; i<4; i++) {
+ delay = (int) floor(scaler * lengths[i]);
+ if ( (delay & 1) == 0) delay++;
+ while ( !this->isPrime(delay) ) delay += 2;
+ lengths[i] = delay;
+ }
+ }
+
+ for ( i=0; i<2; i++ ) {
+ allpassDelays_[i].setMaximumDelay( lengths[i] );
+ allpassDelays_[i].setDelay( lengths[i] );
+
+ combDelays_[i].setMaximumDelay( lengths[i+2] );
+ combDelays_[i].setDelay( lengths[i+2] );
+ }
+
+ this->setT60( T60 );
+ allpassCoefficient_ = 0.7;
+ effectMix_ = 0.5;
+ this->clear();
+}
+
+void PRCRev :: clear( void )
+{
+ allpassDelays_[0].clear();
+ allpassDelays_[1].clear();
+ combDelays_[0].clear();
+ combDelays_[1].clear();
+ lastFrame_[0] = 0.0;
+ lastFrame_[1] = 0.0;
+}
+
+void PRCRev :: setT60( StkFloat T60 )
+{
+ combCoefficient_[0] = pow(10.0, (-3.0 * combDelays_[0].getDelay() / (T60 * Stk::sampleRate())));
+ combCoefficient_[1] = pow(10.0, (-3.0 * combDelays_[1].getDelay() / (T60 * Stk::sampleRate())));
+}
+
+StkFrames& PRCRev :: tick( StkFrames& frames, unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel >= frames.channels() - 1 ) {
+ errorString_ << "PRCRev::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *samples = &frames[channel];
+ unsigned int hop = frames.channels();
+ for ( unsigned int i=0; i<frames.frames(); i++, samples += hop ) {
+ *samples = tick( *samples );
+ *samples++;
+ *samples = lastFrame_[1];
+ }
+
+ return frames;
+}
+
+StkFrames& PRCRev :: tick( StkFrames& iFrames, StkFrames& oFrames, unsigned int iChannel, unsigned int oChannel )
+{
+#if defined(_STK_DEBUG_)
+ if ( iChannel >= iFrames.channels() || oChannel >= oFrames.channels() - 1 ) {
+ errorString_ << "PRCRev::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *iSamples = &iFrames[iChannel];
+ StkFloat *oSamples = &oFrames[oChannel];
+ unsigned int iHop = iFrames.channels(), oHop = oFrames.channels();
+ for ( unsigned int i=0; i<iFrames.frames(); i++, iSamples += iHop, oSamples += oHop ) {
+ *oSamples++ = tick( *iSamples );
+ *oSamples = lastFrame_[1];
+ }
+
+ return iFrames;
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class PercFlut
+ \brief STK percussive flute FM synthesis instrument.
+
+ This class implements algorithm 4 of the TX81Z.
+
+ \code
+ Algorithm 4 is : 4->3--\
+ 2-- + -->1-->Out
+ \endcode
+
+ Control Change Numbers:
+ - Total Modulator Index = 2
+ - Modulator Crossfade = 4
+ - LFO Speed = 11
+ - LFO Depth = 1
+ - ADSR 2 & 4 Target = 128
+
+ The basic Chowning/Stanford FM patent expired
+ in 1995, but there exist follow-on patents,
+ mostly assigned to Yamaha. If you are of the
+ type who should worry about this (making
+ money) worry away.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "PercFlut.h"
+
+namespace stk {
+
+PercFlut :: PercFlut( void )
+ : FM()
+{
+ // Concatenate the STK rawwave path to the rawwave files
+ for ( unsigned int i=0; i<3; i++ )
+ waves_[i] = new FileLoop( (Stk::rawwavePath() + "sinewave.raw").c_str(), true );
+ waves_[3] = new FileLoop( (Stk::rawwavePath() + "fwavblnk.raw").c_str(), true );
+
+ this->setRatio(0, 1.50 * 1.000);
+ this->setRatio(1, 3.00 * 0.995);
+ this->setRatio(2, 2.99 * 1.005);
+ this->setRatio(3, 6.00 * 0.997);
+ gains_[0] = fmGains_[99];
+ gains_[1] = fmGains_[71];
+ gains_[2] = fmGains_[93];
+ gains_[3] = fmGains_[85];
+
+ adsr_[0]->setAllTimes( 0.05, 0.05, fmSusLevels_[14], 0.05);
+ adsr_[1]->setAllTimes( 0.02, 0.50, fmSusLevels_[13], 0.5);
+ adsr_[2]->setAllTimes( 0.02, 0.30, fmSusLevels_[11], 0.05);
+ adsr_[3]->setAllTimes( 0.02, 0.05, fmSusLevels_[13], 0.01);
+
+ twozero_.setGain( 0.0 );
+ modDepth_ = 0.005;
+}
+
+PercFlut :: ~PercFlut( void )
+{
+}
+
+void PercFlut :: setFrequency( StkFloat frequency )
+{
+ baseFrequency_ = frequency;
+}
+
+void PercFlut :: noteOn( StkFloat frequency, StkFloat amplitude )
+{
+ gains_[0] = amplitude * fmGains_[99] * 0.5;
+ gains_[1] = amplitude * fmGains_[71] * 0.5;
+ gains_[2] = amplitude * fmGains_[93] * 0.5;
+ gains_[3] = amplitude * fmGains_[85] * 0.5;
+ this->setFrequency( frequency );
+ this->keyOn();
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "PercFlut::NoteOn: frequency = " << frequency << ", amplitude = " << amplitude << '.';
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class Phonemes
+ \brief STK phonemes table.
+
+ This class does nothing other than declare a
+ set of 32 static phoneme formant parameters
+ and provide access to those values.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "Phonemes.h"
+#include <iostream>
+
+namespace stk {
+
+const char Phonemes :: phonemeNames[32][4] =
+ {"eee", "ihh", "ehh", "aaa",
+ "ahh", "aww", "ohh", "uhh",
+ "uuu", "ooo", "rrr", "lll",
+ "mmm", "nnn", "nng", "ngg",
+ "fff", "sss", "thh", "shh",
+ "xxx", "hee", "hoo", "hah",
+ "bbb", "ddd", "jjj", "ggg",
+ "vvv", "zzz", "thz", "zhh"
+ };
+
+const StkFloat Phonemes :: phonemeGains[32][2] =
+ {{1.0, 0.0}, // eee
+ {1.0, 0.0}, // ihh
+ {1.0, 0.0}, // ehh
+ {1.0, 0.0}, // aaa
+
+ {1.0, 0.0}, // ahh
+ {1.0, 0.0}, // aww
+ {1.0, 0.0}, // ohh
+ {1.0, 0.0}, // uhh
+
+ {1.0, 0.0}, // uuu
+ {1.0, 0.0}, // ooo
+ {1.0, 0.0}, // rrr
+ {1.0, 0.0}, // lll
+
+ {1.0, 0.0}, // mmm
+ {1.0, 0.0}, // nnn
+ {1.0, 0.0}, // nng
+ {1.0, 0.0}, // ngg
+
+ {0.0, 0.7}, // fff
+ {0.0, 0.7}, // sss
+ {0.0, 0.7}, // thh
+ {0.0, 0.7}, // shh
+
+ {0.0, 0.7}, // xxx
+ {0.0, 0.1}, // hee
+ {0.0, 0.1}, // hoo
+ {0.0, 0.1}, // hah
+
+ {1.0, 0.1}, // bbb
+ {1.0, 0.1}, // ddd
+ {1.0, 0.1}, // jjj
+ {1.0, 0.1}, // ggg
+
+ {1.0, 1.0}, // vvv
+ {1.0, 1.0}, // zzz
+ {1.0, 1.0}, // thz
+ {1.0, 1.0} // zhh
+ };
+
+const StkFloat Phonemes :: phonemeParameters[32][4][3] =
+ {{ { 273, 0.996, 10}, // eee (beet)
+ {2086, 0.945, -16},
+ {2754, 0.979, -12},
+ {3270, 0.440, -17}},
+ { { 385, 0.987, 10}, // ihh (bit)
+ {2056, 0.930, -20},
+ {2587, 0.890, -20},
+ {3150, 0.400, -20}},
+ { { 515, 0.977, 10}, // ehh (bet)
+ {1805, 0.810, -10},
+ {2526, 0.875, -10},
+ {3103, 0.400, -13}},
+ { { 773, 0.950, 10}, // aaa (bat)
+ {1676, 0.830, -6},
+ {2380, 0.880, -20},
+ {3027, 0.600, -20}},
+
+ { { 770, 0.950, 0}, // ahh (father)
+ {1153, 0.970, -9},
+ {2450, 0.780, -29},
+ {3140, 0.800, -39}},
+ { { 637, 0.910, 0}, // aww (bought)
+ { 895, 0.900, -3},
+ {2556, 0.950, -17},
+ {3070, 0.910, -20}},
+ { { 637, 0.910, 0}, // ohh (bone) NOTE:: same as aww (bought)
+ { 895, 0.900, -3},
+ {2556, 0.950, -17},
+ {3070, 0.910, -20}},
+ { { 561, 0.965, 0}, // uhh (but)
+ {1084, 0.930, -10},
+ {2541, 0.930, -15},
+ {3345, 0.900, -20}},
+
+ { { 515, 0.976, 0}, // uuu (foot)
+ {1031, 0.950, -3},
+ {2572, 0.960, -11},
+ {3345, 0.960, -20}},
+ { { 349, 0.986, -10}, // ooo (boot)
+ { 918, 0.940, -20},
+ {2350, 0.960, -27},
+ {2731, 0.950, -33}},
+ { { 394, 0.959, -10}, // rrr (bird)
+ {1297, 0.780, -16},
+ {1441, 0.980, -16},
+ {2754, 0.950, -40}},
+ { { 462, 0.990, +5}, // lll (lull)
+ {1200, 0.640, -10},
+ {2500, 0.200, -20},
+ {3000, 0.100, -30}},
+
+ { { 265, 0.987, -10}, // mmm (mom)
+ {1176, 0.940, -22},
+ {2352, 0.970, -20},
+ {3277, 0.940, -31}},
+ { { 204, 0.980, -10}, // nnn (nun)
+ {1570, 0.940, -15},
+ {2481, 0.980, -12},
+ {3133, 0.800, -30}},
+ { { 204, 0.980, -10}, // nng (sang) NOTE:: same as nnn
+ {1570, 0.940, -15},
+ {2481, 0.980, -12},
+ {3133, 0.800, -30}},
+ { { 204, 0.980, -10}, // ngg (bong) NOTE:: same as nnn
+ {1570, 0.940, -15},
+ {2481, 0.980, -12},
+ {3133, 0.800, -30}},
+
+ { {1000, 0.300, 0}, // fff
+ {2800, 0.860, -10},
+ {7425, 0.740, 0},
+ {8140, 0.860, 0}},
+ { {0, 0.000, 0}, // sss
+ {2000, 0.700, -15},
+ {5257, 0.750, -3},
+ {7171, 0.840, 0}},
+ { { 100, 0.900, 0}, // thh
+ {4000, 0.500, -20},
+ {5500, 0.500, -15},
+ {8000, 0.400, -20}},
+ { {2693, 0.940, 0}, // shh
+ {4000, 0.720, -10},
+ {6123, 0.870, -10},
+ {7755, 0.750, -18}},
+
+ { {1000, 0.300, -10}, // xxx NOTE:: Not Really Done Yet
+ {2800, 0.860, -10},
+ {7425, 0.740, 0},
+ {8140, 0.860, 0}},
+ { { 273, 0.996, -40}, // hee (beet) (noisy eee)
+ {2086, 0.945, -16},
+ {2754, 0.979, -12},
+ {3270, 0.440, -17}},
+ { { 349, 0.986, -40}, // hoo (boot) (noisy ooo)
+ { 918, 0.940, -10},
+ {2350, 0.960, -17},
+ {2731, 0.950, -23}},
+ { { 770, 0.950, -40}, // hah (father) (noisy ahh)
+ {1153, 0.970, -3},
+ {2450, 0.780, -20},
+ {3140, 0.800, -32}},
+
+ { {2000, 0.700, -20}, // bbb NOTE:: Not Really Done Yet
+ {5257, 0.750, -15},
+ {7171, 0.840, -3},
+ {9000, 0.900, 0}},
+ { { 100, 0.900, 0}, // ddd NOTE:: Not Really Done Yet
+ {4000, 0.500, -20},
+ {5500, 0.500, -15},
+ {8000, 0.400, -20}},
+ { {2693, 0.940, 0}, // jjj NOTE:: Not Really Done Yet
+ {4000, 0.720, -10},
+ {6123, 0.870, -10},
+ {7755, 0.750, -18}},
+ { {2693, 0.940, 0}, // ggg NOTE:: Not Really Done Yet
+ {4000, 0.720, -10},
+ {6123, 0.870, -10},
+ {7755, 0.750, -18}},
+
+ { {2000, 0.700, -20}, // vvv NOTE:: Not Really Done Yet
+ {5257, 0.750, -15},
+ {7171, 0.840, -3},
+ {9000, 0.900, 0}},
+ { { 100, 0.900, 0}, // zzz NOTE:: Not Really Done Yet
+ {4000, 0.500, -20},
+ {5500, 0.500, -15},
+ {8000, 0.400, -20}},
+ { {2693, 0.940, 0}, // thz NOTE:: Not Really Done Yet
+ {4000, 0.720, -10},
+ {6123, 0.870, -10},
+ {7755, 0.750, -18}},
+ { {2693, 0.940, 0}, // zhh NOTE:: Not Really Done Yet
+ {4000, 0.720, -10},
+ {6123, 0.870, -10},
+ {7755, 0.750, -18}}
+ };
+
+Phonemes :: Phonemes(void)
+{
+}
+
+Phonemes :: ~Phonemes(void)
+{
+}
+
+const char *Phonemes :: name( unsigned int index )
+{
+ if ( index > 31 ) {
+ std::ostringstream error;
+ error << "Phonemes::name: index is greater than 31!";
+ handleError( error.str(), StkError::WARNING );
+ return 0;
+ }
+ return phonemeNames[index];
+}
+
+StkFloat Phonemes :: voiceGain( unsigned int index )
+{
+ if ( index > 31 ) {
+ std::ostringstream error;
+ error << "Phonemes::voiceGain: index is greater than 31!";
+ handleError( error.str(), StkError::WARNING );
+ return 0.0;
+ }
+ return phonemeGains[index][0];
+}
+
+StkFloat Phonemes :: noiseGain( unsigned int index )
+{
+ if ( index > 31 ) {
+ std::ostringstream error;
+ error << "Phonemes::noiseGain: index is greater than 31!";
+ handleError( error.str(), StkError::WARNING );
+ return 0.0;
+ }
+ return phonemeGains[index][1];
+}
+
+StkFloat Phonemes :: formantFrequency( unsigned int index, unsigned int partial )
+{
+ std::ostringstream error;
+ if ( index > 31 ) {
+ error << "Phonemes::formantFrequency: index is greater than 31!";
+ handleError( error.str(), StkError::WARNING );
+ return 0.0;
+ }
+ if ( partial > 3 ) {
+ error << "Phonemes::formantFrequency: partial is greater than 3!";
+ handleError( error.str(), StkError::WARNING );
+ return 0.0;
+ }
+ return phonemeParameters[index][partial][0];
+}
+
+StkFloat Phonemes :: formantRadius( unsigned int index, unsigned int partial )
+{
+ std::ostringstream error;
+ if ( index > 31 ) {
+ error << "Phonemes::formantRadius: index is greater than 31!";
+ handleError( error.str(), StkError::WARNING );
+ return 0.0;
+ }
+ if ( partial > 3 ) {
+ error << "Phonemes::formantRadius: partial is greater than 3!";
+ handleError( error.str(), StkError::WARNING );
+ return 0.0;
+ }
+ return phonemeParameters[index][partial][1];
+}
+
+StkFloat Phonemes :: formantGain( unsigned int index, unsigned int partial )
+{
+ std::ostringstream error;
+ if ( index > 31 ) {
+ error << "Phonemes::formantGain: index is greater than 31!";
+ handleError( error.str(), StkError::WARNING );
+ return 0.0;
+ }
+ if ( partial > 3 ) {
+ error << "Phonemes::formantGain: partial is greater than 3!";
+ handleError( error.str(), StkError::WARNING );
+ return 0.0;
+ }
+ return phonemeParameters[index][partial][2];
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class PitShift
+ \brief STK simple pitch shifter effect class.
+
+ This class implements a simple pitch shifter
+ using delay lines.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "PitShift.h"
+#include <cmath>
+
+namespace stk {
+
+PitShift :: PitShift( void )
+{
+ delayLength_ = maxDelay - 24;
+ halfLength_ = delayLength_ / 2;
+ delay_[0] = 12;
+ delay_[1] = maxDelay / 2;
+
+ delayLine_[0].setMaximumDelay( maxDelay );
+ delayLine_[0].setDelay( delay_[0] );
+ delayLine_[1].setMaximumDelay( maxDelay );
+ delayLine_[1].setDelay( delay_[1] );
+ effectMix_ = 0.5;
+ rate_ = 1.0;
+}
+
+void PitShift :: clear()
+{
+ delayLine_[0].clear();
+ delayLine_[1].clear();
+ lastFrame_[0] = 0.0;
+}
+
+void PitShift :: setShift( StkFloat shift )
+{
+ if ( shift < 1.0 ) {
+ rate_ = 1.0 - shift;
+ }
+ else if ( shift > 1.0 ) {
+ rate_ = 1.0 - shift;
+ }
+ else {
+ rate_ = 0.0;
+ delay_[0] = halfLength_ + 12;
+ }
+}
+
+StkFrames& PitShift :: tick( StkFrames& frames, unsigned int channel )
+{
+#if defined(_STK_DEBUG_)
+ if ( channel >= frames.channels() ) {
+ errorString_ << "PitShift::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *samples = &frames[channel];
+ unsigned int hop = frames.channels();
+ for ( unsigned int i=0; i<frames.frames(); i++, samples += hop )
+ *samples = tick( *samples );
+
+ return frames;
+}
+
+StkFrames& PitShift :: tick( StkFrames& iFrames, StkFrames& oFrames, unsigned int iChannel, unsigned int oChannel )
+{
+#if defined(_STK_DEBUG_)
+ if ( iChannel >= iFrames.channels() || oChannel >= oFrames.channels() ) {
+ errorString_ << "PitShift::tick(): channel and StkFrames arguments are incompatible!";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+#endif
+
+ StkFloat *iSamples = &iFrames[iChannel];
+ StkFloat *oSamples = &oFrames[oChannel];
+ unsigned int iHop = iFrames.channels(), oHop = oFrames.channels();
+ for ( unsigned int i=0; i<iFrames.frames(); i++, iSamples += iHop, oSamples += oHop )
+ *oSamples = tick( *iSamples );
+
+ return iFrames;
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class PluckTwo
+ \brief STK enhanced plucked string model class.
+
+ This class implements an enhanced two-string,
+ plucked physical model, a la Jaffe-Smith,
+ Smith, and others.
+
+ PluckTwo is an abstract class, with no excitation
+ specified. Therefore, it can't be directly
+ instantiated.
+
+ This is a digital waveguide model, making its
+ use possibly subject to patents held by
+ Stanford University, Yamaha, and others.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "PluckTwo.h"
+
+namespace stk {
+
+PluckTwo :: PluckTwo( StkFloat lowestFrequency )
+{
+ length_ = (unsigned long) ( Stk::sampleRate() / lowestFrequency + 1 );
+ lastLength_ = length_ * 0.5;
+ delayLine_.setMaximumDelay( length_ );
+ delayLine_.setDelay( lastLength_ );
+ delayLine2_.setMaximumDelay( length_ );
+ delayLine2_.setDelay( lastLength_ );
+ combDelay_.setMaximumDelay( length_ );
+ combDelay_.setDelay( lastLength_ );
+
+ baseLoopGain_ = 0.995;
+ loopGain_ = 0.999;
+ pluckAmplitude_ = 0.3;
+ pluckPosition_ = 0.4;
+ detuning_ = 0.995;
+ lastFrequency_ = lowestFrequency * 2.0;
+}
+
+PluckTwo :: ~PluckTwo( void )
+{
+}
+
+void PluckTwo :: clear( void )
+{
+ delayLine_.clear();
+ delayLine2_.clear();
+ combDelay_.clear();
+ filter_.clear();
+ filter2_.clear();
+}
+
+void PluckTwo :: setFrequency( StkFloat frequency )
+{
+ lastFrequency_ = frequency;
+ if ( lastFrequency_ <= 0.0 ) {
+ errorString_ << "Clarinet::setFrequency: parameter is less than or equal to zero!";
+ handleError( StkError::WARNING );
+ lastFrequency_ = 220.0;
+ }
+
+ // Delay = length - approximate filter delay.
+ lastLength_ = Stk::sampleRate() / lastFrequency_;
+ StkFloat delay = (lastLength_ / detuning_) - 0.5;
+ if ( delay <= 0.0 ) delay = 0.3;
+ else if ( delay > length_ ) delay = length_;
+ delayLine_.setDelay( delay );
+
+ delay = (lastLength_ * detuning_) - 0.5;
+ if ( delay <= 0.0 ) delay = 0.3;
+ else if ( delay > length_ ) delay = length_;
+ delayLine2_.setDelay( delay );
+
+ loopGain_ = baseLoopGain_ + (frequency * 0.000005);
+ if ( loopGain_ > 1.0 ) loopGain_ = 0.99999;
+}
+
+void PluckTwo :: setDetune( StkFloat detune )
+{
+ detuning_ = detune;
+ if ( detuning_ <= 0.0 ) {
+ errorString_ << "Clarinet::setDeturn: parameter is less than or equal to zero!";
+ handleError( StkError::WARNING );
+ detuning_ = 0.1;
+ }
+ delayLine_.setDelay(( lastLength_ / detuning_) - 0.5);
+ delayLine2_.setDelay( (lastLength_ * detuning_) - 0.5);
+}
+
+void PluckTwo :: setFreqAndDetune( StkFloat frequency, StkFloat detune )
+{
+ detuning_ = detune;
+ this->setFrequency( frequency );
+}
+
+void PluckTwo :: setPluckPosition( StkFloat position )
+{
+ pluckPosition_ = position;
+ if ( position < 0.0 ) {
+ errorString_ << "PluckTwo::setPluckPosition: parameter is less than zero ... setting to 0.0!";
+ handleError( StkError::WARNING );
+ pluckPosition_ = 0.0;
+ }
+ else if ( position > 1.0 ) {
+ errorString_ << "PluckTwo::setPluckPosition: parameter is greater than one ... setting to 1.0!";
+ handleError( StkError::WARNING );
+ pluckPosition_ = 1.0;
+ }
+}
+
+void PluckTwo :: setBaseLoopGain( StkFloat aGain )
+{
+ baseLoopGain_ = aGain;
+ loopGain_ = baseLoopGain_ + (lastFrequency_ * 0.000005);
+ if ( loopGain_ > 0.99999 ) loopGain_ = 0.99999;
+}
+
+void PluckTwo :: noteOff( StkFloat amplitude )
+{
+ loopGain_ = (1.0 - amplitude) * 0.5;
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "PluckTwo::NoteOff: amplitude = " << amplitude << ".";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class Plucked
+ \brief STK plucked string model class.
+
+ This class implements a simple plucked string
+ physical model based on the Karplus-Strong
+ algorithm.
+
+ This is a digital waveguide model, making its
+ use possibly subject to patents held by
+ Stanford University, Yamaha, and others.
+ There exist at least two patents, assigned to
+ Stanford, bearing the names of Karplus and/or
+ Strong.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "Plucked.h"
+
+namespace stk {
+
+Plucked :: Plucked( StkFloat lowestFrequency )
+{
+ length_ = (unsigned long) ( Stk::sampleRate() / lowestFrequency + 1 );
+ loopGain_ = 0.999;
+ delayLine_.setMaximumDelay( length_ );
+ delayLine_.setDelay( 0.5 * length_ );
+ this->clear();
+}
+
+Plucked :: ~Plucked( void )
+{
+}
+
+void Plucked :: clear( void )
+{
+ delayLine_.clear();
+ loopFilter_.clear();
+ pickFilter_.clear();
+}
+
+void Plucked :: setFrequency( StkFloat frequency )
+{
+ StkFloat freakency = frequency;
+ if ( frequency <= 0.0 ) {
+ errorString_ << "Plucked::setFrequency: parameter is less than or equal to zero!";
+ handleError( StkError::WARNING );
+ freakency = 220.0;
+ }
+
+ // Delay = length - approximate filter delay.
+ StkFloat delay = (Stk::sampleRate() / freakency) - 0.5;
+ if ( delay <= 0.0 )
+ delay = 0.3;
+ else if ( delay > length_ )
+ delay = length_;
+ delayLine_.setDelay( delay );
+
+ loopGain_ = 0.995 + (freakency * 0.000005);
+ if ( loopGain_ >= 1.0 ) loopGain_ = 0.99999;
+}
+
+void Plucked :: pluck( StkFloat amplitude )
+{
+ StkFloat gain = amplitude;
+ if ( gain > 1.0 ) {
+ errorString_ << "Plucked::pluck: amplitude is greater than 1.0 ... setting to 1.0!";
+ handleError( StkError::WARNING );
+ gain = 1.0;
+ }
+ else if ( gain < 0.0 ) {
+ errorString_ << "Plucked::pluck: amplitude is < 0.0 ... setting to 0.0!";
+ handleError( StkError::WARNING );
+ gain = 0.0;
+ }
+
+ pickFilter_.setPole( 0.999 - (gain * 0.15) );
+ pickFilter_.setGain( gain * 0.5 );
+ for (unsigned long i=0; i<length_; i++)
+ // Fill delay with noise additively with current contents.
+ delayLine_.tick( 0.6 * delayLine_.lastOut() + pickFilter_.tick( noise_.tick() ) );
+}
+
+void Plucked :: noteOn( StkFloat frequency, StkFloat amplitude )
+{
+ this->setFrequency( frequency );
+ this->pluck( amplitude );
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Plucked::NoteOn: frequency = " << frequency << ", amplitude = " << amplitude << ".";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+void Plucked :: noteOff( StkFloat amplitude )
+{
+ loopGain_ = 1.0 - amplitude;
+ if ( loopGain_ < 0.0 ) {
+ errorString_ << "Plucked::noteOff: amplitude is greater than 1.0 ... setting to 1.0!";
+ handleError( StkError::WARNING );
+ loopGain_ = 0.0;
+ }
+ else if ( loopGain_ > 1.0 ) {
+ errorString_ << "Plucked::noteOff: amplitude is < 0.0 ... setting to 0.0!";
+ handleError( StkError::WARNING );
+ loopGain_ = (StkFloat) 0.99999;
+ }
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Plucked::NoteOff: amplitude = " << amplitude << ".";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class PoleZero
+ \brief STK one-pole, one-zero filter class.
+
+ This class implements a one-pole, one-zero digital filter. A
+ method is provided for creating an allpass filter with a given
+ coefficient. Another method is provided to create a DC blocking
+ filter.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "PoleZero.h"
+
+namespace stk {
+
+PoleZero :: PoleZero()
+{
+ // Default setting for pass-through.
+ b_.resize( 2, 0.0 );
+ a_.resize( 2, 0.0 );
+ b_[0] = 1.0;
+ a_[0] = 1.0;
+ inputs_.resize( 2, 1, 0.0 );
+ outputs_.resize( 2, 1, 0.0 );
+}
+
+PoleZero :: ~PoleZero()
+{
+}
+
+void PoleZero :: setCoefficients( StkFloat b0, StkFloat b1, StkFloat a1, bool clearState )
+{
+ b_[0] = b0;
+ b_[1] = b1;
+ a_[1] = a1;
+
+ if ( clearState ) this->clear();
+}
+
+void PoleZero :: setAllpass( StkFloat coefficient )
+{
+ b_[0] = coefficient;
+ b_[1] = 1.0;
+ a_[0] = 1.0; // just in case
+ a_[1] = coefficient;
+}
+
+void PoleZero :: setBlockZero( StkFloat thePole )
+{
+ b_[0] = 1.0;
+ b_[1] = -1.0;
+ a_[0] = 1.0; // just in case
+ a_[1] = -thePole;
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class Resonate
+ \brief STK noise driven formant filter.
+
+ This instrument contains a noise source, which
+ excites a biquad resonance filter, with volume
+ controlled by an ADSR.
+
+ Control Change Numbers:
+ - Resonance Frequency (0-Nyquist) = 2
+ - Pole Radii = 4
+ - Notch Frequency (0-Nyquist) = 11
+ - Zero Radii = 1
+ - Envelope Gain = 128
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "Resonate.h"
+#include "Skini_msg.h"
+
+namespace stk {
+
+Resonate :: Resonate( void )
+{
+ poleFrequency_ = 4000.0;
+ poleRadius_ = 0.95;
+ // Set the filter parameters.
+ filter_.setResonance( poleFrequency_, poleRadius_, true );
+ zeroFrequency_ = 0.0;
+ zeroRadius_ = 0.0;
+}
+
+Resonate :: ~Resonate( void )
+{
+}
+
+void Resonate :: noteOn( StkFloat frequency, StkFloat amplitude )
+{
+ adsr_.setTarget( amplitude );
+ this->keyOn();
+ this->setResonance( frequency, poleRadius_ );
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Resonate::NoteOn: frequency = " << frequency << ", amplitude = " << amplitude << '.';
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+void Resonate :: noteOff( StkFloat amplitude )
+{
+ this->keyOff();
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Resonate::NoteOff: amplitude = " << amplitude << '.';
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+void Resonate :: setResonance( StkFloat frequency, StkFloat radius )
+{
+ poleFrequency_ = frequency;
+ if ( frequency < 0.0 ) {
+ errorString_ << "Resonate::setResonance: frequency parameter is less than zero ... setting to 0.0!";
+ handleError( StkError::WARNING );
+ poleFrequency_ = 0.0;
+ }
+
+ poleRadius_ = radius;
+ if ( radius < 0.0 ) {
+ std::cerr << "Resonate::setResonance: radius parameter is less than 0.0 ... setting to 0.0!";
+ handleError( StkError::WARNING );
+ poleRadius_ = 0.0;
+ }
+ else if ( radius >= 1.0 ) {
+ errorString_ << "Resonate::setResonance: radius parameter is greater than or equal to 1.0, which is unstable ... correcting!";
+ handleError( StkError::WARNING );
+ poleRadius_ = 0.9999;
+ }
+ filter_.setResonance( poleFrequency_, poleRadius_, true );
+}
+
+void Resonate :: setNotch( StkFloat frequency, StkFloat radius )
+{
+ zeroFrequency_ = frequency;
+ if ( frequency < 0.0 ) {
+ errorString_ << "Resonate::setNotch: frequency parameter is less than zero ... setting to 0.0!";
+ handleError( StkError::WARNING );
+ zeroFrequency_ = 0.0;
+ }
+
+ zeroRadius_ = radius;
+ if ( radius < 0.0 ) {
+ errorString_ << "Resonate::setNotch: radius parameter is less than 0.0 ... setting to 0.0!";
+ handleError( StkError::WARNING );
+ zeroRadius_ = 0.0;
+ }
+
+ filter_.setNotch( zeroFrequency_, zeroRadius_ );
+}
+
+void Resonate :: controlChange( int number, StkFloat value )
+{
+ StkFloat norm = value * ONE_OVER_128;
+ if ( norm < 0 ) {
+ norm = 0.0;
+ errorString_ << "Resonate::controlChange: control value less than zero ... setting to zero!";
+ handleError( StkError::WARNING );
+ }
+ else if ( norm > 1.0 ) {
+ norm = 1.0;
+ errorString_ << "Resonate::controlChange: control value greater than 128.0 ... setting to 128.0!";
+ handleError( StkError::WARNING );
+ }
+
+ if (number == 2) // 2
+ setResonance( norm * Stk::sampleRate() * 0.5, poleRadius_ );
+ else if (number == 4) // 4
+ setResonance( poleFrequency_, norm*0.9999 );
+ else if (number == 11) // 11
+ this->setNotch( norm * Stk::sampleRate() * 0.5, zeroRadius_ );
+ else if (number == 1)
+ this->setNotch( zeroFrequency_, norm );
+ else if (number == __SK_AfterTouch_Cont_) // 128
+ adsr_.setTarget( norm );
+ else {
+ errorString_ << "Resonate::controlChange: undefined control number (" << number << ")!";
+ handleError( StkError::WARNING );
+ }
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Resonate::controlChange: number = " << number << ", value = " << value << '.';
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class Rhodey
+ \brief STK Fender Rhodes-like electric piano FM
+ synthesis instrument.
+
+ This class implements two simple FM Pairs
+ summed together, also referred to as algorithm
+ 5 of the TX81Z.
+
+ \code
+ Algorithm 5 is : 4->3--\
+ + --> Out
+ 2->1--/
+ \endcode
+
+ Control Change Numbers:
+ - Modulator Index One = 2
+ - Crossfade of Outputs = 4
+ - LFO Speed = 11
+ - LFO Depth = 1
+ - ADSR 2 & 4 Target = 128
+
+ The basic Chowning/Stanford FM patent expired
+ in 1995, but there exist follow-on patents,
+ mostly assigned to Yamaha. If you are of the
+ type who should worry about this (making
+ money) worry away.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "Rhodey.h"
+
+namespace stk {
+
+Rhodey :: Rhodey( void )
+ : FM()
+{
+ // Concatenate the STK rawwave path to the rawwave files
+ for ( unsigned int i=0; i<3; i++ )
+ waves_[i] = new FileLoop( (Stk::rawwavePath() + "sinewave.raw").c_str(), true );
+ waves_[3] = new FileLoop( (Stk::rawwavePath() + "fwavblnk.raw").c_str(), true );
+
+ this->setRatio(0, 1.0);
+ this->setRatio(1, 0.5);
+ this->setRatio(2, 1.0);
+ this->setRatio(3, 15.0);
+
+ gains_[0] = fmGains_[99];
+ gains_[1] = fmGains_[90];
+ gains_[2] = fmGains_[99];
+ gains_[3] = fmGains_[67];
+
+ adsr_[0]->setAllTimes( 0.001, 1.50, 0.0, 0.04);
+ adsr_[1]->setAllTimes( 0.001, 1.50, 0.0, 0.04);
+ adsr_[2]->setAllTimes( 0.001, 1.00, 0.0, 0.04);
+ adsr_[3]->setAllTimes( 0.001, 0.25, 0.0, 0.04);
+
+ twozero_.setGain( 1.0 );
+}
+
+Rhodey :: ~Rhodey( void )
+{
+}
+
+void Rhodey :: setFrequency( StkFloat frequency )
+{
+ baseFrequency_ = frequency * 2.0;
+
+ for (unsigned int i=0; i<nOperators_; i++ )
+ waves_[i]->setFrequency( baseFrequency_ * ratios_[i] );
+}
+
+void Rhodey :: noteOn( StkFloat frequency, StkFloat amplitude )
+{
+ gains_[0] = amplitude * fmGains_[99];
+ gains_[1] = amplitude * fmGains_[90];
+ gains_[2] = amplitude * fmGains_[99];
+ gains_[3] = amplitude * fmGains_[67];
+ this->setFrequency( frequency );
+ this->keyOn();
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Rhodey::NoteOn: frequency = " << frequency << ", amplitude = " << amplitude << '.';
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class Sampler
+ \brief STK sampling synthesis abstract base class.
+
+ This instrument provides an ADSR envelope, a one-pole filter, and
+ structures for an arbitrary number of attack and looped files.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "Sampler.h"
+
+namespace stk {
+
+Sampler :: Sampler( void )
+{
+ // We don't make the waves here yet, because
+ // we don't know what they will be.
+ baseFrequency_ = 440.0;
+ attackGain_ = 0.25;
+ loopGain_ = 0.25;
+}
+
+Sampler :: ~Sampler( void )
+{
+ unsigned int i;
+ for ( i=0; i<attacks_.size(); i++ ) delete attacks_[i];
+ for ( i=0; i<loops_.size(); i++ ) delete loops_[i];
+}
+
+void Sampler :: keyOn( void )
+{
+ // Reset all attack waves.
+ for ( unsigned int i=0; i<attacks_.size(); i++ )
+ attacks_[i]->reset();
+
+ // Start the envelope.
+ adsr_.keyOn();
+
+}
+
+void Sampler :: keyOff( void )
+{
+ adsr_.keyOff();
+}
+
+void Sampler :: noteOff( StkFloat amplitude )
+{
+ this->keyOff();
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Sampler::NoteOff: amplitude = " << amplitude << ".";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class Saxofony
+ \brief STK faux conical bore reed instrument class.
+
+ This class implements a "hybrid" digital
+ waveguide instrument that can generate a
+ variety of wind-like sounds. It has also been
+ referred to as the "blowed string" model. The
+ waveguide section is essentially that of a
+ string, with one rigid and one lossy
+ termination. The non-linear function is a
+ reed table. The string can be "blown" at any
+ point between the terminations, though just as
+ with strings, it is impossible to excite the
+ system at either end. If the excitation is
+ placed at the string mid-point, the sound is
+ that of a clarinet. At points closer to the
+ "bridge", the sound is closer to that of a
+ saxophone. See Scavone (2002) for more details.
+
+ This is a digital waveguide model, making its
+ use possibly subject to patents held by Stanford
+ University, Yamaha, and others.
+
+ Control Change Numbers:
+ - Reed Stiffness = 2
+ - Reed Aperture = 26
+ - Noise Gain = 4
+ - Blow Position = 11
+ - Vibrato Frequency = 29
+ - Vibrato Gain = 1
+ - Breath Pressure = 128
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "Saxofony.h"
+#include "Skini_msg.h"
+
+namespace stk {
+
+Saxofony :: Saxofony( StkFloat lowestFrequency )
+{
+ length_ = (unsigned long) (Stk::sampleRate() / lowestFrequency + 1);
+ // Initialize blowing position to 0.2 of length / 2.
+ position_ = 0.2;
+ delays_[0].setMaximumDelay( length_ );
+ delays_[0].setDelay( (1.0-position_) * (length_ >> 1) );
+ delays_[1].setMaximumDelay( length_ );
+ delays_[1].setDelay( (1.0-position_) * (length_ >> 1) );
+
+ reedTable_.setOffset( 0.7 );
+ reedTable_.setSlope( 0.3 );
+
+ vibrato_.setFrequency((StkFloat) 5.735);
+
+ outputGain_ = 0.3;
+ noiseGain_ = 0.2;
+ vibratoGain_ = 0.1;
+}
+
+Saxofony :: ~Saxofony( void )
+{
+}
+
+void Saxofony :: clear( void )
+{
+ delays_[0].clear();
+ delays_[1].clear();
+ filter_.clear();
+}
+
+void Saxofony :: setFrequency( StkFloat frequency )
+{
+ StkFloat freakency = frequency;
+ if ( frequency <= 0.0 ) {
+ errorString_ << "Saxofony::setFrequency: parameter is less than or equal to zero!";
+ handleError( StkError::WARNING );
+ freakency = 220.0;
+ }
+
+ StkFloat delay = (Stk::sampleRate() / freakency) - (StkFloat) 3.0;
+ if (delay <= 0.0) delay = 0.3;
+ else if (delay > length_) delay = length_;
+
+ delays_[0].setDelay( (1.0-position_) * delay );
+ delays_[1].setDelay( position_ * delay );
+}
+
+void Saxofony :: setBlowPosition( StkFloat position )
+{
+ if ( position_ == position ) return;
+
+ if ( position < 0.0 ) position_ = 0.0;
+ else if ( position > 1.0 ) position_ = 1.0;
+ else position_ = position;
+
+ StkFloat totalDelay = delays_[0].getDelay();
+ totalDelay += delays_[1].getDelay();
+
+ delays_[0].setDelay( (1.0-position_) * totalDelay );
+ delays_[1].setDelay( position_ * totalDelay );
+}
+
+void Saxofony :: startBlowing( StkFloat amplitude, StkFloat rate )
+{
+ envelope_.setRate( rate );
+ envelope_.setTarget( amplitude );
+}
+
+void Saxofony :: stopBlowing( StkFloat rate )
+{
+ envelope_.setRate( rate );
+ envelope_.setTarget( 0.0 );
+}
+
+void Saxofony :: noteOn( StkFloat frequency, StkFloat amplitude )
+{
+ this->setFrequency( frequency );
+ this->startBlowing( 0.55 + (amplitude * 0.30), amplitude * 0.005 );
+ outputGain_ = amplitude + 0.001;
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Saxofony::NoteOn: frequency = " << frequency << ", amplitude = " << amplitude << ".";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+void Saxofony :: noteOff( StkFloat amplitude )
+{
+ this->stopBlowing( amplitude * 0.01 );
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Saxofony::NoteOff: amplitude = " << amplitude << ".";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+void Saxofony :: controlChange( int number, StkFloat value )
+{
+ StkFloat norm = value * ONE_OVER_128;
+ if ( norm < 0 ) {
+ norm = 0.0;
+ errorString_ << "Saxofony::controlChange: control value less than zero ... setting to zero!";
+ handleError( StkError::WARNING );
+ }
+ else if ( norm > 1.0 ) {
+ norm = 1.0;
+ errorString_ << "Saxofony::controlChange: control value greater than 128.0 ... setting to 128.0!";
+ handleError( StkError::WARNING );
+ }
+
+ if (number == __SK_ReedStiffness_) // 2
+ reedTable_.setSlope( 0.1 + (0.4 * norm) );
+ else if (number == __SK_NoiseLevel_) // 4
+ noiseGain_ = ( norm * 0.4 );
+ else if (number == 29) // 29
+ vibrato_.setFrequency( norm * 12.0 );
+ else if (number == __SK_ModWheel_) // 1
+ vibratoGain_ = ( norm * 0.5 );
+ else if (number == __SK_AfterTouch_Cont_) // 128
+ envelope_.setValue( norm );
+ else if (number == 11) // 11
+ this->setBlowPosition( norm );
+ else if (number == 26) // reed table offset
+ reedTable_.setOffset(0.4 + ( norm * 0.6));
+ else {
+ errorString_ << "Saxofony::controlChange: undefined control number (" << number << ")!";
+ handleError( StkError::WARNING );
+ }
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Saxofony::controlChange: number = " << number << ", value = " << value << ".";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class Shakers
+ \brief PhISEM and PhOLIES class.
+
+ PhISEM (Physically Informed Stochastic Event
+ Modeling) is an algorithmic approach for
+ simulating collisions of multiple independent
+ sound producing objects. This class is a
+ meta-model that can simulate a Maraca, Sekere,
+ Cabasa, Bamboo Wind Chimes, Water Drops,
+ Tambourine, Sleighbells, and a Guiro.
+
+ PhOLIES (Physically-Oriented Library of
+ Imitated Environmental Sounds) is a similar
+ approach for the synthesis of environmental
+ sounds. This class implements simulations of
+ breaking sticks, crunchy snow (or not), a
+ wrench, sandpaper, and more.
+
+ Control Change Numbers:
+ - Shake Energy = 2
+ - System Decay = 4
+ - Number Of Objects = 11
+ - Resonance Frequency = 1
+ - Shake Energy = 128
+ - Instrument Selection = 1071
+ - Maraca = 0
+ - Cabasa = 1
+ - Sekere = 2
+ - Guiro = 3
+ - Water Drops = 4
+ - Bamboo Chimes = 5
+ - Tambourine = 6
+ - Sleigh Bells = 7
+ - Sticks = 8
+ - Crunch = 9
+ - Wrench = 10
+ - Sand Paper = 11
+ - Coke Can = 12
+ - Next Mug = 13
+ - Penny + Mug = 14
+ - Nickle + Mug = 15
+ - Dime + Mug = 16
+ - Quarter + Mug = 17
+ - Franc + Mug = 18
+ - Peso + Mug = 19
+ - Big Rocks = 20
+ - Little Rocks = 21
+ - Tuned Bamboo Chimes = 22
+
+ by Perry R. Cook, 1996 - 2010.
+*/
+/***************************************************/
+
+#include "Shakers.h"
+#include "Skini_msg.h"
+#include <cstring>
+#include <cmath>
+#include <cstdlib>
+
+namespace stk {
+
+int my_random( int max ) // Return Random Int Between 0 and max
+{
+ int temp = (int) ((float)max * rand() / (RAND_MAX + 1.0) );
+ return temp;
+}
+
+StkFloat float_random( StkFloat max ) // Return random float between 0.0 and max
+{
+ StkFloat temp = (StkFloat) (max * rand() / (RAND_MAX + 1.0) );
+ return temp;
+}
+
+StkFloat noise_tick( void ) // Return random StkFloat float between -1.0 and 1.0
+{
+ StkFloat temp = (StkFloat) (2.0 * rand() / (RAND_MAX + 1.0) );
+ temp -= 1.0;
+ return temp;
+}
+
+// Maraca
+const StkFloat MARA_SOUND_DECAY = 0.95;
+const StkFloat MARA_SYSTEM_DECAY = 0.999;
+const StkFloat MARA_GAIN = 20.0;
+const StkFloat MARA_NUM_BEANS = 25;
+const StkFloat MARA_CENTER_FREQ = 3200.0;
+const StkFloat MARA_RESON = 0.96;
+
+// Sekere
+const StkFloat SEKE_SOUND_DECAY = 0.96;
+const StkFloat SEKE_SYSTEM_DECAY = 0.999;
+const StkFloat SEKE_GAIN = 20.0;
+const StkFloat SEKE_NUM_BEANS = 64;
+const StkFloat SEKE_CENTER_FREQ = 5500.0;
+const StkFloat SEKE_RESON = 0.6;
+
+// Sandpaper
+const StkFloat SANDPAPR_SOUND_DECAY = 0.999;
+const StkFloat SANDPAPR_SYSTEM_DECAY = 0.999;
+const StkFloat SANDPAPR_GAIN = 0.5;
+const StkFloat SANDPAPR_NUM_GRAINS = 128;
+const StkFloat SANDPAPR_CENTER_FREQ = 4500.0;
+const StkFloat SANDPAPR_RESON = 0.6;
+
+// Cabasa
+const StkFloat CABA_SOUND_DECAY = 0.96;
+const StkFloat CABA_SYSTEM_DECAY = 0.997;
+const StkFloat CABA_GAIN = 40.0;
+const StkFloat CABA_NUM_BEADS = 512;
+const StkFloat CABA_CENTER_FREQ = 3000.0;
+const StkFloat CABA_RESON = 0.7;
+
+// Bamboo Wind Chimes
+const StkFloat BAMB_SOUND_DECAY = 0.95;
+const StkFloat BAMB_SYSTEM_DECAY = 0.9999;
+const StkFloat BAMB_GAIN = 2.0;
+const StkFloat BAMB_NUM_TUBES = 1.25;
+const StkFloat BAMB_CENTER_FREQ0 = 2800.0;
+const StkFloat BAMB_CENTER_FREQ1 = 0.8 * 2800.0;
+const StkFloat BAMB_CENTER_FREQ2 = 1.2 * 2800.0;
+const StkFloat BAMB_RESON = 0.995;
+
+// Tuned Bamboo Wind Chimes (Anklung)
+const StkFloat TBAMB_SOUND_DECAY = 0.95;
+const StkFloat TBAMB_SYSTEM_DECAY = 0.9999;
+const StkFloat TBAMB_GAIN = 1.0;
+const StkFloat TBAMB_NUM_TUBES = 1.25;
+const StkFloat TBAMB_CENTER_FREQ0 = 1046.6;
+const StkFloat TBAMB_CENTER_FREQ1 = 1174.8;
+const StkFloat TBAMB_CENTER_FREQ2 = 1397.0;
+const StkFloat TBAMB_CENTER_FREQ3 = 1568.0;
+const StkFloat TBAMB_CENTER_FREQ4 = 1760.0;
+const StkFloat TBAMB_CENTER_FREQ5 = 2093.3;
+const StkFloat TBAMB_CENTER_FREQ6 = 2350.0;
+const StkFloat TBAMB_RESON = 0.996;
+
+// Water Drops
+const StkFloat WUTR_SOUND_DECAY = 0.95;
+const StkFloat WUTR_SYSTEM_DECAY = 0.996;
+const StkFloat WUTR_GAIN = 1.0;
+const StkFloat WUTR_NUM_SOURCES = 10;
+const StkFloat WUTR_CENTER_FREQ0 = 450.0;
+const StkFloat WUTR_CENTER_FREQ1 = 600.0;
+const StkFloat WUTR_CENTER_FREQ2 = 750.0;
+const StkFloat WUTR_RESON = 0.9985;
+const StkFloat WUTR_FREQ_SWEEP = 1.0001;
+
+// Tambourine
+const StkFloat TAMB_SOUND_DECAY = 0.95;
+const StkFloat TAMB_SYSTEM_DECAY = 0.9985;
+const StkFloat TAMB_GAIN = 5.0;
+const StkFloat TAMB_NUM_TIMBRELS = 32;
+const StkFloat TAMB_SHELL_FREQ = 2300;
+const StkFloat TAMB_SHELL_GAIN = 0.1;
+const StkFloat TAMB_SHELL_RESON = 0.96;
+const StkFloat TAMB_CYMB_FREQ1 = 5600;
+const StkFloat TAMB_CYMB_FREQ2 = 8100;
+const StkFloat TAMB_CYMB_RESON = 0.99;
+
+// Sleighbells
+const StkFloat SLEI_SOUND_DECAY = 0.97;
+const StkFloat SLEI_SYSTEM_DECAY = 0.9994;
+const StkFloat SLEI_GAIN = 1.0;
+const StkFloat SLEI_NUM_BELLS = 32;
+const StkFloat SLEI_CYMB_FREQ0 = 2500;
+const StkFloat SLEI_CYMB_FREQ1 = 5300;
+const StkFloat SLEI_CYMB_FREQ2 = 6500;
+const StkFloat SLEI_CYMB_FREQ3 = 8300;
+const StkFloat SLEI_CYMB_FREQ4 = 9800;
+const StkFloat SLEI_CYMB_RESON = 0.99;
+
+// Guiro
+const StkFloat GUIR_SOUND_DECAY = 0.95;
+const StkFloat GUIR_GAIN = 10.0;
+const StkFloat GUIR_NUM_PARTS = 128;
+const StkFloat GUIR_GOURD_FREQ = 2500.0;
+const StkFloat GUIR_GOURD_RESON = 0.97;
+const StkFloat GUIR_GOURD_FREQ2 = 4000.0;
+const StkFloat GUIR_GOURD_RESON2 = 0.97;
+
+// Wrench
+const StkFloat WRENCH_SOUND_DECAY = 0.95;
+const StkFloat WRENCH_GAIN = 5;
+const StkFloat WRENCH_NUM_PARTS = 128;
+const StkFloat WRENCH_FREQ = 3200.0;
+const StkFloat WRENCH_RESON = 0.99;
+const StkFloat WRENCH_FREQ2 = 8000.0;
+const StkFloat WRENCH_RESON2 = 0.992;
+
+// Cokecan
+const StkFloat COKECAN_SOUND_DECAY = 0.97;
+const StkFloat COKECAN_SYSTEM_DECAY = 0.999;
+const StkFloat COKECAN_GAIN = 0.8;
+const StkFloat COKECAN_NUM_PARTS = 48;
+const StkFloat COKECAN_HELMFREQ = 370;
+const StkFloat COKECAN_HELM_RES = 0.99;
+const StkFloat COKECAN_METLFREQ0 = 1025;
+const StkFloat COKECAN_METLFREQ1 = 1424;
+const StkFloat COKECAN_METLFREQ2 = 2149;
+const StkFloat COKECAN_METLFREQ3 = 3596;
+const StkFloat COKECAN_METL_RES = 0.992;
+
+// PhOLIES (Physically-Oriented Library of Imitated Environmental
+// Sounds), Perry Cook, 1997-8
+
+// Stix1
+const StkFloat STIX1_SOUND_DECAY = 0.96;
+const StkFloat STIX1_SYSTEM_DECAY = 0.998;
+const StkFloat STIX1_GAIN = 30.0;
+const StkFloat STIX1_NUM_BEANS = 2;
+const StkFloat STIX1_CENTER_FREQ = 5500.0;
+const StkFloat STIX1_RESON = 0.6;
+
+// Crunch1
+const StkFloat CRUNCH1_SOUND_DECAY = 0.95;
+const StkFloat CRUNCH1_SYSTEM_DECAY = 0.99806;
+const StkFloat CRUNCH1_GAIN = 20.0;
+const StkFloat CRUNCH1_NUM_BEADS = 7;
+const StkFloat CRUNCH1_CENTER_FREQ = 800.0;
+const StkFloat CRUNCH1_RESON = 0.95;
+
+// Nextmug
+const StkFloat NEXTMUG_SOUND_DECAY = 0.97;
+const StkFloat NEXTMUG_SYSTEM_DECAY = 0.9995;
+const StkFloat NEXTMUG_GAIN = 0.8;
+const StkFloat NEXTMUG_NUM_PARTS = 3;
+const StkFloat NEXTMUG_FREQ0 = 2123;
+const StkFloat NEXTMUG_FREQ1 = 4518;
+const StkFloat NEXTMUG_FREQ2 = 8856;
+const StkFloat NEXTMUG_FREQ3 = 10753;
+const StkFloat NEXTMUG_RES = 0.997;
+
+const StkFloat PENNY_FREQ0 = 11000;
+const StkFloat PENNY_FREQ1 = 5200;
+const StkFloat PENNY_FREQ2 = 3835;
+const StkFloat PENNY_RES = 0.999;
+
+const StkFloat NICKEL_FREQ0 = 5583;
+const StkFloat NICKEL_FREQ1 = 9255;
+const StkFloat NICKEL_FREQ2 = 9805;
+const StkFloat NICKEL_RES = 0.9992;
+
+const StkFloat DIME_FREQ0 = 4450;
+const StkFloat DIME_FREQ1 = 4974;
+const StkFloat DIME_FREQ2 = 9945;
+const StkFloat DIME_RES = 0.9993;
+
+const StkFloat QUARTER_FREQ0 = 1708;
+const StkFloat QUARTER_FREQ1 = 8863;
+const StkFloat QUARTER_FREQ2 = 9045;
+const StkFloat QUARTER_RES = 0.9995;
+
+const StkFloat FRANC_FREQ0 = 5583;
+const StkFloat FRANC_FREQ1 = 11010;
+const StkFloat FRANC_FREQ2 = 1917;
+const StkFloat FRANC_RES = 0.9995;
+
+const StkFloat PESO_FREQ0 = 7250;
+const StkFloat PESO_FREQ1 = 8150;
+const StkFloat PESO_FREQ2 = 10060;
+const StkFloat PESO_RES = 0.9996;
+
+// Big Gravel
+const StkFloat BIGROCKS_SOUND_DECAY = 0.98;
+const StkFloat BIGROCKS_SYSTEM_DECAY = 0.9965;
+const StkFloat BIGROCKS_GAIN = 20.0;
+const StkFloat BIGROCKS_NUM_PARTS = 23;
+const StkFloat BIGROCKS_FREQ = 6460;
+const StkFloat BIGROCKS_RES = 0.932;
+
+// Little Gravel
+const StkFloat LITLROCKS_SOUND_DECAY = 0.98;
+const StkFloat LITLROCKS_SYSTEM_DECAY = 0.99586;
+const StkFloat LITLROCKS_GAIN = 20.0;
+const StkFloat LITLROCKS_NUM_PARTS = 1600;
+const StkFloat LITLROCKS_FREQ = 9000;
+const StkFloat LITLROCKS_RES = 0.843;
+
+// Finally ... the class code!
+
+Shakers :: Shakers( void )
+{
+ int i;
+
+ instType_ = 0;
+ shakeEnergy_ = 0.0;
+ nFreqs_ = 0;
+ sndLevel_ = 0.0;
+
+ for ( i=0; i<MAX_FREQS; i++ ) {
+ inputs_[i] = 0.0;
+ outputs_[i][0] = 0.0;
+ outputs_[i][1] = 0.0;
+ coeffs_[i][0] = 0.0;
+ coeffs_[i][1] = 0.0;
+ gains_[i] = 0.0;
+ center_freqs_[i] = 0.0;
+ resons_[i] = 0.0;
+ freq_rand_[i] = 0.0;
+ freqalloc_[i] = 0;
+ }
+
+ soundDecay_ = 0.0;
+ systemDecay_ = 0.0;
+ nObjects_ = 0.0;
+ totalEnergy_ = 0.0;
+ ratchet_ = 0.0;
+ ratchetDelta_ = 0.0005;
+ lastRatchetPos_ = 0;
+ finalZ_[0] = 0.0;
+ finalZ_[1] = 0.0;
+ finalZ_[2] = 0.0;
+ finalZCoeffs_[0] = 1.0;
+ finalZCoeffs_[1] = 0.0;
+ finalZCoeffs_[2] = 0.0;
+
+ this->setupNum(instType_);
+}
+
+Shakers :: ~Shakers( void )
+{
+}
+
+const StkFloat MAX_SHAKE = 2000.0;
+
+char instrs[NUM_INSTR][10] = {
+ "Maraca", "Cabasa", "Sekere", "Guiro",
+ "Waterdrp", "Bamboo", "Tambourn", "Sleighbl",
+ "Stix1", "Crunch1", "Wrench", "SandPapr",
+ "CokeCan", "NextMug", "PennyMug", "NicklMug",
+ "DimeMug", "QuartMug", "FrancMug", "PesoMug",
+ "BigRocks", "LitlRoks", "TBamboo"
+};
+
+int Shakers :: setupName( char* instr )
+{
+ int which = 0;
+
+ for (int i=0;i<NUM_INSTR;i++) {
+ if ( !strcmp(instr,instrs[i]) )
+ which = i;
+ }
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Shakers::setupName: setting instrument to " << instrs[which] << '.';
+ handleError( StkError::DEBUG_WARNING );
+#endif
+
+ return this->setupNum(which);
+}
+
+void Shakers :: setFinalZs( StkFloat z0, StkFloat z1, StkFloat z2 )
+{
+ finalZCoeffs_[0] = z0;
+ finalZCoeffs_[1] = z1;
+ finalZCoeffs_[2] = z2;
+}
+
+void Shakers :: setDecays( StkFloat sndDecay, StkFloat sysDecay )
+{
+ soundDecay_ = sndDecay;
+ systemDecay_ = sysDecay;
+}
+
+int Shakers :: setFreqAndReson( int which, StkFloat freq, StkFloat reson )
+{
+ if ( which < MAX_FREQS ) {
+ resons_[which] = reson;
+ center_freqs_[which] = freq;
+ t_center_freqs_[which] = freq;
+ coeffs_[which][1] = reson * reson;
+ coeffs_[which][0] = -reson * 2.0 * cos(freq * TWO_PI / Stk::sampleRate());
+ return 1;
+ }
+ else return 0;
+}
+
+int Shakers :: setupNum( int inst )
+{
+ int i, rv = 0;
+ StkFloat temp;
+
+ if (inst == 1) { // Cabasa
+ rv = inst;
+ nObjects_ = CABA_NUM_BEADS;
+ defObjs_[inst] = CABA_NUM_BEADS;
+ setDecays(CABA_SOUND_DECAY, CABA_SYSTEM_DECAY);
+ defDecays_[inst] = CABA_SYSTEM_DECAY;
+ decayScale_[inst] = 0.97;
+ nFreqs_ = 1;
+ baseGain_ = CABA_GAIN;
+ temp = log(nObjects_) * baseGain_ / (StkFloat) nObjects_;
+ gains_[0] = temp;
+ freqalloc_[0] = 0;
+ setFreqAndReson(0,CABA_CENTER_FREQ,CABA_RESON);
+ setFinalZs(1.0,-1.0,0.0);
+ }
+ else if (inst == 2) { // Sekere
+ rv = inst;
+ nObjects_ = SEKE_NUM_BEANS;
+ defObjs_[inst] = SEKE_NUM_BEANS;
+ this->setDecays(SEKE_SOUND_DECAY,SEKE_SYSTEM_DECAY);
+ defDecays_[inst] = SEKE_SYSTEM_DECAY;
+ decayScale_[inst] = 0.94;
+ nFreqs_ = 1;
+ baseGain_ = SEKE_GAIN;
+ temp = log(nObjects_) * baseGain_ / (StkFloat) nObjects_;
+ gains_[0] = temp;
+ freqalloc_[0] = 0;
+ this->setFreqAndReson(0,SEKE_CENTER_FREQ,SEKE_RESON);
+ this->setFinalZs(1.0, 0.0, -1.0);
+ }
+ else if (inst == 3) { // Guiro
+ rv = inst;
+ nObjects_ = GUIR_NUM_PARTS;
+ defObjs_[inst] = GUIR_NUM_PARTS;
+ setDecays(GUIR_SOUND_DECAY,1.0);
+ defDecays_[inst] = 0.9999;
+ decayScale_[inst] = 1.0;
+ nFreqs_ = 2;
+ baseGain_ = GUIR_GAIN;
+ temp = log(nObjects_) * baseGain_ / (StkFloat) nObjects_;
+ gains_[0]=temp;
+ gains_[1]=temp;
+ freqalloc_[0] = 0;
+ freqalloc_[1] = 0;
+ freq_rand_[0] = 0.0;
+ freq_rand_[1] = 0.0;
+ setFreqAndReson(0,GUIR_GOURD_FREQ,GUIR_GOURD_RESON);
+ setFreqAndReson(1,GUIR_GOURD_FREQ2,GUIR_GOURD_RESON2);
+ ratchet_ = 0;
+ ratchetPos_ = 10;
+ }
+ else if (inst == 4) { // Water Drops
+ rv = inst;
+ nObjects_ = WUTR_NUM_SOURCES;
+ defObjs_[inst] = WUTR_NUM_SOURCES;
+ setDecays(WUTR_SOUND_DECAY,WUTR_SYSTEM_DECAY);
+ defDecays_[inst] = WUTR_SYSTEM_DECAY;
+ decayScale_[inst] = 0.8;
+ nFreqs_ = 3;
+ baseGain_ = WUTR_GAIN;
+ temp = log(nObjects_) * baseGain_ / (StkFloat) nObjects_;
+ gains_[0]=temp;
+ gains_[1]=temp;
+ gains_[2]=temp;
+ freqalloc_[0] = 1;
+ freqalloc_[1] = 1;
+ freqalloc_[2] = 1;
+ freq_rand_[0] = 0.2;
+ freq_rand_[1] = 0.2;
+ freq_rand_[2] = 0.2;
+ setFreqAndReson(0,WUTR_CENTER_FREQ0,WUTR_RESON);
+ setFreqAndReson(1,WUTR_CENTER_FREQ0,WUTR_RESON);
+ setFreqAndReson(2,WUTR_CENTER_FREQ0,WUTR_RESON);
+ setFinalZs(1.0,0.0,0.0);
+ }
+ else if (inst == 5) { // Bamboo
+ rv = inst;
+ nObjects_ = BAMB_NUM_TUBES;
+ defObjs_[inst] = BAMB_NUM_TUBES;
+ setDecays(BAMB_SOUND_DECAY, BAMB_SYSTEM_DECAY);
+ defDecays_[inst] = BAMB_SYSTEM_DECAY;
+ decayScale_[inst] = 0.7;
+ nFreqs_ = 3;
+ baseGain_ = BAMB_GAIN;
+ temp = log(nObjects_) * baseGain_ / (StkFloat) nObjects_;
+ gains_[0]=temp;
+ gains_[1]=temp;
+ gains_[2]=temp;
+ freqalloc_[0] = 1;
+ freqalloc_[1] = 1;
+ freqalloc_[2] = 1;
+ freq_rand_[0] = 0.2;
+ freq_rand_[1] = 0.2;
+ freq_rand_[2] = 0.2;
+ setFreqAndReson(0,BAMB_CENTER_FREQ0,BAMB_RESON);
+ setFreqAndReson(1,BAMB_CENTER_FREQ1,BAMB_RESON);
+ setFreqAndReson(2,BAMB_CENTER_FREQ2,BAMB_RESON);
+ setFinalZs(1.0,0.0,0.0);
+ }
+ else if (inst == 6) { // Tambourine
+ rv = inst;
+ nObjects_ = TAMB_NUM_TIMBRELS;
+ defObjs_[inst] = TAMB_NUM_TIMBRELS;
+ setDecays(TAMB_SOUND_DECAY,TAMB_SYSTEM_DECAY);
+ defDecays_[inst] = TAMB_SYSTEM_DECAY;
+ decayScale_[inst] = 0.95;
+ nFreqs_ = 3;
+ baseGain_ = TAMB_GAIN;
+ temp = log(nObjects_) * baseGain_ / (StkFloat) nObjects_;
+ gains_[0]=temp*TAMB_SHELL_GAIN;
+ gains_[1]=temp*0.8;
+ gains_[2]=temp;
+ freqalloc_[0] = 0;
+ freqalloc_[1] = 1;
+ freqalloc_[2] = 1;
+ freq_rand_[0] = 0.0;
+ freq_rand_[1] = 0.05;
+ freq_rand_[2] = 0.05;
+ setFreqAndReson(0,TAMB_SHELL_FREQ,TAMB_SHELL_RESON);
+ setFreqAndReson(1,TAMB_CYMB_FREQ1,TAMB_CYMB_RESON);
+ setFreqAndReson(2,TAMB_CYMB_FREQ2,TAMB_CYMB_RESON);
+ setFinalZs(1.0,0.0,-1.0);
+ }
+ else if (inst == 7) { // Sleighbell
+ rv = inst;
+ nObjects_ = SLEI_NUM_BELLS;
+ defObjs_[inst] = SLEI_NUM_BELLS;
+ setDecays(SLEI_SOUND_DECAY,SLEI_SYSTEM_DECAY);
+ defDecays_[inst] = SLEI_SYSTEM_DECAY;
+ decayScale_[inst] = 0.9;
+ nFreqs_ = 5;
+ baseGain_ = SLEI_GAIN;
+ temp = log(nObjects_) * baseGain_ / (StkFloat) nObjects_;
+ gains_[0]=temp;
+ gains_[1]=temp;
+ gains_[2]=temp;
+ gains_[3]=temp*0.5;
+ gains_[4]=temp*0.3;
+ for (i=0;i<nFreqs_;i++) {
+ freqalloc_[i] = 1;
+ freq_rand_[i] = 0.03;
+ }
+ setFreqAndReson(0,SLEI_CYMB_FREQ0,SLEI_CYMB_RESON);
+ setFreqAndReson(1,SLEI_CYMB_FREQ1,SLEI_CYMB_RESON);
+ setFreqAndReson(2,SLEI_CYMB_FREQ2,SLEI_CYMB_RESON);
+ setFreqAndReson(3,SLEI_CYMB_FREQ3,SLEI_CYMB_RESON);
+ setFreqAndReson(4,SLEI_CYMB_FREQ4,SLEI_CYMB_RESON);
+ setFinalZs(1.0,0.0,-1.0);
+ }
+ else if (inst == 8) { // Stix1
+ rv = inst;
+ nObjects_ = STIX1_NUM_BEANS;
+ defObjs_[inst] = STIX1_NUM_BEANS;
+ setDecays(STIX1_SOUND_DECAY,STIX1_SYSTEM_DECAY);
+ defDecays_[inst] = STIX1_SYSTEM_DECAY;
+
+ decayScale_[inst] = 0.96;
+ nFreqs_ = 1;
+ baseGain_ = STIX1_GAIN;
+ temp = log(nObjects_) * baseGain_ / (StkFloat) nObjects_;
+ gains_[0]=temp;
+ freqalloc_[0] = 0;
+ setFreqAndReson(0,STIX1_CENTER_FREQ,STIX1_RESON);
+ setFinalZs(1.0,0.0,-1.0);
+ }
+ else if (inst == 9) { // Crunch1
+ rv = inst;
+ nObjects_ = CRUNCH1_NUM_BEADS;
+ defObjs_[inst] = CRUNCH1_NUM_BEADS;
+ setDecays(CRUNCH1_SOUND_DECAY,CRUNCH1_SYSTEM_DECAY);
+ defDecays_[inst] = CRUNCH1_SYSTEM_DECAY;
+ decayScale_[inst] = 0.96;
+ nFreqs_ = 1;
+ baseGain_ = CRUNCH1_GAIN;
+ temp = log(nObjects_) * baseGain_ / (StkFloat) nObjects_;
+ gains_[0]=temp;
+ freqalloc_[0] = 0;
+ setFreqAndReson(0,CRUNCH1_CENTER_FREQ,CRUNCH1_RESON);
+ setFinalZs(1.0,-1.0,0.0);
+ }
+ else if (inst == 10) { // Wrench
+ rv = inst;
+ nObjects_ = WRENCH_NUM_PARTS;
+ defObjs_[inst] = WRENCH_NUM_PARTS;
+ setDecays(WRENCH_SOUND_DECAY,1.0);
+ defDecays_[inst] = 0.9999;
+ decayScale_[inst] = 0.98;
+ nFreqs_ = 2;
+ baseGain_ = WRENCH_GAIN;
+ temp = log(nObjects_) * baseGain_ / (StkFloat) nObjects_;
+ gains_[0]=temp;
+ gains_[1]=temp;
+ freqalloc_[0] = 0;
+ freqalloc_[1] = 0;
+ freq_rand_[0] = 0.0;
+ freq_rand_[1] = 0.0;
+ setFreqAndReson(0,WRENCH_FREQ,WRENCH_RESON);
+ setFreqAndReson(1,WRENCH_FREQ2,WRENCH_RESON2);
+ ratchet_ = 0;
+ ratchetPos_ = 10;
+ }
+ else if (inst == 11) { // Sandpapr
+ rv = inst;
+ nObjects_ = SANDPAPR_NUM_GRAINS;
+ defObjs_[inst] = SANDPAPR_NUM_GRAINS;
+ this->setDecays(SANDPAPR_SOUND_DECAY,SANDPAPR_SYSTEM_DECAY);
+ defDecays_[inst] = SANDPAPR_SYSTEM_DECAY;
+ decayScale_[inst] = 0.97;
+ nFreqs_ = 1;
+ baseGain_ = SANDPAPR_GAIN;
+ temp = log(nObjects_) * baseGain_ / (StkFloat) nObjects_;
+ gains_[0] = temp;
+ freqalloc_[0] = 0;
+ this->setFreqAndReson(0,SANDPAPR_CENTER_FREQ,SANDPAPR_RESON);
+ this->setFinalZs(1.0, 0.0, -1.0);
+ }
+ else if (inst == 12) { // Cokecan
+ rv = inst;
+ nObjects_ = COKECAN_NUM_PARTS;
+ defObjs_[inst] = COKECAN_NUM_PARTS;
+ setDecays(COKECAN_SOUND_DECAY,COKECAN_SYSTEM_DECAY);
+ defDecays_[inst] = COKECAN_SYSTEM_DECAY;
+ decayScale_[inst] = 0.95;
+ nFreqs_ = 5;
+ baseGain_ = COKECAN_GAIN;
+ temp = log(nObjects_) * baseGain_ / (StkFloat) nObjects_;
+ gains_[0]=temp;
+ gains_[1]=temp*1.8;
+ gains_[2]=temp*1.8;
+ gains_[3]=temp*1.8;
+ gains_[4]=temp*1.8;
+ freqalloc_[0] = 0;
+ freqalloc_[1] = 0;
+ freqalloc_[2] = 0;
+ freqalloc_[3] = 0;
+ freqalloc_[4] = 0;
+ setFreqAndReson(0,COKECAN_HELMFREQ,COKECAN_HELM_RES);
+ setFreqAndReson(1,COKECAN_METLFREQ0,COKECAN_METL_RES);
+ setFreqAndReson(2,COKECAN_METLFREQ1,COKECAN_METL_RES);
+ setFreqAndReson(3,COKECAN_METLFREQ2,COKECAN_METL_RES);
+ setFreqAndReson(4,COKECAN_METLFREQ3,COKECAN_METL_RES);
+ setFinalZs(1.0,0.0,-1.0);
+ }
+ else if (inst>12 && inst<20) { // Nextmug
+ rv = inst;
+ nObjects_ = NEXTMUG_NUM_PARTS;
+ defObjs_[inst] = NEXTMUG_NUM_PARTS;
+ setDecays(NEXTMUG_SOUND_DECAY,NEXTMUG_SYSTEM_DECAY);
+ defDecays_[inst] = NEXTMUG_SYSTEM_DECAY;
+ decayScale_[inst] = 0.95;
+ nFreqs_ = 4;
+ baseGain_ = NEXTMUG_GAIN;
+ temp = log(nObjects_) * baseGain_ / (StkFloat) nObjects_;
+ gains_[0]=temp;
+ gains_[1]=temp*0.8;
+ gains_[2]=temp*0.6;
+ gains_[3]=temp*0.4;
+ freqalloc_[0] = 0;
+ freqalloc_[1] = 0;
+ freqalloc_[2] = 0;
+ freqalloc_[3] = 0;
+ freqalloc_[4] = 0;
+ freqalloc_[5] = 0;
+ setFreqAndReson(0,NEXTMUG_FREQ0,NEXTMUG_RES);
+ setFreqAndReson(1,NEXTMUG_FREQ1,NEXTMUG_RES);
+ setFreqAndReson(2,NEXTMUG_FREQ2,NEXTMUG_RES);
+ setFreqAndReson(3,NEXTMUG_FREQ3,NEXTMUG_RES);
+ setFinalZs(1.0,0.0,-1.0);
+
+ if (inst == 14) { // Mug + Penny
+ nFreqs_ = 7;
+ gains_[4] = temp;
+ gains_[5] = temp*0.8;
+ gains_[6] = temp*0.5;
+ setFreqAndReson(4,PENNY_FREQ0,PENNY_RES);
+ setFreqAndReson(5,PENNY_FREQ1,PENNY_RES);
+ setFreqAndReson(6,PENNY_FREQ2,PENNY_RES);
+ }
+ else if (inst == 15) { // Mug + Nickel
+ nFreqs_ = 6;
+ gains_[4] = temp;
+ gains_[5] = temp*0.8;
+ gains_[6] = temp*0.5;
+ setFreqAndReson(4,NICKEL_FREQ0,NICKEL_RES);
+ setFreqAndReson(5,NICKEL_FREQ1,NICKEL_RES);
+ setFreqAndReson(6,NICKEL_FREQ2,NICKEL_RES);
+ }
+ else if (inst == 16) { // Mug + Dime
+ nFreqs_ = 6;
+ gains_[4] = temp;
+ gains_[5] = temp*0.8;
+ gains_[6] = temp*0.5;
+ setFreqAndReson(4,DIME_FREQ0,DIME_RES);
+ setFreqAndReson(5,DIME_FREQ1,DIME_RES);
+ setFreqAndReson(6,DIME_FREQ2,DIME_RES);
+ }
+ else if (inst == 17) { // Mug + Quarter
+ nFreqs_ = 6;
+ gains_[4] = temp*1.3;
+ gains_[5] = temp*1.0;
+ gains_[6] = temp*0.8;
+ setFreqAndReson(4,QUARTER_FREQ0,QUARTER_RES);
+ setFreqAndReson(5,QUARTER_FREQ1,QUARTER_RES);
+ setFreqAndReson(6,QUARTER_FREQ2,QUARTER_RES);
+ }
+ else if (inst == 18) { // Mug + Franc
+ nFreqs_ = 6;
+ gains_[4] = temp*0.7;
+ gains_[5] = temp*0.4;
+ gains_[6] = temp*0.3;
+ setFreqAndReson(4,FRANC_FREQ0,FRANC_RES);
+ setFreqAndReson(5,FRANC_FREQ1,FRANC_RES);
+ setFreqAndReson(6,FRANC_FREQ2,FRANC_RES);
+ }
+ else if (inst == 19) { // Mug + Peso
+ nFreqs_ = 6;
+ gains_[4] = temp;
+ gains_[5] = temp*1.2;
+ gains_[6] = temp*0.7;
+ setFreqAndReson(4,PESO_FREQ0,PESO_RES);
+ setFreqAndReson(5,PESO_FREQ1,PESO_RES);
+ setFreqAndReson(6,PESO_FREQ2,PESO_RES);
+ }
+ }
+ else if (inst == 20) { // Big Rocks
+ nFreqs_ = 1;
+ rv = inst;
+ nObjects_ = BIGROCKS_NUM_PARTS;
+ defObjs_[inst] = BIGROCKS_NUM_PARTS;
+ setDecays(BIGROCKS_SOUND_DECAY,BIGROCKS_SYSTEM_DECAY);
+ defDecays_[inst] = BIGROCKS_SYSTEM_DECAY;
+ decayScale_[inst] = 0.95;
+ baseGain_ = BIGROCKS_GAIN;
+ temp = log(nObjects_) * baseGain_ / (StkFloat) nObjects_;
+ gains_[0]=temp;
+ freqalloc_[0] = 1;
+ freq_rand_[0] = 0.11;
+ setFreqAndReson(0,BIGROCKS_FREQ,BIGROCKS_RES);
+ setFinalZs(1.0,0.0,-1.0);
+ }
+ else if (inst == 21) { // Little Rocks
+ nFreqs_ = 1;
+ rv = inst;
+ nObjects_ = LITLROCKS_NUM_PARTS;
+ defObjs_[inst] = LITLROCKS_NUM_PARTS;
+ setDecays(LITLROCKS_SOUND_DECAY,LITLROCKS_SYSTEM_DECAY);
+ defDecays_[inst] = LITLROCKS_SYSTEM_DECAY;
+ decayScale_[inst] = 0.95;
+ baseGain_ = LITLROCKS_GAIN;
+ temp = log(nObjects_) * baseGain_ / (StkFloat) nObjects_;
+ gains_[0]=temp;
+ freqalloc_[0] = 1;
+ freq_rand_[0] = 0.18;
+ setFreqAndReson(0,LITLROCKS_FREQ,LITLROCKS_RES);
+ setFinalZs(1.0,0.0,-1.0);
+ }
+ else if (inst == 22) { // Tuned Bamboo
+ rv = inst;
+ nObjects_ = TBAMB_NUM_TUBES;
+ defObjs_[inst] = TBAMB_NUM_TUBES;
+ setDecays(TBAMB_SOUND_DECAY, TBAMB_SYSTEM_DECAY);
+ defDecays_[inst] = TBAMB_SYSTEM_DECAY;
+ decayScale_[inst] = 0.7;
+ nFreqs_ = 7;
+ baseGain_ = TBAMB_GAIN;
+ temp = log(nObjects_) * baseGain_ / (StkFloat) nObjects_;
+ gains_[0]=temp;
+ gains_[1]=temp;
+ gains_[2]=temp;
+ gains_[3]=temp;
+ gains_[4]=temp;
+ gains_[5]=temp;
+ gains_[6]=temp;
+ freqalloc_[0] = 0;
+ freqalloc_[1] = 0;
+ freqalloc_[2] = 0;
+ freqalloc_[3] = 0;
+ freqalloc_[4] = 0;
+ freqalloc_[5] = 0;
+ freqalloc_[6] = 0;
+ freq_rand_[0] = 0.0;
+ freq_rand_[1] = 0.0;
+ freq_rand_[2] = 0.0;
+ freq_rand_[3] = 0.0;
+ freq_rand_[4] = 0.0;
+ freq_rand_[5] = 0.0;
+ freq_rand_[6] = 0.0;
+ setFreqAndReson(0,TBAMB_CENTER_FREQ0,TBAMB_RESON);
+ setFreqAndReson(1,TBAMB_CENTER_FREQ1,TBAMB_RESON);
+ setFreqAndReson(2,TBAMB_CENTER_FREQ2,TBAMB_RESON);
+ setFreqAndReson(3,TBAMB_CENTER_FREQ3,TBAMB_RESON);
+ setFreqAndReson(4,TBAMB_CENTER_FREQ4,TBAMB_RESON);
+ setFreqAndReson(5,TBAMB_CENTER_FREQ5,TBAMB_RESON);
+ setFreqAndReson(6,TBAMB_CENTER_FREQ6,TBAMB_RESON);
+ setFinalZs(1.0,0.0,-1.0);
+ }
+ else { // Maraca (inst == 0) or default
+ rv = 0;
+ nObjects_ = MARA_NUM_BEANS;
+ defObjs_[0] = MARA_NUM_BEANS;
+ setDecays(MARA_SOUND_DECAY,MARA_SYSTEM_DECAY);
+ defDecays_[0] = MARA_SYSTEM_DECAY;
+ decayScale_[inst] = 0.9;
+ nFreqs_ = 1;
+ baseGain_ = MARA_GAIN;
+ temp = log(nObjects_) * baseGain_ / (StkFloat) nObjects_;
+ gains_[0]=temp;
+ freqalloc_[0] = 0;
+ setFreqAndReson(0,MARA_CENTER_FREQ,MARA_RESON);
+ setFinalZs(1.0,-1.0,0.0);
+ }
+ return rv;
+}
+
+void Shakers :: noteOn( StkFloat frequency, StkFloat amplitude )
+{
+ // Yep ... pretty kludgey, but it works!
+ int noteNum = (int) ((12*log(frequency/220.0)/log(2.0)) + 57.01) % 32;
+ if (instType_ != noteNum) instType_ = this->setupNum(noteNum);
+ shakeEnergy_ += amplitude * MAX_SHAKE * 0.1;
+ if (shakeEnergy_ > MAX_SHAKE) shakeEnergy_ = MAX_SHAKE;
+ if (instType_==10 || instType_==3) ratchetPos_ += 1;
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Shakers::NoteOn: frequency = " << frequency << ", amplitude = " << amplitude << '.';
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+void Shakers :: noteOff( StkFloat amplitude )
+{
+ shakeEnergy_ = 0.0;
+ if (instType_==10 || instType_==3) ratchetPos_ = 0;
+}
+
+const StkFloat MIN_ENERGY = 0.3;
+
+StkFloat Shakers :: tick( unsigned int )
+{
+ StkFloat data;
+ StkFloat temp_rand;
+ int i;
+
+ if (instType_ == 4) {
+ if (shakeEnergy_ > MIN_ENERGY) {
+ lastFrame_[0] = wuter_tick();
+ lastFrame_[0] *= 0.0001;
+ }
+ else {
+ lastFrame_[0] = 0.0;
+ }
+ }
+ else if (instType_ == 22) {
+ lastFrame_[0] = tbamb_tick();
+ }
+ else if (instType_ == 10 || instType_ == 3) {
+ if (ratchetPos_ > 0) {
+ ratchet_ -= (ratchetDelta_ + (0.002*totalEnergy_));
+ if (ratchet_ < 0.0) {
+ ratchet_ = 1.0;
+ ratchetPos_ -= 1;
+ }
+ totalEnergy_ = ratchet_;
+ lastFrame_[0] = ratchet_tick();
+ lastFrame_[0] *= 0.0001;
+ }
+ else lastFrame_[0] = 0.0;
+ }
+ else { // generic_tick()
+ if (shakeEnergy_ > MIN_ENERGY) {
+ shakeEnergy_ *= systemDecay_; // Exponential system decay
+ if (float_random(1024.0) < nObjects_) {
+ sndLevel_ += shakeEnergy_;
+ for (i=0;i<nFreqs_;i++) {
+ if (freqalloc_[i]) {
+ temp_rand = t_center_freqs_[i] * (1.0 + (freq_rand_[i] * noise_tick()));
+ coeffs_[i][0] = -resons_[i] * 2.0 * cos(temp_rand * TWO_PI / Stk::sampleRate());
+ }
+ }
+ }
+ inputs_[0] = sndLevel_ * noise_tick(); // Actual Sound is Random
+ for (i=1; i<nFreqs_; i++) {
+ inputs_[i] = inputs_[0];
+ }
+ sndLevel_ *= soundDecay_; // Exponential Sound decay
+ finalZ_[2] = finalZ_[1];
+ finalZ_[1] = finalZ_[0];
+ finalZ_[0] = 0;
+ for (i=0;i<nFreqs_;i++) {
+ inputs_[i] -= outputs_[i][0]*coeffs_[i][0]; // Do
+ inputs_[i] -= outputs_[i][1]*coeffs_[i][1]; // resonant
+ outputs_[i][1] = outputs_[i][0]; // filter
+ outputs_[i][0] = inputs_[i]; // calculations
+ finalZ_[0] += gains_[i] * outputs_[i][1];
+ }
+ data = finalZCoeffs_[0] * finalZ_[0]; // Extra zero(s) for shape
+ data += finalZCoeffs_[1] * finalZ_[1]; // Extra zero(s) for shape
+ data += finalZCoeffs_[2] * finalZ_[2]; // Extra zero(s) for shape
+ if (data > 10000.0) data = 10000.0;
+ if (data < -10000.0) data = -10000.0;
+ lastFrame_[0] = data * 0.0001;
+ }
+ else lastFrame_[0] = 0.0;
+ }
+
+ return lastFrame_[0];
+}
+
+void Shakers :: controlChange( int number, StkFloat value )
+{
+ StkFloat norm = value * ONE_OVER_128;
+ if ( norm < 0 ) {
+ norm = 0.0;
+ errorString_ << "Shakers::controlChange: control value less than zero ... setting to zero!";
+ handleError( StkError::WARNING );
+ }
+ else if ( norm > 1.0 ) {
+ norm = 1.0;
+ errorString_ << "Shakers::controlChange: control value greater than 128.0 ... setting to 128.0!";
+ handleError( StkError::WARNING );
+ }
+
+ StkFloat temp;
+ int i;
+
+ if (number == __SK_Breath_) { // 2 ... energy
+ shakeEnergy_ += norm * MAX_SHAKE * 0.1;
+ if (shakeEnergy_ > MAX_SHAKE) shakeEnergy_ = MAX_SHAKE;
+ if (instType_==10 || instType_==3) {
+ ratchetPos_ = (int) fabs(value - lastRatchetPos_);
+ ratchetDelta_ = 0.0002 * ratchetPos_;
+ lastRatchetPos_ = (int) value;
+ }
+ }
+ else if (number == __SK_ModFrequency_) { // 4 ... decay
+ if (instType_ != 3 && instType_ != 10) {
+ systemDecay_ = defDecays_[instType_] + ((value - 64.0) *
+ decayScale_[instType_] *
+ (1.0 - defDecays_[instType_]) / 64.0 );
+ gains_[0] = log(nObjects_) * baseGain_ / (StkFloat) nObjects_;
+ for (i=1;i<nFreqs_;i++) gains_[i] = gains_[0];
+ if (instType_ == 6) { // tambourine
+ gains_[0] *= TAMB_SHELL_GAIN;
+ gains_[1] *= 0.8;
+ }
+ else if (instType_ == 7) { // sleighbell
+ gains_[3] *= 0.5;
+ gains_[4] *= 0.3;
+ }
+ else if (instType_ == 12) { // cokecan
+ for (i=1;i<nFreqs_;i++) gains_[i] *= 1.8;
+ }
+ for (i=0;i<nFreqs_;i++) gains_[i] *= ((128-value)/100.0 + 0.36);
+ }
+ }
+ else if (number == __SK_FootControl_) { // 11 ... number of objects
+ if (instType_ == 5) // bamboo
+ nObjects_ = (StkFloat) (value * defObjs_[instType_] / 64.0) + 0.3;
+ else
+ nObjects_ = (StkFloat) (value * defObjs_[instType_] / 64.0) + 1.1;
+ gains_[0] = log(nObjects_) * baseGain_ / (StkFloat) nObjects_;
+ for (i=1;i<nFreqs_;i++) gains_[i] = gains_[0];
+ if (instType_ == 6) { // tambourine
+ gains_[0] *= TAMB_SHELL_GAIN;
+ gains_[1] *= 0.8;
+ }
+ else if (instType_ == 7) { // sleighbell
+ gains_[3] *= 0.5;
+ gains_[4] *= 0.3;
+ }
+ else if (instType_ == 12) { // cokecan
+ for (i=1;i<nFreqs_;i++) gains_[i] *= 1.8;
+ }
+ if (instType_ != 3 && instType_ != 10) {
+ // reverse calculate decay setting
+ double temp = (double) (64.0 * (systemDecay_-defDecays_[instType_])/(decayScale_[instType_]*(1-defDecays_[instType_])) + 64.0);
+ // scale gains_ by decay setting
+ for (i=0;i<nFreqs_;i++) gains_[i] *= ((128-temp)/100.0 + 0.36);
+ }
+ }
+ else if (number == __SK_ModWheel_) { // 1 ... resonance frequency
+ for (i=0; i<nFreqs_; i++) {
+ if (instType_ == 6 || instType_ == 2 || instType_ == 7) // limit range a bit for tambourine
+ temp = center_freqs_[i] * pow (1.008,value-64);
+ else
+ temp = center_freqs_[i] * pow (1.015,value-64);
+ t_center_freqs_[i] = temp;
+
+ coeffs_[i][0] = -resons_[i] * 2.0 * cos(temp * TWO_PI / Stk::sampleRate());
+ coeffs_[i][1] = resons_[i]*resons_[i];
+ }
+ }
+ else if (number == __SK_AfterTouch_Cont_) { // 128
+ shakeEnergy_ += norm * MAX_SHAKE * 0.1;
+ if (shakeEnergy_ > MAX_SHAKE) shakeEnergy_ = MAX_SHAKE;
+ if (instType_==10 || instType_==3) {
+ ratchetPos_ = (int) fabs(value - lastRatchetPos_);
+ ratchetDelta_ = 0.0002 * ratchetPos_;
+ lastRatchetPos_ = (int) value;
+ }
+ }
+ else if (number == __SK_ShakerInst_) { // 1071
+ instType_ = (int) (value + 0.5); // Just to be safe
+ this->setupNum(instType_);
+ }
+ else {
+ errorString_ << "Shakers::controlChange: undefined control number (" << number << ")!";
+ handleError( StkError::WARNING );
+ }
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Shakers::controlChange: number = " << number << ", value = " << value << '.';
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+// KLUDGE-O-MATIC-O-RAMA
+
+StkFloat Shakers :: wuter_tick( void ) {
+ StkFloat data;
+ int j;
+ shakeEnergy_ *= systemDecay_; // Exponential system decay
+ if (my_random(32767) < nObjects_) {
+ sndLevel_ = shakeEnergy_;
+ j = my_random(3);
+ if (j == 0) {
+ center_freqs_[0] = WUTR_CENTER_FREQ1 * (0.75 + (0.25 * noise_tick()));
+ gains_[0] = fabs(noise_tick());
+ }
+ else if (j == 1) {
+ center_freqs_[1] = WUTR_CENTER_FREQ1 * (1.0 + (0.25 * noise_tick()));
+ gains_[1] = fabs(noise_tick());
+ }
+ else {
+ center_freqs_[2] = WUTR_CENTER_FREQ1 * (1.25 + (0.25 * noise_tick()));
+ gains_[2] = fabs(noise_tick());
+ }
+ }
+
+ gains_[0] *= resons_[0];
+ if (gains_[0] > 0.001) {
+ center_freqs_[0] *= WUTR_FREQ_SWEEP;
+ coeffs_[0][0] = -resons_[0] * 2.0 *
+ cos(center_freqs_[0] * TWO_PI / Stk::sampleRate());
+ }
+ gains_[1] *= resons_[1];
+ if (gains_[1] > 0.001) {
+ center_freqs_[1] *= WUTR_FREQ_SWEEP;
+ coeffs_[1][0] = -resons_[1] * 2.0 *
+ cos(center_freqs_[1] * TWO_PI / Stk::sampleRate());
+ }
+ gains_[2] *= resons_[2];
+ if (gains_[2] > 0.001) {
+ center_freqs_[2] *= WUTR_FREQ_SWEEP;
+ coeffs_[2][0] = -resons_[2] * 2.0 *
+ cos(center_freqs_[2] * TWO_PI / Stk::sampleRate());
+ }
+
+ sndLevel_ *= soundDecay_; // Each (all) event(s)
+ // decay(s) exponentially
+ inputs_[0] = sndLevel_;
+ inputs_[0] *= noise_tick(); // Actual Sound is Random
+ inputs_[1] = inputs_[0] * gains_[1];
+ inputs_[2] = inputs_[0] * gains_[2];
+ inputs_[0] *= gains_[0];
+ inputs_[0] -= outputs_[0][0]*coeffs_[0][0];
+ inputs_[0] -= outputs_[0][1]*coeffs_[0][1];
+ outputs_[0][1] = outputs_[0][0];
+ outputs_[0][0] = inputs_[0];
+ data = gains_[0]*outputs_[0][0];
+ inputs_[1] -= outputs_[1][0]*coeffs_[1][0];
+ inputs_[1] -= outputs_[1][1]*coeffs_[1][1];
+ outputs_[1][1] = outputs_[1][0];
+ outputs_[1][0] = inputs_[1];
+ data += gains_[1]*outputs_[1][0];
+ inputs_[2] -= outputs_[2][0]*coeffs_[2][0];
+ inputs_[2] -= outputs_[2][1]*coeffs_[2][1];
+ outputs_[2][1] = outputs_[2][0];
+ outputs_[2][0] = inputs_[2];
+ data += gains_[2]*outputs_[2][0];
+
+ finalZ_[2] = finalZ_[1];
+ finalZ_[1] = finalZ_[0];
+ finalZ_[0] = data * 4;
+
+ data = finalZ_[2] - finalZ_[0];
+ return data;
+}
+
+StkFloat Shakers :: ratchet_tick( void ) {
+ StkFloat data;
+ if (my_random(1024) < nObjects_) {
+ sndLevel_ += 512 * ratchet_ * totalEnergy_;
+ }
+ inputs_[0] = sndLevel_;
+ inputs_[0] *= noise_tick() * ratchet_;
+ sndLevel_ *= soundDecay_;
+
+ inputs_[1] = inputs_[0];
+ inputs_[0] -= outputs_[0][0]*coeffs_[0][0];
+ inputs_[0] -= outputs_[0][1]*coeffs_[0][1];
+ outputs_[0][1] = outputs_[0][0];
+ outputs_[0][0] = inputs_[0];
+ inputs_[1] -= outputs_[1][0]*coeffs_[1][0];
+ inputs_[1] -= outputs_[1][1]*coeffs_[1][1];
+ outputs_[1][1] = outputs_[1][0];
+ outputs_[1][0] = inputs_[1];
+
+ finalZ_[2] = finalZ_[1];
+ finalZ_[1] = finalZ_[0];
+ finalZ_[0] = gains_[0]*outputs_[0][1] + gains_[1]*outputs_[1][1];
+ data = finalZ_[0] - finalZ_[2];
+ return data;
+}
+
+StkFloat Shakers :: tbamb_tick( void ) {
+ StkFloat data, temp;
+ static int which = 0;
+ int i;
+
+ if (shakeEnergy_ > MIN_ENERGY) {
+ shakeEnergy_ *= systemDecay_; // Exponential system decay
+ if (float_random(1024.0) < nObjects_) {
+ sndLevel_ += shakeEnergy_;
+ which = my_random(7);
+ }
+ temp = sndLevel_ * noise_tick(); // Actual Sound is Random
+ for (i=0;i<nFreqs_;i++) inputs_[i] = 0;
+ inputs_[which] = temp;
+ sndLevel_ *= soundDecay_; // Exponential Sound decay
+ finalZ_[2] = finalZ_[1];
+ finalZ_[1] = finalZ_[0];
+ finalZ_[0] = 0;
+ for (i=0;i<nFreqs_;i++) {
+ inputs_[i] -= outputs_[i][0]*coeffs_[i][0]; // Do
+ inputs_[i] -= outputs_[i][1]*coeffs_[i][1]; // resonant
+ outputs_[i][1] = outputs_[i][0]; // filter
+ outputs_[i][0] = inputs_[i]; // calculations
+ finalZ_[0] += gains_[i] * outputs_[i][1];
+ }
+ data = finalZCoeffs_[0] * finalZ_[0]; // Extra zero(s) for shape
+ data += finalZCoeffs_[1] * finalZ_[1]; // Extra zero(s) for shape
+ data += finalZCoeffs_[2] * finalZ_[2]; // Extra zero(s) for shape
+ if (data > 10000.0) data = 10000.0;
+ if (data < -10000.0) data = -10000.0;
+ data = data * 0.0001;
+ }
+ else data = 0.0;
+ return data;
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class Simple
+ \brief STK wavetable/noise instrument.
+
+ This class combines a looped wave, a
+ noise source, a biquad resonance filter,
+ a one-pole filter, and an ADSR envelope
+ to create some interesting sounds.
+
+ Control Change Numbers:
+ - Filter Pole Position = 2
+ - Noise/Pitched Cross-Fade = 4
+ - Envelope Rate = 11
+ - Gain = 128
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "Simple.h"
+#include "Skini_msg.h"
+
+namespace stk {
+
+Simple :: Simple( void )
+{
+ // Concatenate the STK rawwave path to the rawwave file
+ loop_ = new FileLoop( (Stk::rawwavePath() + "impuls10.raw").c_str(), true );
+
+ filter_.setPole( 0.5 );
+ baseFrequency_ = 440.0;
+ setFrequency( baseFrequency_ );
+ loopGain_ = 0.5;
+}
+
+Simple :: ~Simple( void )
+{
+ delete loop_;
+}
+
+void Simple :: keyOn( void )
+{
+ adsr_.keyOn();
+}
+
+void Simple :: keyOff( void )
+{
+ adsr_.keyOff();
+}
+
+void Simple :: noteOn( StkFloat frequency, StkFloat amplitude )
+{
+ this->keyOn();
+ this->setFrequency( frequency );
+ filter_.setGain( amplitude );
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Simple::NoteOn: frequency = " << frequency << ", amplitude = " << amplitude << '.';
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+void Simple :: noteOff( StkFloat amplitude )
+{
+ this->keyOff();
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Simple::NoteOff: amplitude = " << amplitude << ".";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+void Simple :: setFrequency( StkFloat frequency )
+{
+ biquad_.setResonance( frequency, 0.98, true );
+ loop_->setFrequency( frequency );
+}
+
+void Simple :: controlChange( int number, StkFloat value )
+{
+ StkFloat norm = value * ONE_OVER_128;
+ if ( norm < 0 ) {
+ norm = 0.0;
+ errorString_ << "Simple::controlChange: control value less than zero ... setting to zero!";
+ handleError( StkError::WARNING );
+ }
+ else if ( norm > 1.0 ) {
+ norm = 1.0;
+ errorString_ << "Simple::controlChange: control value greater than 128.0 ... setting to 128.0!";
+ handleError( StkError::WARNING );
+ }
+
+ if (number == __SK_Breath_) // 2
+ filter_.setPole( 0.99 * (1.0 - (norm * 2.0)) );
+ else if (number == __SK_NoiseLevel_) // 4
+ loopGain_ = norm;
+ else if (number == __SK_ModFrequency_) { // 11
+ norm /= 0.2 * Stk::sampleRate();
+ adsr_.setAttackRate( norm );
+ adsr_.setDecayRate( norm );
+ adsr_.setReleaseRate( norm );
+ }
+ else if (number == __SK_AfterTouch_Cont_) // 128
+ adsr_.setTarget( norm );
+ else {
+ errorString_ << "Simple::controlChange: undefined control number (" << number << ")!";
+ handleError( StkError::WARNING );
+ }
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Simple::controlChange: number = " << number << ", value = " << value << '.';
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class SineWave
+ \brief STK sinusoid oscillator class.
+
+ This class computes and saves a static sine "table" that can be
+ shared by multiple instances. It has an interface similar to the
+ WaveLoop class but inherits from the Generator class. Output
+ values are computed using linear interpolation.
+
+ The "table" length, set in SineWave.h, is 2048 samples by default.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "SineWave.h"
+#include <cmath>
+
+namespace stk {
+
+StkFrames SineWave :: table_;
+
+SineWave :: SineWave( void )
+ : time_(0.0), rate_(1.0), phaseOffset_(0.0)
+{
+ if ( table_.empty() ) {
+ table_.resize( TABLE_SIZE + 1, 1 );
+ StkFloat temp = 1.0 / TABLE_SIZE;
+ for ( unsigned long i=0; i<=TABLE_SIZE; i++ )
+ table_[i] = sin( TWO_PI * i * temp );
+ }
+
+ Stk::addSampleRateAlert( this );
+}
+
+SineWave :: ~SineWave()
+{
+ Stk::removeSampleRateAlert( this );
+}
+
+void SineWave :: sampleRateChanged( StkFloat newRate, StkFloat oldRate )
+{
+ if ( !ignoreSampleRateChange_ )
+ this->setRate( oldRate * rate_ / newRate );
+}
+
+void SineWave :: reset( void )
+{
+ time_ = 0.0;
+ lastFrame_[0] = 0;
+}
+
+void SineWave :: setFrequency( StkFloat frequency )
+{
+ // This is a looping frequency.
+ this->setRate( TABLE_SIZE * frequency / Stk::sampleRate() );
+}
+
+void SineWave :: addTime( StkFloat time )
+{
+ // Add an absolute time in samples.
+ time_ += time;
+}
+
+void SineWave :: addPhase( StkFloat phase )
+{
+ // Add a time in cycles (one cycle = TABLE_SIZE).
+ time_ += TABLE_SIZE * phase;
+}
+
+void SineWave :: addPhaseOffset( StkFloat phaseOffset )
+{
+ // Add a phase offset relative to any previous offset value.
+ time_ += ( phaseOffset - phaseOffset_ ) * TABLE_SIZE;
+ phaseOffset_ = phaseOffset;
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class SingWave
+ \brief STK "singing" looped soundfile class.
+
+ This class loops a specified soundfile and modulates it both
+ periodically and randomly to produce a pitched musical sound, like
+ a simple voice or violin. In general, it is not be used alone
+ because of "munchkinification" effects from pitch shifting.
+ Within STK, it is used as an excitation source for other
+ instruments.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "SingWave.h"
+
+namespace stk {
+
+SingWave :: SingWave( std::string fileName, bool raw )
+{
+ // An exception could be thrown here.
+ wave_.openFile( fileName, raw );
+
+ rate_ = 1.0;
+ sweepRate_ = 0.001;
+
+ modulator_.setVibratoRate( 6.0 );
+ modulator_.setVibratoGain( 0.04 );
+ modulator_.setRandomGain( 0.005 );
+
+ this->setFrequency( 75.0 );
+ pitchEnvelope_.setRate( 1.0 );
+ this->tick();
+ this->tick();
+ pitchEnvelope_.setRate( sweepRate_ * rate_ );
+}
+
+SingWave :: ~SingWave()
+{
+}
+
+void SingWave :: setFrequency( StkFloat frequency )
+{
+ StkFloat temp = rate_;
+ rate_ = wave_.getSize() * frequency / Stk::sampleRate();
+ temp -= rate_;
+ if ( temp < 0) temp = -temp;
+ pitchEnvelope_.setTarget( rate_ );
+ pitchEnvelope_.setRate( sweepRate_ * temp );
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class Sitar
+ \brief STK sitar string model class.
+
+ This class implements a sitar plucked string
+ physical model based on the Karplus-Strong
+ algorithm.
+
+ This is a digital waveguide model, making its
+ use possibly subject to patents held by
+ Stanford University, Yamaha, and others.
+ There exist at least two patents, assigned to
+ Stanford, bearing the names of Karplus and/or
+ Strong.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "Sitar.h"
+
+namespace stk {
+
+Sitar :: Sitar( StkFloat lowestFrequency )
+{
+ unsigned long length = (unsigned long) ( Stk::sampleRate() / lowestFrequency + 1 );
+ delayLine_.setMaximumDelay( length );
+ delay_ = 0.5 * length;
+ delayLine_.setDelay( delay_ );
+ targetDelay_ = delay_;
+
+ loopFilter_.setZero(0.01);
+ loopGain_ = 0.999;
+
+ envelope_.setAllTimes(0.001, 0.04, 0.0, 0.5);
+ this->clear();
+}
+
+Sitar :: ~Sitar( void )
+{
+}
+
+void Sitar :: clear( void )
+{
+ delayLine_.clear();
+ loopFilter_.clear();
+}
+
+void Sitar :: setFrequency( StkFloat frequency )
+{
+ StkFloat freakency = frequency;
+ if ( frequency <= 0.0 ) {
+ errorString_ << "Sitar::setFrequency: parameter is less than or equal to zero!";
+ handleError( StkError::WARNING );
+ freakency = 220.0;
+ }
+
+ targetDelay_ = (Stk::sampleRate() / freakency);
+ delay_ = targetDelay_ * (1.0 + (0.05 * noise_.tick()));
+ delayLine_.setDelay( delay_ );
+ loopGain_ = 0.995 + (freakency * 0.0000005);
+ if ( loopGain_ > 0.9995 ) loopGain_ = 0.9995;
+}
+
+void Sitar :: pluck( StkFloat amplitude )
+{
+ envelope_.keyOn();
+}
+
+void Sitar :: noteOn( StkFloat frequency, StkFloat amplitude )
+{
+ this->setFrequency( frequency );
+ this->pluck( amplitude );
+ amGain_ = 0.1 * amplitude;
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Sitar::NoteOn: frequency = " << frequency << ", amplitude = " << amplitude << ".";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+void Sitar :: noteOff( StkFloat amplitude )
+{
+ loopGain_ = (StkFloat) 1.0 - amplitude;
+ if ( loopGain_ < 0.0 ) {
+ errorString_ << "Sitar::noteOff: amplitude is greater than 1.0 ... setting to 1.0!";
+ handleError( StkError::WARNING );
+ loopGain_ = 0.0;
+ }
+ else if ( loopGain_ > 1.0 ) {
+ errorString_ << "Sitar::noteOff: amplitude is < 0.0 ... setting to 0.0!";
+ handleError( StkError::WARNING );
+ loopGain_ = 0.99999;
+ }
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Sitar::NoteOff: amplitude = " << amplitude << ".";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class Skini
+ \brief STK SKINI parsing class
+
+ This class parses SKINI formatted text
+ messages. It can be used to parse individual
+ messages or it can be passed an entire file.
+ The SKINI specification is Perry's and his
+ alone, but it's all text so it shouldn't be too
+ hard to figure out.
+
+ SKINI (Synthesis toolKit Instrument Network
+ Interface) is like MIDI, but allows for
+ floating-point control changes, note numbers,
+ etc. The following example causes a sharp
+ middle C to be played with a velocity of 111.132:
+
+ noteOn 60.01 111.132
+
+ See also SKINI.txt.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "Skini.h"
+#include "Skini_tbl.h"
+#include <cstdlib>
+
+namespace stk {
+
+Skini :: Skini()
+{
+}
+
+Skini :: ~Skini()
+{
+}
+
+bool Skini :: setFile( std::string fileName )
+{
+ if ( file_.is_open() ) {
+ errorString_ << "Skini::setFile: already reaading a file!";
+ handleError( StkError::WARNING );
+ return false;
+ }
+
+ file_.open( fileName.c_str() );
+ if ( !file_ ) {
+ errorString_ << "Skini::setFile: unable to open file (" << fileName << ")";
+ handleError( StkError::WARNING );
+ return false;
+ }
+
+ return true;
+}
+
+long Skini :: nextMessage( Message& message )
+{
+ if ( !file_.is_open() ) return 0;
+
+ std::string line;
+ bool done = false;
+ while ( !done ) {
+
+ // Read a line from the file and skip over invalid messages.
+ if ( std::getline( file_, line ).eof() ) {
+ errorString_ << "// End of Score. Thanks for using SKINI!!";
+ handleError( StkError::STATUS );
+ file_.close();
+ message.type = 0;
+ done = true;
+ }
+ else if ( parseString( line, message ) > 0 ) done = true;
+ }
+
+ return message.type;
+}
+
+void Skini :: tokenize( const std::string& str,
+ std::vector<std::string>& tokens,
+ const std::string& delimiters )
+{
+ // Skip delimiters at beginning.
+ std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
+ // Find first "non-delimiter".
+ std::string::size_type pos = str.find_first_of(delimiters, lastPos);
+
+ while (std::string::npos != pos || std::string::npos != lastPos) {
+ // Found a token, add it to the vector.
+ tokens.push_back(str.substr(lastPos, pos - lastPos));
+ // Skip delimiters. Note the "not_of"
+ lastPos = str.find_first_not_of(delimiters, pos);
+ // Find next "non-delimiter"
+ pos = str.find_first_of(delimiters, lastPos);
+ }
+}
+
+long Skini :: parseString( std::string& line, Message& message )
+{
+ message.type = 0;
+ if ( line.empty() ) return message.type;
+
+ // Check for comment lines.
+ std::string::size_type lastPos = line.find_first_not_of(" ,\t", 0);
+ std::string::size_type pos = line.find_first_of("/", lastPos);
+ if ( std::string::npos != pos ) {
+ errorString_ << "// Comment Line: " << line;
+ handleError( StkError::STATUS );
+ return message.type;
+ }
+
+ // Tokenize the string.
+ std::vector<std::string> tokens;
+ this->tokenize( line, tokens, " ,\t");
+
+ // Valid SKINI messages must have at least three fields (type, time,
+ // and channel).
+ if ( tokens.size() < 3 ) return message.type;
+
+ // Determine message type.
+ int iSkini = 0;
+ while ( iSkini < __SK_MaxMsgTypes_ ) {
+ if ( tokens[0] == skini_msgs[iSkini].messageString ) break;
+ iSkini++;
+ }
+
+ if ( iSkini >= __SK_MaxMsgTypes_ ) {
+ errorString_ << "Skini::parseString: couldn't parse this line:\n " << line;
+ handleError( StkError::WARNING );
+ return message.type;
+ }
+
+ // Found the type.
+ message.type = skini_msgs[iSkini].type;
+
+ // Parse time field.
+ if ( tokens[1][0] == '=' ) {
+ tokens[1].erase( tokens[1].begin() );
+ if ( tokens[1].empty() ) {
+ errorString_ << "Skini::parseString: couldn't parse time field in line:\n " << line;
+ handleError( StkError::WARNING );
+ return message.type = 0;
+ }
+ message.time = (StkFloat) -atof( tokens[1].c_str() );
+ }
+ else
+ message.time = (StkFloat) atof( tokens[1].c_str() );
+
+ // Parse the channel field.
+ message.channel = atoi( tokens[2].c_str() );
+
+ // Parse the remaining fields (maximum of 2 more).
+ int iValue = 0;
+ long dataType = skini_msgs[iSkini].data2;
+ while ( dataType != NOPE ) {
+
+ if ( tokens.size() <= (unsigned int) (iValue+3) ) {
+ errorString_ << "Skini::parseString: inconsistency between type table and parsed line:\n " << line;
+ handleError( StkError::WARNING );
+ return message.type = 0;
+ }
+
+ switch ( dataType ) {
+
+ case SK_INT:
+ message.intValues[iValue] = atoi( tokens[iValue+3].c_str() );
+ message.floatValues[iValue] = (StkFloat) message.intValues[iValue];
+ break;
+
+ case SK_DBL:
+ message.floatValues[iValue] = atof( tokens[iValue+3].c_str() );
+ message.intValues[iValue] = (long) message.floatValues[iValue];
+ break;
+
+ case SK_STR: // Must be the last field.
+ message.remainder = tokens[iValue+3];
+ return message.type;
+
+ default: // MIDI extension message
+ message.intValues[iValue] = dataType;
+ message.floatValues[iValue] = (StkFloat) message.intValues[iValue];
+ iValue--;
+ }
+
+ if ( ++iValue == 1 )
+ dataType = skini_msgs[iSkini].data3;
+ else
+ dataType = NOPE;
+ }
+
+ return message.type;
+}
+
+std::string Skini :: whatsThisType(long type)
+{
+ std::string typeString;
+
+ for ( int i=0; i<__SK_MaxMsgTypes_; i++ ) {
+ if ( type == skini_msgs[i].type ) {
+ typeString = skini_msgs[i].messageString;
+ break;
+ }
+ }
+ return typeString;
+}
+
+std::string Skini :: whatsThisController( long number )
+{
+ std::string controller;
+
+ for ( int i=0; i<__SK_MaxMsgTypes_; i++) {
+ if ( skini_msgs[i].type == __SK_ControlChange_ &&
+ number == skini_msgs[i].data2) {
+ controller = skini_msgs[i].messageString;
+ break;
+ }
+ }
+ return controller;
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class Socket
+ \brief STK internet socket abstract base class.
+
+ This class provides common functionality for TCP and UDP internet
+ socket server and client subclasses.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "Socket.h"
+
+namespace stk {
+
+Socket :: Socket()
+{
+ soket_ = -1;
+ port_ = -1;
+}
+
+Socket :: ~Socket()
+{
+ this->close( soket_ );
+
+#if defined(__OS_WINDOWS__)
+
+ WSACleanup();
+
+#endif
+}
+
+void Socket :: close( int socket )
+{
+ if ( !isValid( socket ) ) return;
+
+#if (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__))
+
+ ::close( socket );
+
+#elif defined(__OS_WINDOWS__)
+
+ ::closesocket( socket );
+
+#endif
+}
+
+void Socket :: setBlocking( int socket, bool enable )
+{
+ if ( !isValid( socket ) ) return;
+
+#if (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__))
+
+ int tmp = ::fcntl( socket, F_GETFL, 0 );
+ if ( tmp >= 0 )
+ tmp = ::fcntl( socket, F_SETFL, enable ? (tmp &~ O_NONBLOCK) : (tmp | O_NONBLOCK) );
+
+#elif defined(__OS_WINDOWS__)
+
+ unsigned long non_block = !enable;
+ ioctlsocket( socket, FIONBIO, &non_block );
+
+#endif
+}
+
+int Socket :: writeBuffer(int socket, const void *buffer, long bufferSize, int flags )
+{
+ if ( !isValid( socket ) ) return -1;
+ return send( socket, (const char *)buffer, bufferSize, flags );
+}
+
+int Socket :: readBuffer(int socket, void *buffer, long bufferSize, int flags )
+{
+ if ( !isValid( socket ) ) return -1;
+ return recv( socket, (char *)buffer, bufferSize, flags );
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class Sphere
+ \brief STK sphere class.
+
+ This class implements a spherical ball with
+ radius, mass, position, and velocity parameters.
+
+ by Perry R. Cook, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "Sphere.h"
+#include <cmath>
+
+namespace stk {
+
+Vector3D* Sphere::getRelativePosition( Vector3D* position )
+{
+ workingVector_.setXYZ(position->getX() - position_.getX(),
+ position->getY() - position_.getY(),
+ position->getZ() - position_.getZ());
+ return &workingVector_;
+};
+
+StkFloat Sphere::getVelocity( Vector3D* velocity )
+{
+ velocity->setXYZ( velocity_.getX(), velocity_.getY(), velocity_.getZ() );
+ return velocity_.getLength();
+};
+
+StkFloat Sphere::isInside( Vector3D *position )
+{
+ // Return directed distance from aPosition to spherical boundary ( <
+ // 0 if inside).
+ StkFloat distance;
+ Vector3D *tempVector;
+
+ tempVector = this->getRelativePosition( position );
+ distance = tempVector->getLength();
+ return distance - radius_;
+};
+
+void Sphere::addVelocity(StkFloat x, StkFloat y, StkFloat z)
+{
+ velocity_.setX(velocity_.getX() + x);
+ velocity_.setY(velocity_.getY() + y);
+ velocity_.setZ(velocity_.getZ() + z);
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class StifKarp
+ \brief STK plucked stiff string instrument.
+
+ This class implements a simple plucked string
+ algorithm (Karplus Strong) with enhancements
+ (Jaffe-Smith, Smith, and others), including
+ string stiffness and pluck position controls.
+ The stiffness is modeled with allpass filters.
+
+ This is a digital waveguide model, making its
+ use possibly subject to patents held by
+ Stanford University, Yamaha, and others.
+
+ Control Change Numbers:
+ - Pickup Position = 4
+ - String Sustain = 11
+ - String Stretch = 1
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "StifKarp.h"
+#include "Skini_msg.h"
+#include <cmath>
+
+namespace stk {
+
+StifKarp :: StifKarp( StkFloat lowestFrequency )
+{
+ length_ = (unsigned long) ( Stk::sampleRate() / lowestFrequency + 1 );
+ delayLine_.setMaximumDelay( length_ );
+ delayLine_.setDelay( 0.5 * length_ );
+ combDelay_.setMaximumDelay( length_ );
+ combDelay_.setDelay( 0.2 * length_ );
+
+ pluckAmplitude_ = 0.3;
+ pickupPosition_ = 0.4;
+ lastFrequency_ = lowestFrequency * 2.0;
+ lastLength_ = length_ * 0.5;
+ stretching_ = 0.9999;
+ baseLoopGain_ = 0.995;
+ loopGain_ = 0.999;
+
+ this->clear();
+}
+
+StifKarp :: ~StifKarp( void )
+{
+}
+
+void StifKarp :: clear( void )
+{
+ delayLine_.clear();
+ combDelay_.clear();
+ filter_.clear();
+}
+
+void StifKarp :: setFrequency( StkFloat frequency )
+{
+ lastFrequency_ = frequency;
+ if ( frequency <= 0.0 ) {
+ errorString_ << "StifKarp::setFrequency: parameter is less than or equal to zero!";
+ handleError( StkError::WARNING );
+ lastFrequency_ = 220.0;
+ }
+
+ lastLength_ = Stk::sampleRate() / lastFrequency_;
+ StkFloat delay = lastLength_ - 0.5;
+ if (delay <= 0.0)
+ delay = 0.3;
+ else if (delay > length_)
+ delay = length_;
+ delayLine_.setDelay( delay );
+
+ loopGain_ = baseLoopGain_ + (frequency * 0.000005);
+ if (loopGain_ >= 1.0) loopGain_ = 0.99999;
+
+ setStretch(stretching_);
+
+ combDelay_.setDelay( 0.5 * pickupPosition_ * lastLength_ );
+}
+
+void StifKarp :: setStretch( StkFloat stretch )
+{
+ stretching_ = stretch;
+ StkFloat coefficient;
+ StkFloat freq = lastFrequency_ * 2.0;
+ StkFloat dFreq = ( (0.5 * Stk::sampleRate()) - freq ) * 0.25;
+ StkFloat temp = 0.5 + (stretch * 0.5);
+ if (temp > 0.9999) temp = 0.9999;
+ for (int i=0; i<4; i++) {
+ coefficient = temp * temp;
+ biquad_[i].setA2( coefficient );
+ biquad_[i].setB0( coefficient );
+ biquad_[i].setB2( 1.0 );
+
+ coefficient = -2.0 * temp * cos(TWO_PI * freq / Stk::sampleRate());
+ biquad_[i].setA1( coefficient );
+ biquad_[i].setB1( coefficient );
+
+ freq += dFreq;
+ }
+}
+
+void StifKarp :: setPickupPosition( StkFloat position ) {
+ pickupPosition_ = position;
+ if ( position < 0.0 ) {
+ errorString_ << "StifKarp::setPickupPosition: parameter is less than zero ... setting to 0.0!";
+ handleError( StkError::WARNING );
+ pickupPosition_ = 0.0;
+ }
+ else if ( position > 1.0 ) {
+ errorString_ << "StifKarp::setPickupPosition: parameter is greater than 1.0 ... setting to 1.0!";
+ handleError( StkError::WARNING );
+ pickupPosition_ = 1.0;
+ }
+
+ // Set the pick position, which puts zeroes at position * length.
+ combDelay_.setDelay( 0.5 * pickupPosition_ * lastLength_ );
+}
+
+void StifKarp :: setBaseLoopGain( StkFloat aGain )
+{
+ baseLoopGain_ = aGain;
+ loopGain_ = baseLoopGain_ + (lastFrequency_ * 0.000005);
+ if ( loopGain_ > 0.99999 ) loopGain_ = (StkFloat) 0.99999;
+}
+
+void StifKarp :: pluck( StkFloat amplitude )
+{
+ StkFloat gain = amplitude;
+ if ( gain > 1.0 ) {
+ errorString_ << "StifKarp::pluck: amplitude is greater than 1.0 ... setting to 1.0!";
+ handleError( StkError::WARNING );
+ gain = 1.0;
+ }
+ else if ( gain < 0.0 ) {
+ errorString_ << "StifKarp::pluck: amplitude is less than zero ... setting to 0.0!";
+ handleError( StkError::WARNING );
+ gain = 0.0;
+ }
+
+ pluckAmplitude_ = amplitude;
+ for (unsigned long i=0; i<length_; i++) {
+ // Fill delay with noise additively with current contents.
+ delayLine_.tick( (delayLine_.lastOut() * 0.6) + 0.4 * noise_.tick() * pluckAmplitude_ );
+ //delayLine_.tick( combDelay_.tick((delayLine_.lastOut() * 0.6) + 0.4 * noise->tick() * pluckAmplitude_) );
+ }
+}
+
+void StifKarp :: noteOn( StkFloat frequency, StkFloat amplitude )
+{
+ this->setFrequency( frequency );
+ this->pluck( amplitude );
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "StifKarp::NoteOn: frequency = " << frequency << ", amplitude = " << amplitude << ".";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+void StifKarp :: noteOff( StkFloat amplitude )
+{
+ StkFloat gain = amplitude;
+ if ( gain > 1.0 ) {
+ errorString_ << "StifKarp::noteOff: amplitude is greater than 1.0 ... setting to 1.0!";
+ handleError( StkError::WARNING );
+ gain = 1.0;
+ }
+ else if ( gain < 0.0 ) {
+ errorString_ << "StifKarp::noteOff: amplitude is < 0.0 ... setting to 0.0!";
+ handleError( StkError::WARNING );
+ gain = 0.0;
+ }
+ loopGain_ = (1.0 - gain) * 0.5;
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "StifKarp::NoteOff: amplitude = " << amplitude << ".";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+void StifKarp :: controlChange( int number, StkFloat value )
+{
+ StkFloat norm = value * ONE_OVER_128;
+ if ( norm < 0 ) {
+ norm = 0.0;
+ errorString_ << "StifKarp::controlChange: control value less than zero ... setting to zero!";
+ handleError( StkError::WARNING );
+ }
+ else if ( norm > 1.0 ) {
+ norm = 1.0;
+ errorString_ << "StifKarp::controlChange: control value greater than 128.0 ... setting to 128.0!";
+ handleError( StkError::WARNING );
+ }
+
+ if (number == __SK_PickPosition_) // 4
+ this->setPickupPosition( norm );
+ else if (number == __SK_StringDamping_) // 11
+ this->setBaseLoopGain( 0.97 + (norm * 0.03) );
+ else if (number == __SK_StringDetune_) // 1
+ this->setStretch( 0.9 + (0.1 * (1.0 - norm)) );
+ else {
+ errorString_ << "StifKarp::controlChange: undefined control number (" << number << ")!";
+ handleError( StkError::WARNING );
+ }
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "StifKarp::controlChange: number = " << number << ", value = " << value << ".";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class Stk
+ \brief STK base class
+
+ Nearly all STK classes inherit from this class.
+ The global sample rate can be queried and
+ modified via Stk. In addition, this class
+ provides error handling and byte-swapping
+ functions.
+
+ The Synthesis ToolKit in C++ (STK) is a set of open source audio
+ signal processing and algorithmic synthesis classes written in the
+ C++ programming language. STK was designed to facilitate rapid
+ development of music synthesis and audio processing software, with
+ an emphasis on cross-platform functionality, realtime control,
+ ease of use, and educational example code. STK currently runs
+ with realtime support (audio and MIDI) on Linux, Macintosh OS X,
+ and Windows computer platforms. Generic, non-realtime support has
+ been tested under NeXTStep, Sun, and other platforms and should
+ work with any standard C++ compiler.
+
+ STK WWW site: http://ccrma.stanford.edu/software/stk/
+
+ The Synthesis ToolKit in C++ (STK)
+ Copyright (c) 1995-2010 Perry R. Cook and Gary P. Scavone
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation files
+ (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ Any person wishing to distribute modifications to the Software is
+ asked to send the modifications to the original developer so that
+ they can be incorporated into the canonical version. This is,
+ however, not a binding provision of this license.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+/***************************************************/
+
+#include "Stk.h"
+
+namespace stk {
+
+StkFloat Stk :: srate_ = (StkFloat) SRATE;
+const Stk::StkFormat Stk :: STK_SINT8 = 0x1;
+const Stk::StkFormat Stk :: STK_SINT16 = 0x2;
+const Stk::StkFormat Stk :: STK_SINT24 = 0x4;
+const Stk::StkFormat Stk :: STK_SINT32 = 0x8;
+const Stk::StkFormat Stk :: STK_FLOAT32 = 0x10;
+const Stk::StkFormat Stk :: STK_FLOAT64 = 0x20;
+bool Stk :: showWarnings_ = true;
+bool Stk :: printErrors_ = true;
+std::vector<Stk *> Stk :: alertList_;
+
+std::string Stk::rawwavepath_ = "";
+
+
+
+Stk :: Stk( void )
+ : ignoreSampleRateChange_(false)
+{
+ std::string path([[[NSBundle mainBundle] resourcePath] UTF8String]);
+ setRawwavePath( path );
+ //std::cout<<(rawwavepath_)<<std::endl;
+}
+
+Stk :: ~Stk( void )
+{
+}
+
+void Stk :: setSampleRate( StkFloat rate )
+{
+ if ( rate > 0.0 && rate != srate_ ) {
+ StkFloat oldRate = srate_;
+ srate_ = rate;
+
+ for ( unsigned int i=0; i<alertList_.size(); i++ )
+ alertList_[i]->sampleRateChanged( srate_, oldRate );
+ }
+}
+
+void Stk :: sampleRateChanged( StkFloat newRate, StkFloat oldRate )
+{
+ // This function should be reimplemented in classes that need to
+ // make internal variable adjustments in response to a global sample
+ // rate change.
+}
+
+void Stk :: addSampleRateAlert( Stk *ptr )
+{
+ for ( unsigned int i=0; i<alertList_.size(); i++ )
+ if ( alertList_[i] == ptr ) return;
+
+ alertList_.push_back( ptr );
+}
+
+void Stk :: removeSampleRateAlert( Stk *ptr )
+{
+ for ( unsigned int i=0; i<alertList_.size(); i++ ) {
+ if ( alertList_[i] == ptr ) {
+ alertList_.erase( alertList_.begin() + i );
+ return;
+ }
+ }
+}
+
+void Stk :: setRawwavePath( std::string path )
+{
+ if ( !path.empty() )
+ rawwavepath_ = path;
+
+ // Make sure the path includes a "/"
+ if ( rawwavepath_[rawwavepath_.length()-1] != '/' )
+ rawwavepath_ += "/";
+}
+
+void Stk :: swap16(unsigned char *ptr)
+{
+ register unsigned char val;
+
+ // Swap 1st and 2nd bytes
+ val = *(ptr);
+ *(ptr) = *(ptr+1);
+ *(ptr+1) = val;
+}
+
+void Stk :: swap32(unsigned char *ptr)
+{
+ register unsigned char val;
+
+ // Swap 1st and 4th bytes
+ val = *(ptr);
+ *(ptr) = *(ptr+3);
+ *(ptr+3) = val;
+
+ //Swap 2nd and 3rd bytes
+ ptr += 1;
+ val = *(ptr);
+ *(ptr) = *(ptr+1);
+ *(ptr+1) = val;
+}
+
+void Stk :: swap64(unsigned char *ptr)
+{
+ register unsigned char val;
+
+ // Swap 1st and 8th bytes
+ val = *(ptr);
+ *(ptr) = *(ptr+7);
+ *(ptr+7) = val;
+
+ // Swap 2nd and 7th bytes
+ ptr += 1;
+ val = *(ptr);
+ *(ptr) = *(ptr+5);
+ *(ptr+5) = val;
+
+ // Swap 3rd and 6th bytes
+ ptr += 1;
+ val = *(ptr);
+ *(ptr) = *(ptr+3);
+ *(ptr+3) = val;
+
+ // Swap 4th and 5th bytes
+ ptr += 1;
+ val = *(ptr);
+ *(ptr) = *(ptr+1);
+ *(ptr+1) = val;
+}
+
+#if (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__))
+ #include <unistd.h>
+#elif defined(__OS_WINDOWS__)
+ #include <windows.h>
+#endif
+
+void Stk :: sleep(unsigned long milliseconds)
+{
+#if defined(__OS_WINDOWS__)
+ Sleep((DWORD) milliseconds);
+#elif (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__))
+ usleep( (unsigned long) (milliseconds * 1000.0) );
+#endif
+}
+
+void Stk :: handleError( StkError::Type type )
+{
+ handleError( errorString_.str(), type );
+ errorString_.str( std::string() ); // reset the ostringstream buffer
+}
+
+void Stk :: handleError( const char *message, StkError::Type type )
+{
+ std::string msg( message );
+ handleError( msg, type );
+}
+
+void Stk :: handleError( std::string message, StkError::Type type )
+{
+ if ( type == StkError::WARNING || type == StkError::STATUS ) {
+ if ( !showWarnings_ ) return;
+ std::cerr << '\n' << message << '\n' << std::endl;
+ }
+ else if (type == StkError::DEBUG_WARNING) {
+#if defined(_STK_DEBUG_)
+ std::cerr << '\n' << message << '\n' << std::endl;
+#endif
+ }
+ else {
+ if ( printErrors_ ) {
+ // Print error message before throwing.
+ std::cerr << '\n' << message << '\n' << std::endl;
+ }
+ throw StkError(message, type);
+ }
+}
+
+//
+// StkFrames definitions
+//
+
+StkFrames :: StkFrames( unsigned int nFrames, unsigned int nChannels )
+ : nFrames_( nFrames ), nChannels_( nChannels )
+{
+ size_ = nFrames_ * nChannels_;
+ bufferSize_ = size_;
+
+ if ( size_ > 0 ) {
+ data_ = (StkFloat *) calloc( size_, sizeof( StkFloat ) );
+#if defined(_STK_DEBUG_)
+ if ( data_ == NULL ) {
+ std::string error = "StkFrames: memory allocation error in constructor!";
+ Stk::handleError( error, StkError::MEMORY_ALLOCATION );
+ }
+#endif
+ }
+ else data_ = 0;
+
+ dataRate_ = Stk::sampleRate();
+}
+
+StkFrames :: StkFrames( const StkFloat& value, unsigned int nFrames, unsigned int nChannels )
+ : nFrames_( nFrames ), nChannels_( nChannels )
+{
+ size_ = nFrames_ * nChannels_;
+ bufferSize_ = size_;
+ if ( size_ > 0 ) {
+ data_ = (StkFloat *) malloc( size_ * sizeof( StkFloat ) );
+#if defined(_STK_DEBUG_)
+ if ( data_ == NULL ) {
+ std::string error = "StkFrames: memory allocation error in constructor!";
+ Stk::handleError( error, StkError::MEMORY_ALLOCATION );
+ }
+#endif
+ for ( long i=0; i<(long)size_; i++ ) data_[i] = value;
+ }
+ else data_ = 0;
+
+ dataRate_ = Stk::sampleRate();
+}
+
+StkFrames :: ~StkFrames()
+{
+ if ( data_ ) free( data_ );
+}
+
+StkFrames :: StkFrames( const StkFrames& f )
+ : size_(0), bufferSize_(0)
+{
+ resize( f.frames(), f.channels() );
+ dataRate_ = Stk::sampleRate();
+ for ( unsigned int i=0; i<size_; i++ ) data_[i] = f[i];
+}
+
+StkFrames& StkFrames :: operator= ( const StkFrames& f )
+{
+ size_ = 0;
+ bufferSize_ = 0;
+ resize( f.frames(), f.channels() );
+ dataRate_ = Stk::sampleRate();
+ for ( unsigned int i=0; i<size_; i++ ) data_[i] = f[i];
+ return *this;
+}
+
+void StkFrames :: resize( size_t nFrames, unsigned int nChannels )
+{
+ nFrames_ = nFrames;
+ nChannels_ = nChannels;
+
+ size_ = nFrames_ * nChannels_;
+ if ( size_ > bufferSize_ ) {
+ if ( data_ ) free( data_ );
+ data_ = (StkFloat *) malloc( size_ * sizeof( StkFloat ) );
+#if defined(_STK_DEBUG_)
+ if ( data_ == NULL ) {
+ std::string error = "StkFrames::resize: memory allocation error!";
+ Stk::handleError( error, StkError::MEMORY_ALLOCATION );
+ }
+#endif
+ bufferSize_ = size_;
+ }
+}
+
+void StkFrames :: resize( size_t nFrames, unsigned int nChannels, StkFloat value )
+{
+ this->resize( nFrames, nChannels );
+
+ for ( size_t i=0; i<size_; i++ ) data_[i] = value;
+}
+
+StkFloat StkFrames :: interpolate( StkFloat frame, unsigned int channel ) const
+{
+#if defined(_STK_DEBUG_)
+ if ( frame < 0.0 || frame > (StkFloat) ( nFrames_ - 1 ) || channel >= nChannels_ ) {
+ std::ostringstream error;
+ error << "StkFrames::interpolate: invalid frame (" << frame << ") or channel (" << channel << ") value!";
+ Stk::handleError( error.str(), StkError::MEMORY_ACCESS );
+ }
+#endif
+
+ size_t iIndex = ( size_t ) frame; // integer part of index
+ StkFloat output, alpha = frame - (StkFloat) iIndex; // fractional part of index
+
+ iIndex = iIndex * nChannels_ + channel;
+ output = data_[ iIndex ];
+ if ( alpha > 0.0 )
+ output += ( alpha * ( data_[ iIndex + nChannels_ ] - output ) );
+
+ return output;
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class UdpSocket
+ \brief STK UDP socket server/client class.
+
+ This class provides a uniform cross-platform UDP socket
+ server/client interface. Methods are provided for reading or
+ writing data buffers. The constructor creates a UDP socket and
+ binds it to the specified port. Note that only one socket can be
+ bound to a given port on the same machine.
+
+ UDP sockets provide unreliable, connection-less service. Messages
+ can be lost, duplicated, or received out of order. That said,
+ data transmission tends to be faster than with TCP connections and
+ datagrams are not potentially combined by the underlying system.
+
+ The user is responsible for checking the values returned by the
+ read/write methods. Values less than or equal to zero indicate
+ the occurence of an error.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "StkUdpSocket.h"
+#include <cstring>
+
+namespace stk {
+
+StkUdpSocket :: StkUdpSocket(int port )
+{
+ validAddress_ = false;
+
+#if defined(__OS_WINDOWS__) // windoze-only stuff
+ WSADATA wsaData;
+ WORD wVersionRequested = MAKEWORD(1,1);
+
+ WSAStartup(wVersionRequested, &wsaData);
+ if (wsaData.wVersion != wVersionRequested) {
+ errorString_ << "UdpSocket: Incompatible Windows socket library version!";
+ handleError( StkError::PROCESS_SOCKET );
+ }
+#endif
+
+ // Create the UDP socket
+ soket_ = ::socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
+ if ( soket_ < 0 ) {
+ errorString_ << "UdpSocket: Couldn't create UDP socket!";
+ handleError( StkError::PROCESS_SOCKET );
+ }
+
+ struct sockaddr_in address;
+ address.sin_family = AF_INET;
+ address.sin_addr.s_addr = INADDR_ANY;
+ address.sin_port = htons( port );
+
+ // Bind socket to the appropriate port and interface (INADDR_ANY)
+ if ( bind(soket_, (struct sockaddr *)&address, sizeof(address)) < 0 ) {
+ errorString_ << "UdpSocket: Couldn't bind socket in constructor!";
+ handleError( StkError::PROCESS_SOCKET );
+ }
+
+ port_ = port;
+}
+
+StkUdpSocket :: ~StkUdpSocket()
+{
+}
+
+void StkUdpSocket :: setDestination( int port, std::string hostname )
+{
+ this->setAddress( &address_, port, hostname );
+ validAddress_ = true;
+}
+
+void StkUdpSocket :: setAddress( struct sockaddr_in *address, int port, std::string hostname )
+{
+ struct hostent *hostp;
+ if ( (hostp = gethostbyname( hostname.c_str() )) == 0 ) {
+ errorString_ << "UdpSocket::setAddress: unknown host (" << hostname << ")!";
+ handleError( StkError::PROCESS_SOCKET_IPADDR );
+ }
+
+ // Fill in the address structure
+ address->sin_family = AF_INET;
+ memcpy((void *)&address->sin_addr, hostp->h_addr, hostp->h_length);
+ address->sin_port = htons( port );
+}
+
+int StkUdpSocket :: writeBuffer( const void *buffer, long bufferSize, int flags )
+{
+ if ( !isValid( soket_ ) || !validAddress_ ) return -1;
+ return sendto( soket_, (const char *)buffer, bufferSize, flags, (struct sockaddr *)&address_, sizeof(address_) );
+}
+
+int StkUdpSocket :: readBuffer( void *buffer, long bufferSize, int flags )
+{
+ if ( !isValid( soket_ ) ) return -1;
+ return recvfrom( soket_, (char *)buffer, bufferSize, flags, NULL, NULL );
+}
+
+int StkUdpSocket :: writeBufferTo( const void *buffer, long bufferSize, int port, std::string hostname, int flags )
+{
+ if ( !isValid( soket_ ) ) return -1;
+ struct sockaddr_in address;
+ this->setAddress( &address, port, hostname );
+ return sendto( soket_, (const char *)buffer, bufferSize, flags, (struct sockaddr *)&address, sizeof(address) );
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class TapDelay
+ \brief STK non-interpolating tapped delay line class.
+
+ This class implements a non-interpolating digital delay-line with
+ an arbitrary number of output "taps". If the maximum length and
+ tap delays are not specified during instantiation, a fixed maximum
+ length of 4095 and a single tap delay of zero is set.
+
+ A non-interpolating delay line is typically used in fixed
+ delay-length applications, such as for reverberation.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "TapDelay.h"
+
+namespace stk {
+
+TapDelay :: TapDelay( std::vector<unsigned long> taps, unsigned long maxDelay )
+{
+ // Writing before reading allows delays from 0 to length-1.
+ // If we want to allow a delay of maxDelay, we need a
+ // delayline of length = maxDelay+1.
+ if ( maxDelay < 1 ) {
+ errorString_ << "TapDelay::TapDelay: maxDelay must be > 0!\n";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+
+ for ( unsigned int i=0; i<taps.size(); i++ ) {
+ if ( taps[i] > maxDelay ) {
+ errorString_ << "TapDelay::TapDelay: maxDelay must be > than all tap delay values!\n";
+ handleError( StkError::FUNCTION_ARGUMENT );
+ }
+ }
+
+ if ( ( maxDelay + 1 ) > inputs_.size() )
+ inputs_.resize( maxDelay + 1, 1, 0.0 );
+
+ inPoint_ = 0;
+ this->setTapDelays( taps );
+}
+
+TapDelay :: ~TapDelay()
+{
+}
+
+void TapDelay :: setMaximumDelay( unsigned long delay )
+{
+ if ( delay < inputs_.size() ) return;
+
+ if ( delay < 0 ) {
+ errorString_ << "TapDelay::setMaximumDelay: argument (" << delay << ") less than zero!\n";
+ handleError( StkError::WARNING );
+ return;
+ }
+
+ for ( unsigned int i=0; i<delays_.size(); i++ ) {
+ if ( delay < delays_[i] ) {
+ errorString_ << "TapDelay::setMaximumDelay: argument (" << delay << ") less than a current tap delay setting (" << delays_[i] << ")!\n";
+ handleError( StkError::WARNING );
+ return;
+ }
+ }
+
+ inputs_.resize( delay + 1 );
+}
+
+void TapDelay :: setTapDelays( std::vector<unsigned long> taps )
+{
+ if ( taps.size() != outPoint_.size() ) {
+ outPoint_.resize( taps.size() );
+ delays_.resize( taps.size() );
+ lastFrame_.resize( 1, taps.size(), 0.0 );
+ }
+
+ for ( unsigned int i=0; i<taps.size(); i++ ) {
+ if ( taps[i] > inputs_.size() - 1 ) { // The value is too big.
+ errorString_ << "TapDelay::setTapDelay: argument (" << taps[i] << ") too big ... setting to maximum!\n";
+ handleError( StkError::WARNING );
+
+ // Force delay to maximum length.
+ outPoint_[i] = inPoint_ + 1;
+ if ( outPoint_[i] == inputs_.size() ) outPoint_[i] = 0;
+ delays_[i] = inputs_.size() - 1;
+ }
+ else if ( taps[i] < 0 ) {
+ errorString_ << "TapDelay::setDelay: argument (" << taps[i] << ") less than zero ... setting to zero!\n";
+ handleError( StkError::WARNING );
+
+ outPoint_[i] = inPoint_;
+ delays_[i] = 0;
+ }
+ else { // read chases write
+ if ( inPoint_ >= taps[i] ) outPoint_[i] = inPoint_ - taps[i];
+ else outPoint_[i] = inputs_.size() + inPoint_ - taps[i];
+ delays_[i] = taps[i];
+ }
+ }
+}
+
+} // stk namespace
+
--- /dev/null
+/***************************************************/
+/*! \class TcpClient
+ \brief STK TCP socket client class.
+
+ This class provides a uniform cross-platform TCP socket client
+ interface. Methods are provided for reading or writing data
+ buffers to/from connections.
+
+ TCP sockets are reliable and connection-oriented. A TCP socket
+ client must be connected to a TCP server before data can be sent
+ or received. Data delivery is guaranteed in order, without loss,
+ error, or duplication. That said, TCP transmissions tend to be
+ slower than those using the UDP protocol and data sent with
+ multiple \e write() calls can be arbitrarily combined by the
+ underlying system.
+
+ The user is responsible for checking the values
+ returned by the read/write methods. Values
+ less than or equal to zero indicate a closed
+ or lost connection or the occurence of an error.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "TcpClient.h"
+#include <cstring>
+
+namespace stk {
+
+TcpClient :: TcpClient( int port, std::string hostname )
+{
+#if defined(__OS_WINDOWS__) // windoze-only stuff
+ WSADATA wsaData;
+ WORD wVersionRequested = MAKEWORD(1,1);
+
+ WSAStartup( wVersionRequested, &wsaData );
+ if ( wsaData.wVersion != wVersionRequested ) {
+ errorString_ << "TcpClient: Incompatible Windows socket library version!";
+ handleError( StkError::PROCESS_SOCKET );
+ }
+#endif
+
+ // Create a socket client connection.
+ connect( port, hostname );
+}
+
+TcpClient :: ~TcpClient( void )
+{
+}
+
+int TcpClient :: connect( int port, std::string hostname )
+{
+ // Close any existing connections.
+ this->close( soket_ );
+
+ // Create the client-side socket
+ soket_ = ::socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
+ if ( soket_ < 0 ) {
+ errorString_ << "TcpClient: Couldn't create socket client!";
+ handleError( StkError::PROCESS_SOCKET );
+ }
+
+ int flag = 1;
+ int result = setsockopt( soket_, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int) );
+ if ( result < 0 ) {
+ errorString_ << "TcpClient: Error setting socket options!";
+ handleError( StkError::PROCESS_SOCKET );
+ }
+
+ struct hostent *hostp;
+ if ( ( hostp = gethostbyname( hostname.c_str() ) ) == 0 ) {
+ errorString_ << "TcpClient: unknown host (" << hostname << ")!";
+ handleError( StkError::PROCESS_SOCKET_IPADDR );
+ }
+
+ // Fill in the address structure
+ struct sockaddr_in server_address;
+ server_address.sin_family = AF_INET;
+ memcpy( (void *)&server_address.sin_addr, hostp->h_addr, hostp->h_length );
+ server_address.sin_port = htons(port);
+
+ // Connect to the server
+ if ( ::connect( soket_, (struct sockaddr *)&server_address, sizeof(server_address) ) < 0 ) {
+ errorString_ << "TcpClient: Couldn't connect to socket server!";
+ handleError( StkError::PROCESS_SOCKET );
+ }
+
+ return soket_;
+}
+
+int TcpClient :: writeBuffer( const void *buffer, long bufferSize, int flags )
+{
+ if ( !isValid( soket_ ) ) return -1;
+ return send( soket_, (const char *)buffer, bufferSize, flags );
+}
+
+int TcpClient :: readBuffer( void *buffer, long bufferSize, int flags )
+{
+ if ( !isValid( soket_ ) ) return -1;
+ return recv( soket_, (char *)buffer, bufferSize, flags );
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class TcpServer
+ \brief STK TCP socket server class.
+
+ This class provides a uniform cross-platform TCP socket server
+ interface. Methods are provided for reading or writing data
+ buffers to/from connections.
+
+ TCP sockets are reliable and connection-oriented. A TCP socket
+ server must accept a connection from a TCP client before data can
+ be sent or received. Data delivery is guaranteed in order,
+ without loss, error, or duplication. That said, TCP transmissions
+ tend to be slower than those using the UDP protocol and data sent
+ with multiple \e write() calls can be arbitrarily combined by the
+ underlying system.
+
+ The user is responsible for checking the values
+ returned by the read/write methods. Values
+ less than or equal to zero indicate a closed
+ or lost connection or the occurence of an error.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "TcpServer.h"
+
+namespace stk {
+
+TcpServer :: TcpServer( int port )
+{
+ // Create a socket server.
+#if defined(__OS_WINDOWS__) // windoze-only stuff
+ WSADATA wsaData;
+ WORD wVersionRequested = MAKEWORD(1,1);
+
+ WSAStartup(wVersionRequested, &wsaData);
+ if (wsaData.wVersion != wVersionRequested) {
+ errorString_ << "TcpServer: Incompatible Windows socket library version!";
+ handleError( StkError::PROCESS_SOCKET );
+ }
+#endif
+
+ // Create the server-side socket
+ soket_ = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (soket_ < 0) {
+ errorString_ << "TcpServer: Couldn't create socket server!";
+ handleError( StkError::PROCESS_SOCKET );
+ }
+
+ int flag = 1;
+ int result = setsockopt( soket_, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int) );
+ if (result < 0) {
+ errorString_ << "TcpServer: Error setting socket options!";
+ handleError( StkError::PROCESS_SOCKET );
+ }
+
+ struct sockaddr_in address;
+ address.sin_family = AF_INET;
+ address.sin_addr.s_addr = INADDR_ANY;
+ address.sin_port = htons( port );
+
+ // Bind socket to the appropriate port and interface (INADDR_ANY)
+ if ( bind( soket_, (struct sockaddr *)&address, sizeof(address) ) < 0 ) {
+ errorString_ << "TcpServer: Couldn't bind socket!";
+ handleError( StkError::PROCESS_SOCKET );
+ }
+
+ // Listen for incoming connection(s)
+ if ( listen( soket_, 1 ) < 0 ) {
+ errorString_ << "TcpServer: Couldn't start server listening!";
+ handleError( StkError::PROCESS_SOCKET );
+ }
+
+ port_ = port;
+}
+
+TcpServer :: ~TcpServer()
+{
+}
+
+int TcpServer :: accept( void )
+{
+ return ::accept( soket_, NULL, NULL );
+}
+
+int TcpServer :: writeBuffer(const void *buffer, long bufferSize, int flags )
+{
+ if ( !isValid( soket_ ) ) return -1;
+ return send( soket_, (const char *)buffer, bufferSize, flags );
+}
+
+int TcpServer :: readBuffer(void *buffer, long bufferSize, int flags )
+{
+ if ( !isValid( soket_ ) ) return -1;
+ return recv( soket_, (char *)buffer, bufferSize, flags );
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class Thread
+ \brief STK thread class.
+
+ This class provides a uniform interface for cross-platform
+ threads. On unix systems, the pthread library is used. Under
+ Windows, the C runtime threadex functions are used.
+
+ Each instance of the Thread class can be used to control a single
+ thread process. Routines are provided to signal cancelation
+ and/or joining with a thread, though it is not possible for this
+ class to know the running status of a thread once it is started.
+
+ For cross-platform compatability, thread functions should be
+ declared as follows:
+
+ THREAD_RETURN THREAD_TYPE thread_function(void *ptr)
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "Thread.h"
+
+namespace stk {
+
+Thread :: Thread()
+{
+ thread_ = 0;
+}
+
+Thread :: ~Thread()
+{
+}
+
+bool Thread :: start( THREAD_FUNCTION routine, void * ptr )
+{
+ if ( thread_ ) {
+ errorString_ << "Thread:: a thread is already running!";
+ handleError( StkError::WARNING );
+ return false;
+ }
+
+#if (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__))
+
+ if ( pthread_create(&thread_, NULL, *routine, ptr) == 0 )
+ return true;
+
+#elif defined(__OS_WINDOWS__)
+ unsigned thread_id;
+ thread_ = _beginthreadex(NULL, 0, routine, ptr, 0, &thread_id);
+ if ( thread_ ) return true;
+
+#endif
+ return false;
+}
+
+bool Thread :: cancel()
+{
+#if (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__))
+
+ if ( pthread_cancel(thread_) == 0 ) {
+ return true;
+ }
+
+#elif defined(__OS_WINDOWS__)
+
+ TerminateThread((HANDLE)thread_, 0);
+ return true;
+
+#endif
+ return false;
+}
+
+bool Thread :: wait()
+{
+#if (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__))
+
+ if ( pthread_join(thread_, NULL) == 0 ) {
+ thread_ = 0;
+ return true;
+ }
+
+#elif defined(__OS_WINDOWS__)
+
+ long retval = WaitForSingleObject( (HANDLE)thread_, INFINITE );
+ if ( retval == WAIT_OBJECT_0 ) {
+ CloseHandle( (HANDLE)thread_ );
+ thread_ = 0;
+ return true;
+ }
+
+#endif
+ return false;
+}
+
+void Thread :: testCancel(void)
+{
+#if (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__))
+
+ pthread_testcancel();
+
+#endif
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class TubeBell
+ \brief STK tubular bell (orchestral chime) FM
+ synthesis instrument.
+
+ This class implements two simple FM Pairs
+ summed together, also referred to as algorithm
+ 5 of the TX81Z.
+
+ \code
+ Algorithm 5 is : 4->3--\
+ + --> Out
+ 2->1--/
+ \endcode
+
+ Control Change Numbers:
+ - Modulator Index One = 2
+ - Crossfade of Outputs = 4
+ - LFO Speed = 11
+ - LFO Depth = 1
+ - ADSR 2 & 4 Target = 128
+
+ The basic Chowning/Stanford FM patent expired
+ in 1995, but there exist follow-on patents,
+ mostly assigned to Yamaha. If you are of the
+ type who should worry about this (making
+ money) worry away.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "TubeBell.h"
+
+namespace stk {
+
+TubeBell :: TubeBell( void )
+ : FM()
+{
+ // Concatenate the STK rawwave path to the rawwave files
+ for ( unsigned int i=0; i<3; i++ )
+ waves_[i] = new FileLoop( (Stk::rawwavePath() + "sinewave.raw").c_str(), true );
+ waves_[3] = new FileLoop( (Stk::rawwavePath() + "fwavblnk.raw").c_str(), true );
+
+ this->setRatio(0, 1.0 * 0.995);
+ this->setRatio(1, 1.414 * 0.995);
+ this->setRatio(2, 1.0 * 1.005);
+ this->setRatio(3, 1.414 * 1.000);
+
+ gains_[0] = fmGains_[94];
+ gains_[1] = fmGains_[76];
+ gains_[2] = fmGains_[99];
+ gains_[3] = fmGains_[71];
+
+ adsr_[0]->setAllTimes( 0.005, 4.0, 0.0, 0.04);
+ adsr_[1]->setAllTimes( 0.005, 4.0, 0.0, 0.04);
+ adsr_[2]->setAllTimes( 0.001, 2.0, 0.0, 0.04);
+ adsr_[3]->setAllTimes( 0.004, 4.0, 0.0, 0.04);
+
+ twozero_.setGain( 0.5 );
+ vibrato_.setFrequency( 2.0 );
+}
+
+TubeBell :: ~TubeBell( void )
+{
+}
+
+void TubeBell :: noteOn( StkFloat frequency, StkFloat amplitude )
+{
+ gains_[0] = amplitude * fmGains_[94];
+ gains_[1] = amplitude * fmGains_[76];
+ gains_[2] = amplitude * fmGains_[99];
+ gains_[3] = amplitude * fmGains_[71];
+ this->setFrequency( frequency );
+ this->keyOn();
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "TubeBell::NoteOn: frequency = " << frequency << ", amplitude = " << amplitude << '.';
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class TwoPole
+ \brief STK two-pole filter class.
+
+ This class implements a two-pole digital filter. A method is
+ provided for creating a resonance in the frequency response while
+ maintaining a nearly constant filter gain.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "TwoPole.h"
+#include <cmath>
+
+namespace stk {
+
+TwoPole :: TwoPole( void )
+{
+ b_.resize( 1 );
+ a_.resize( 3 );
+ inputs_.resize( 1, 1, 0.0 );
+ outputs_.resize( 3, 1, 0.0 );
+ b_[0] = 1.0;
+ a_[0] = 1.0;
+
+ Stk::addSampleRateAlert( this );
+}
+
+TwoPole :: ~TwoPole()
+{
+ Stk::removeSampleRateAlert( this );
+}
+
+void TwoPole :: sampleRateChanged( StkFloat newRate, StkFloat oldRate )
+{
+ if ( !ignoreSampleRateChange_ ) {
+ errorString_ << "TwoPole::sampleRateChanged: you may need to recompute filter coefficients!";
+ handleError( StkError::WARNING );
+ }
+}
+
+void TwoPole :: setResonance( StkFloat frequency, StkFloat radius, bool normalize )
+{
+ a_[2] = radius * radius;
+ a_[1] = (StkFloat) -2.0 * radius * cos(TWO_PI * frequency / Stk::sampleRate());
+
+ if ( normalize ) {
+ // Normalize the filter gain ... not terribly efficient.
+ StkFloat real = 1 - radius + (a_[2] - radius) * cos(TWO_PI * 2 * frequency / Stk::sampleRate());
+ StkFloat imag = (a_[2] - radius) * sin(TWO_PI * 2 * frequency / Stk::sampleRate());
+ b_[0] = sqrt( pow(real, 2) + pow(imag, 2) );
+ }
+}
+
+void TwoPole :: setCoefficients( StkFloat b0, StkFloat a1, StkFloat a2, bool clearState )
+{
+ b_[0] = b0;
+ a_[1] = a1;
+ a_[2] = a2;
+
+ if ( clearState ) this->clear();
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class TwoZero
+ \brief STK two-zero filter class.
+
+ This class implements a two-zero digital filter. A method is
+ provided for creating a "notch" in the frequency response while
+ maintaining a constant filter gain.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "TwoZero.h"
+#include <cmath>
+
+namespace stk {
+
+TwoZero :: TwoZero( void )
+{
+ b_.resize( 3, 0.0 );
+ inputs_.resize( 3, 1, 0.0 );
+ b_[0] = 1.0;
+
+ Stk::addSampleRateAlert( this );
+}
+
+TwoZero :: ~TwoZero()
+{
+ Stk::removeSampleRateAlert( this );
+}
+
+void TwoZero :: sampleRateChanged( StkFloat newRate, StkFloat oldRate )
+{
+ if ( !ignoreSampleRateChange_ ) {
+ errorString_ << "TwoZero::sampleRateChanged: you may need to recompute filter coefficients!";
+ handleError( StkError::WARNING );
+ }
+}
+
+void TwoZero :: setCoefficients( StkFloat b0, StkFloat b1, StkFloat b2, bool clearState )
+{
+ b_[0] = b0;
+ b_[1] = b1;
+ b_[2] = b2;
+
+ if ( clearState ) this->clear();
+}
+
+void TwoZero :: setNotch( StkFloat frequency, StkFloat radius )
+{
+ b_[2] = radius * radius;
+ b_[1] = (StkFloat) -2.0 * radius * cos(TWO_PI * (double) frequency / Stk::sampleRate());
+
+ // Normalize the filter gain.
+ if ( b_[1] > 0.0 ) // Maximum at z = 0.
+ b_[0] = 1.0 / ( 1.0 + b_[1] + b_[2] );
+ else // Maximum at z = -1.
+ b_[0] = 1.0 / ( 1.0 - b_[1] + b_[2] );
+ b_[1] *= b_[0];
+ b_[2] *= b_[0];
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class VoicForm
+ \brief Four formant synthesis instrument.
+
+ This instrument contains an excitation singing
+ wavetable (looping wave with random and
+ periodic vibrato, smoothing on frequency,
+ etc.), excitation noise, and four sweepable
+ complex resonances.
+
+ Measured formant data is included, and enough
+ data is there to support either parallel or
+ cascade synthesis. In the floating point case
+ cascade synthesis is the most natural so
+ that's what you'll find here.
+
+ Control Change Numbers:
+ - Voiced/Unvoiced Mix = 2
+ - Vowel/Phoneme Selection = 4
+ - Vibrato Frequency = 11
+ - Vibrato Gain = 1
+ - Loudness (Spectral Tilt) = 128
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "VoicForm.h"
+#include "Phonemes.h"
+#include "Skini_msg.h"
+#include <cstring>
+#include <cmath>
+
+namespace stk {
+
+VoicForm :: VoicForm( void ) : Instrmnt()
+{
+ // Concatenate the STK rawwave path to the rawwave file
+ voiced_ = new SingWave( (Stk::rawwavePath() + "impuls20.raw").c_str(), true );
+ voiced_->setGainRate( 0.001 );
+ voiced_->setGainTarget( 0.0 );
+
+ for ( int i=0; i<4; i++ )
+ filters_[i].setSweepRate( 0.001 );
+
+ onezero_.setZero( -0.9 );
+ onepole_.setPole( 0.9 );
+
+ noiseEnv_.setRate( 0.001 );
+ noiseEnv_.setTarget( 0.0 );
+
+ this->setPhoneme( "eee" );
+ this->clear();
+}
+
+VoicForm :: ~VoicForm( void )
+{
+ delete voiced_;
+}
+
+void VoicForm :: clear( void )
+{
+ onezero_.clear();
+ onepole_.clear();
+ for ( int i=0; i<4; i++ ) {
+ filters_[i].clear();
+ }
+}
+
+void VoicForm :: setFrequency( StkFloat frequency )
+{
+ StkFloat freakency = frequency;
+ if ( frequency <= 0.0 ) {
+ errorString_ << "VoicForm::setFrequency: parameter is less than or equal to zero!";
+ handleError( StkError::WARNING );
+ freakency = 220.0;
+ }
+
+ voiced_->setFrequency( freakency );
+}
+
+bool VoicForm :: setPhoneme( const char *phoneme )
+{
+ bool found = false;
+ unsigned int i = 0;
+ while( i < 32 && !found ) {
+ if ( !strcmp( Phonemes::name(i), phoneme ) ) {
+ found = true;
+ filters_[0].setTargets( Phonemes::formantFrequency(i, 0), Phonemes::formantRadius(i, 0), pow(10.0, Phonemes::formantGain(i, 0 ) / 20.0) );
+ filters_[1].setTargets( Phonemes::formantFrequency(i, 1), Phonemes::formantRadius(i, 1), pow(10.0, Phonemes::formantGain(i, 1 ) / 20.0) );
+ filters_[2].setTargets( Phonemes::formantFrequency(i, 2), Phonemes::formantRadius(i, 2), pow(10.0, Phonemes::formantGain(i, 2 ) / 20.0) );
+ filters_[3].setTargets( Phonemes::formantFrequency(i, 3), Phonemes::formantRadius(i, 3), pow(10.0, Phonemes::formantGain(i, 3 ) / 20.0) );
+ this->setVoiced( Phonemes::voiceGain( i ) );
+ this->setUnVoiced( Phonemes::noiseGain( i ) );
+#if defined(_STK_DEBUG_)
+ errorString_ << "VoicForm::setPhoneme: found formant " << phoneme << " (number " << i << ").";
+ handleError( StkError::DEBUG_WARNING );
+#endif
+ }
+ i++;
+ }
+
+ if ( !found ) {
+ errorString_ << "VoicForm::setPhoneme: phoneme " << phoneme << " not found!";
+ handleError( StkError::WARNING );
+ }
+
+ return found;
+}
+
+void VoicForm :: setFilterSweepRate( unsigned int whichOne, StkFloat rate )
+{
+ if ( whichOne < 0 || whichOne > 3 ) {
+ errorString_ << "VoicForm::setFilterSweepRate: filter select argument outside range 0-3!";
+ handleError( StkError::WARNING );
+ return;
+ }
+
+ filters_[whichOne].setSweepRate(rate);
+}
+
+void VoicForm :: quiet( void )
+{
+ voiced_->noteOff();
+ noiseEnv_.setTarget( 0.0 );
+}
+
+void VoicForm :: noteOn( StkFloat frequency, StkFloat amplitude )
+{
+ this->setFrequency( frequency );
+ voiced_->setGainTarget( amplitude );
+ onepole_.setPole( 0.97 - (amplitude * 0.2) );
+}
+
+void VoicForm :: controlChange( int number, StkFloat value )
+{
+ StkFloat norm = value * ONE_OVER_128;
+ if ( norm < 0 ) {
+ norm = 0.0;
+ errorString_ << "VoicForm::controlChange: control value less than zero ... setting to zero!";
+ handleError( StkError::WARNING );
+ }
+ else if ( norm > 1.0 ) {
+ norm = 1.0;
+ errorString_ << "VoicForm::controlChange: control value greater than 128.0 ... setting to 128.0!";
+ handleError( StkError::WARNING );
+ }
+
+ if (number == __SK_Breath_) { // 2
+ this->setVoiced( 1.0 - norm );
+ this->setUnVoiced( 0.01 * norm );
+ }
+ else if (number == __SK_FootControl_) { // 4
+ StkFloat temp = 0.0;
+ unsigned int i = (int) value;
+ if (i < 32) {
+ temp = 0.9;
+ }
+ else if (i < 64) {
+ i -= 32;
+ temp = 1.0;
+ }
+ else if (i < 96) {
+ i -= 64;
+ temp = 1.1;
+ }
+ else if (i < 128) {
+ i -= 96;
+ temp = 1.2;
+ }
+ else if (i == 128) {
+ i = 0;
+ temp = 1.4;
+ }
+ filters_[0].setTargets( temp * Phonemes::formantFrequency(i, 0), Phonemes::formantRadius(i, 0), pow(10.0, Phonemes::formantGain(i, 0 ) / 20.0) );
+ filters_[1].setTargets( temp * Phonemes::formantFrequency(i, 1), Phonemes::formantRadius(i, 1), pow(10.0, Phonemes::formantGain(i, 1 ) / 20.0) );
+ filters_[2].setTargets( temp * Phonemes::formantFrequency(i, 2), Phonemes::formantRadius(i, 2), pow(10.0, Phonemes::formantGain(i, 2 ) / 20.0) );
+ filters_[3].setTargets( temp * Phonemes::formantFrequency(i, 3), Phonemes::formantRadius(i, 3), pow(10.0, Phonemes::formantGain(i, 3 ) / 20.0) );
+ this->setVoiced( Phonemes::voiceGain( i ) );
+ this->setUnVoiced( Phonemes::noiseGain( i ) );
+ }
+ else if (number == __SK_ModFrequency_) // 11
+ voiced_->setVibratoRate( norm * 12.0); // 0 to 12 Hz
+ else if (number == __SK_ModWheel_) // 1
+ voiced_->setVibratoGain( norm * 0.2);
+ else if (number == __SK_AfterTouch_Cont_) { // 128
+ this->setVoiced( norm );
+ onepole_.setPole( 0.97 - ( norm * 0.2) );
+ }
+ else {
+ errorString_ << "VoicForm::controlChange: undefined control number (" << number << ")!";
+ handleError( StkError::WARNING );
+ }
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "VoicForm::controlChange: number = " << number << ", value = " << value << '.';
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class Voicer
+ \brief STK voice manager class.
+
+ This class can be used to manage a group of STK instrument
+ classes. Individual voices can be controlled via unique note
+ tags. Instrument groups can be controlled by group number.
+
+ A previously constructed STK instrument class is linked with a
+ voice manager using the addInstrument() function. An optional
+ group number argument can be specified to the addInstrument()
+ function as well (default group = 0). The voice manager does not
+ delete any instrument instances ... it is the responsibility of
+ the user to allocate and deallocate all instruments.
+
+ The tick() function returns the mix of all sounding voices. Each
+ noteOn returns a unique tag (credits to the NeXT MusicKit), so you
+ can send control changes to specific voices within an ensemble.
+ Alternately, control changes can be sent to all voices in a given
+ group.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "Voicer.h"
+#include <cmath>
+
+namespace stk {
+
+Voicer :: Voicer( StkFloat decayTime )
+{
+ tags_ = 23456;
+ muteTime_ = (int) ( decayTime * Stk::sampleRate() );
+ lastFrame_.resize( 1, 1, 0.0 );
+}
+
+void Voicer :: addInstrument( Instrmnt *instrument, int group )
+{
+ Voicer::Voice voice;
+ voice.instrument = instrument;
+ voice.group = group;
+ voice.noteNumber = -1;
+ voices_.push_back( voice );
+
+ // Check output channels and resize lastFrame_ if necessary.
+ if ( instrument->channelsOut() > lastFrame_.channels() ) {
+ unsigned int startChannel = lastFrame_.channels();
+ lastFrame_.resize( 1, instrument->channelsOut() );
+ for ( unsigned int i=startChannel; i<lastFrame_.size(); i++ )
+ lastFrame_[i] = 0.0;
+ }
+}
+
+void Voicer :: removeInstrument( Instrmnt *instrument )
+{
+ bool found = false;
+ std::vector< Voicer::Voice >::iterator i;
+ for ( i=voices_.begin(); i!=voices_.end(); ++i ) {
+ if ( (*i).instrument != instrument ) continue;
+ voices_.erase( i );
+ found = true;
+ break;
+ }
+
+ if ( found ) {
+ // Check output channels and resize lastFrame_ if necessary.
+ unsigned int maxChannels = 1;
+ for ( i=voices_.begin(); i!=voices_.end(); ++i ) {
+ if ( (*i).instrument->channelsOut() > maxChannels ) maxChannels = (*i).instrument->channelsOut();
+ }
+ if ( maxChannels < lastFrame_.channels() )
+ lastFrame_.resize( 1, maxChannels );
+ }
+ else {
+ errorString_ << "Voicer::removeInstrument: instrument pointer not found in current voices!";
+ handleError( StkError::WARNING );
+ }
+}
+
+long Voicer :: noteOn(StkFloat noteNumber, StkFloat amplitude, int group )
+{
+ unsigned int i;
+ StkFloat frequency = (StkFloat) 220.0 * pow( 2.0, (noteNumber - 57.0) / 12.0 );
+ for ( i=0; i<voices_.size(); i++ ) {
+ if (voices_[i].noteNumber < 0 && voices_[i].group == group) {
+ voices_[i].tag = tags_++;
+ voices_[i].group = group;
+ voices_[i].noteNumber = noteNumber;
+ voices_[i].frequency = frequency;
+ voices_[i].instrument->noteOn( frequency, amplitude * ONE_OVER_128 );
+ voices_[i].sounding = 1;
+ return voices_[i].tag;
+ }
+ }
+
+ // All voices are sounding, so interrupt the oldest voice.
+ int voice = -1;
+ for ( i=0; i<voices_.size(); i++ ) {
+ if ( voices_[i].group == group ) {
+ if ( voice == -1 ) voice = i;
+ else if ( voices_[i].tag < voices_[voice].tag ) voice = (int) i;
+ }
+ }
+
+ if ( voice >= 0 ) {
+ voices_[voice].tag = tags_++;
+ voices_[voice].group = group;
+ voices_[voice].noteNumber = noteNumber;
+ voices_[voice].frequency = frequency;
+ voices_[voice].instrument->noteOn( frequency, amplitude * ONE_OVER_128 );
+ voices_[voice].sounding = 1;
+ return voices_[voice].tag;
+ }
+
+ return -1;
+}
+
+void Voicer :: noteOff( StkFloat noteNumber, StkFloat amplitude, int group )
+{
+ for ( unsigned int i=0; i<voices_.size(); i++ ) {
+ if ( voices_[i].noteNumber == noteNumber && voices_[i].group == group ) {
+ voices_[i].instrument->noteOff( amplitude * ONE_OVER_128 );
+ voices_[i].sounding = -muteTime_;
+ }
+ }
+}
+
+void Voicer :: noteOff( long tag, StkFloat amplitude )
+{
+ for ( unsigned int i=0; i<voices_.size(); i++ ) {
+ if ( voices_[i].tag == tag ) {
+ voices_[i].instrument->noteOff( amplitude * ONE_OVER_128 );
+ voices_[i].sounding = -muteTime_;
+ break;
+ }
+ }
+}
+
+void Voicer :: setFrequency( StkFloat noteNumber, int group )
+{
+ StkFloat frequency = (StkFloat) 220.0 * pow( 2.0, (noteNumber - 57.0) / 12.0 );
+ for ( unsigned int i=0; i<voices_.size(); i++ ) {
+ if ( voices_[i].group == group ) {
+ voices_[i].noteNumber = noteNumber;
+ voices_[i].frequency = frequency;
+ voices_[i].instrument->setFrequency( frequency );
+ }
+ }
+}
+
+void Voicer :: setFrequency( long tag, StkFloat noteNumber )
+{
+ StkFloat frequency = (StkFloat) 220.0 * pow( 2.0, (noteNumber - 57.0) / 12.0 );
+ for ( unsigned int i=0; i<voices_.size(); i++ ) {
+ if ( voices_[i].tag == tag ) {
+ voices_[i].noteNumber = noteNumber;
+ voices_[i].frequency = frequency;
+ voices_[i].instrument->setFrequency( frequency );
+ break;
+ }
+ }
+}
+
+void Voicer :: pitchBend( StkFloat value, int group )
+{
+ StkFloat pitchScaler;
+ if ( value < 8192.0 )
+ pitchScaler = pow( 0.5, (8192.0-value) / 8192.0 );
+ else
+ pitchScaler = pow( 2.0, (value-8192.0) / 8192.0 );
+ for ( unsigned int i=0; i<voices_.size(); i++ ) {
+ if ( voices_[i].group == group )
+ voices_[i].instrument->setFrequency( (StkFloat) (voices_[i].frequency * pitchScaler) );
+ }
+}
+
+void Voicer :: pitchBend( long tag, StkFloat value )
+{
+ StkFloat pitchScaler;
+ if ( value < 8192.0 )
+ pitchScaler = pow( 0.5, (8192.0-value) / 8192.0 );
+ else
+ pitchScaler = pow( 2.0, (value-8192.0) / 8192.0 );
+ for ( unsigned int i=0; i<voices_.size(); i++ ) {
+ if ( voices_[i].tag == tag ) {
+ voices_[i].instrument->setFrequency( (StkFloat) (voices_[i].frequency * pitchScaler) );
+ break;
+ }
+ }
+}
+
+void Voicer :: controlChange( int number, StkFloat value, int group )
+{
+ for ( unsigned int i=0; i<voices_.size(); i++ ) {
+ if ( voices_[i].group == group )
+ voices_[i].instrument->controlChange( number, value );
+ }
+}
+
+void Voicer :: controlChange( long tag, int number, StkFloat value )
+{
+ for ( unsigned int i=0; i<voices_.size(); i++ ) {
+ if ( voices_[i].tag == tag ) {
+ voices_[i].instrument->controlChange( number, value );
+ break;
+ }
+ }
+}
+
+void Voicer :: silence( void )
+{
+ for ( unsigned int i=0; i<voices_.size(); i++ ) {
+ if ( voices_[i].sounding > 0 )
+ voices_[i].instrument->noteOff( 0.5 );
+ }
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class Whistle
+ \brief STK police/referee whistle instrument class.
+
+ This class implements a hybrid physical/spectral
+ model of a police whistle (a la Cook).
+
+ Control Change Numbers:
+ - Noise Gain = 4
+ - Fipple Modulation Frequency = 11
+ - Fipple Modulation Gain = 1
+ - Blowing Frequency Modulation = 2
+ - Volume = 128
+
+ by Perry R. Cook 1996 - 2010.
+*/
+/***************************************************/
+
+#include "Whistle.h"
+#include "Skini_msg.h"
+#include <cmath>
+
+namespace stk {
+
+const int CAN_RADIUS = 100;
+const int PEA_RADIUS = 30;
+const int BUMP_RADIUS = 5;
+
+const StkFloat NORM_CAN_LOSS = 0.97;
+const StkFloat SLOW_CAN_LOSS = 0.90;
+const StkFloat GRAVITY = 20.0;
+
+const StkFloat NORM_TICK_SIZE = 0.004;
+const StkFloat SLOW_TICK_SIZE = 0.0001;
+
+const StkFloat ENV_RATE = 0.001;
+
+Whistle :: Whistle( void )
+{
+ sine_.setFrequency( 2800.0 );
+
+ can_.setRadius( CAN_RADIUS );
+ can_.setPosition(0, 0, 0); // set can location
+ can_.setVelocity(0, 0, 0); // and the velocity
+
+ onepole_.setPole(0.95); // 0.99
+
+ bumper_.setRadius( BUMP_RADIUS );
+ bumper_.setPosition(0.0, CAN_RADIUS-BUMP_RADIUS, 0);
+ bumper_.setPosition(0.0, CAN_RADIUS-BUMP_RADIUS, 0);
+
+ pea_.setRadius( PEA_RADIUS );
+ pea_.setPosition(0, CAN_RADIUS/2, 0);
+ pea_.setVelocity(35, 15, 0);
+
+ envelope_.setRate( ENV_RATE );
+ envelope_.keyOn();
+
+ fippleFreqMod_ = 0.5;
+ fippleGainMod_ = 0.5;
+ blowFreqMod_ = 0.25;
+ noiseGain_ = 0.125;
+ baseFrequency_ = 2000;
+
+ tickSize_ = NORM_TICK_SIZE;
+ canLoss_ = NORM_CAN_LOSS;
+
+ subSample_ = 1;
+ subSampCount_ = subSample_;
+}
+
+Whistle :: ~Whistle( void )
+{
+#ifdef WHISTLE_ANIMATION
+ printf("Exit, Whistle bye bye!!\n");
+#endif
+}
+
+void Whistle :: clear( void )
+{
+}
+
+void Whistle :: setFrequency( StkFloat frequency )
+{
+ StkFloat freakency = frequency * 4; // the whistle is a transposing instrument
+ if ( frequency <= 0.0 ) {
+ errorString_ << "Whistle::setFrequency: parameter is less than or equal to zero!";
+ handleError( StkError::WARNING );
+ freakency = 220.0;
+ }
+
+ baseFrequency_ = freakency;
+}
+
+void Whistle :: startBlowing( StkFloat amplitude, StkFloat rate )
+{
+ envelope_.setRate( ENV_RATE );
+ envelope_.setTarget( amplitude );
+}
+
+void Whistle :: stopBlowing( StkFloat rate )
+{
+ envelope_.setRate( rate );
+ envelope_.keyOff();
+}
+
+void Whistle :: noteOn( StkFloat frequency, StkFloat amplitude )
+{
+ this->setFrequency( frequency );
+ this->startBlowing( amplitude*2.0 ,amplitude * 0.2 );
+#if defined(_STK_DEBUG_)
+ errorString_ << "Whistle::NoteOn: frequency = " << frequency << ", amplitude = " << amplitude << '.';
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+void Whistle :: noteOff( StkFloat amplitude )
+{
+ this->stopBlowing( amplitude * 0.02 );
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Whistle::NoteOff: amplitude = " << amplitude << '.';
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+int frameCount = 0;
+
+StkFloat Whistle :: tick( unsigned int )
+{
+ StkFloat soundMix, tempFreq;
+ StkFloat envOut = 0, temp, temp1, temp2, tempX, tempY;
+ double phi, cosphi, sinphi;
+ double gain = 0.5, mod = 0.0;
+
+ if ( --subSampCount_ <= 0 ) {
+ tempVectorP_ = pea_.getPosition();
+ subSampCount_ = subSample_;
+ temp = bumper_.isInside( tempVectorP_ );
+#ifdef WHISTLE_ANIMATION
+ frameCount += 1;
+ if ( frameCount >= (1470 / subSample_) ) {
+ frameCount = 0;
+ printf("%f %f %f\n",tempVectorP_->getX(),tempVectorP_->getY(),envOut);
+ fflush(stdout);
+ }
+#endif
+ envOut = envelope_.tick();
+
+ if (temp < (BUMP_RADIUS + PEA_RADIUS)) {
+ tempX = envOut * tickSize_ * 2000 * noise_.tick();
+ tempY = -envOut * tickSize_ * 1000 * (1.0 + noise_.tick());
+ pea_.addVelocity( tempX, tempY, 0 );
+ pea_.tick( tickSize_ );
+ }
+
+ mod = exp(-temp * 0.01); // exp. distance falloff of fipple/pea effect
+ temp = onepole_.tick(mod); // smooth it a little
+ gain = (1.0 - (fippleGainMod_*0.5)) + (2.0 * fippleGainMod_ * temp);
+ gain *= gain; // squared distance/gain
+ // tempFreq = 1.0 // Normalized Base Freq
+ // + (fippleFreqMod_ * 0.25) - (fippleFreqMod_ * temp) // fippleModulation
+ // - (blowFreqMod_) + (blowFreqMod_ * envOut); // blowingModulation
+ // short form of above
+ tempFreq = 1.0 + fippleFreqMod_*(0.25-temp) + blowFreqMod_*(envOut-1.0);
+ tempFreq *= baseFrequency_;
+
+ sine_.setFrequency(tempFreq);
+
+ tempVectorP_ = pea_.getPosition();
+ temp = can_.isInside(tempVectorP_);
+ temp = -temp; // We know (hope) it's inside, just how much??
+ if (temp < (PEA_RADIUS * 1.25)) {
+ pea_.getVelocity( &tempVector_ ); // This is the can/pea collision
+ tempX = tempVectorP_->getX(); // calculation. Could probably
+ tempY = tempVectorP_->getY(); // simplify using tables, etc.
+ phi = -atan2(tempY,tempX);
+
+ cosphi = cos(phi);
+ sinphi = sin(phi);
+ temp1 = (cosphi*tempVector_.getX()) - (sinphi*tempVector_.getY());
+ temp2 = (sinphi*tempVector_.getX()) + (cosphi*tempVector_.getY());
+ temp1 = -temp1;
+ tempX = (cosphi*temp1) + (sinphi*temp2);
+ tempY = (-sinphi*temp1) + (cosphi*temp2);
+ pea_.setVelocity(tempX, tempY, 0);
+ pea_.tick(tickSize_);
+ pea_.setVelocity( tempX*canLoss_, tempY*canLoss_, 0 );
+ pea_.tick(tickSize_);
+ }
+
+ temp = tempVectorP_->getLength();
+ if (temp > 0.01) {
+ tempX = tempVectorP_->getX();
+ tempY = tempVectorP_->getY();
+ phi = atan2( tempY, tempX );
+ phi += 0.3 * temp / CAN_RADIUS;
+ cosphi = cos(phi);
+ sinphi = sin(phi);
+ tempX = 3.0 * temp * cosphi;
+ tempY = 3.0 * temp * sinphi;
+ }
+ else {
+ tempX = 0.0;
+ tempY = 0.0;
+ }
+
+ temp = (0.9 + 0.1*subSample_*noise_.tick()) * envOut * 0.6 * tickSize_;
+ pea_.addVelocity( temp * tempX, (temp*tempY) - (GRAVITY*tickSize_), 0 );
+ pea_.tick( tickSize_ );
+
+ // bumper_.tick(0.0);
+ }
+
+ temp = envOut * envOut * gain / 2;
+ soundMix = temp * ( sine_.tick() + ( noiseGain_*noise_.tick() ) );
+ lastFrame_[0] = 0.20 * soundMix; // should probably do one-zero filter here
+
+ return lastFrame_[0];
+}
+
+void Whistle :: controlChange( int number, StkFloat value )
+{
+ StkFloat norm = value * ONE_OVER_128;
+ if ( norm < 0 ) {
+ norm = 0.0;
+ errorString_ << "Whistle::controlChange: control value less than zero ... setting to zero!";
+ handleError( StkError::WARNING );
+ }
+ else if ( norm > 1.0 ) {
+ norm = 1.0;
+ errorString_ << "Whistle::controlChange: control value greater than 128.0 ... setting to 128.0!";
+ handleError( StkError::WARNING );
+ }
+
+ if ( number == __SK_NoiseLevel_ ) // 4
+ noiseGain_ = 0.25 * norm;
+ else if ( number == __SK_ModFrequency_ ) // 11
+ fippleFreqMod_ = norm;
+ else if ( number == __SK_ModWheel_ ) // 1
+ fippleGainMod_ = norm;
+ else if ( number == __SK_AfterTouch_Cont_ ) // 128
+ envelope_.setTarget( norm * 2.0 );
+ else if ( number == __SK_Breath_ ) // 2
+ blowFreqMod_ = norm * 0.5;
+ else if ( number == __SK_Sustain_ ) { // 64
+ subSample_ = (int) value;
+ if ( subSample_ < 1.0 ) subSample_ = 1;
+ envelope_.setRate( ENV_RATE / subSample_ );
+ }
+ else {
+ errorString_ << "Whistle::controlChange: undefined control number (" << number << ")!";
+ handleError( StkError::WARNING );
+ }
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Whistle::controlChange: number = " << number << ", value = " << value << '.';
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+} // stk namespace
--- /dev/null
+/***************************************************/
+/*! \class Wurley
+ \brief STK Wurlitzer electric piano FM
+ synthesis instrument.
+
+ This class implements two simple FM Pairs
+ summed together, also referred to as algorithm
+ 5 of the TX81Z.
+
+ \code
+ Algorithm 5 is : 4->3--\
+ + --> Out
+ 2->1--/
+ \endcode
+
+ Control Change Numbers:
+ - Modulator Index One = 2
+ - Crossfade of Outputs = 4
+ - LFO Speed = 11
+ - LFO Depth = 1
+ - ADSR 2 & 4 Target = 128
+
+ The basic Chowning/Stanford FM patent expired
+ in 1995, but there exist follow-on patents,
+ mostly assigned to Yamaha. If you are of the
+ type who should worry about this (making
+ money) worry away.
+
+ by Perry R. Cook and Gary P. Scavone, 1995 - 2010.
+*/
+/***************************************************/
+
+#include "Wurley.h"
+
+namespace stk {
+
+Wurley :: Wurley( void )
+ : FM()
+{
+ // Concatenate the STK rawwave path to the rawwave files
+ for ( unsigned int i=0; i<3; i++ )
+ waves_[i] = new FileLoop( (Stk::rawwavePath() + "sinewave.raw").c_str(), true );
+ waves_[3] = new FileLoop( (Stk::rawwavePath() + "fwavblnk.raw").c_str(), true );
+
+ this->setRatio(0, 1.0);
+ this->setRatio(1, 4.0);
+ this->setRatio(2, -510.0);
+ this->setRatio(3, -510.0);
+
+ gains_[0] = fmGains_[99];
+ gains_[1] = fmGains_[82];
+ gains_[2] = fmGains_[92];
+ gains_[3] = fmGains_[68];
+
+ adsr_[0]->setAllTimes( 0.001, 1.50, 0.0, 0.04);
+ adsr_[1]->setAllTimes( 0.001, 1.50, 0.0, 0.04);
+ adsr_[2]->setAllTimes( 0.001, 0.25, 0.0, 0.04);
+ adsr_[3]->setAllTimes( 0.001, 0.15, 0.0, 0.04);
+
+ twozero_.setGain( 2.0 );
+ vibrato_.setFrequency( 8.0 );
+}
+
+Wurley :: ~Wurley( void )
+{
+}
+
+void Wurley :: setFrequency( StkFloat frequency )
+{
+ baseFrequency_ = frequency;
+ waves_[0]->setFrequency( baseFrequency_ * ratios_[0]);
+ waves_[1]->setFrequency( baseFrequency_ * ratios_[1]);
+ waves_[2]->setFrequency( ratios_[2] ); // Note here a 'fixed resonance'.
+ waves_[3]->setFrequency( ratios_[3] );
+}
+
+void Wurley :: noteOn( StkFloat frequency, StkFloat amplitude )
+{
+ gains_[0] = amplitude * fmGains_[99];
+ gains_[1] = amplitude * fmGains_[82];
+ gains_[2] = amplitude * fmGains_[82];
+ gains_[3] = amplitude * fmGains_[68];
+ this->setFrequency( frequency );
+ this->keyOn();
+
+#if defined(_STK_DEBUG_)
+ errorString_ << "Wurley::NoteOn: frequency = " << frequency << ", amplitude = " << amplitude << '.';
+ handleError( StkError::DEBUG_WARNING );
+#endif
+}
+
+} // stk namespace
--- /dev/null
+//
+// Voice.cpp
+// cinder_ios_stk
+//
+// Created by Gabriel Dunne on 12/29/12.
+//
+//
+
+#include "Voice.h"
+
+Voice::SoundMode Voice::s_globalMode = SINE_MODE;
+
+Voice::Voice() :
+ m_fs() {
+ m_gain = 0;
+ m_freq = 220;
+ m_mode = s_globalMode;
+}
+
+Voice::~Voice() {
+}
+
+void Voice::init() {
+
+ m_gain = 0;
+ m_freq = 220;
+
+ adsr.setAllTimes( .1, 1.0, 1.0, 0.01 );
+
+ switch(m_mode) {
+
+ case BANDEDWG_MODE:
+ m_wg.setPreset(3);
+ break;
+
+ case SINE_MODE:
+ break;
+
+ case BLIT_MODE:
+ m_blit.setHarmonics(12);
+ break;
+
+ case NOISE_MODE:
+ m_noise.setSeed(time(NULL));
+ m_noiseFilter.setResonance(m_freq, 0.5, true);
+ m_noiseFilter.setEqualGainZeroes();
+ break;
+
+ case WAVFILE_MODE:
+ // std::string filepath = [[[NSBundle mainBundle]
+ // pathForResource:@"spencer-ahh.wav" ofType:@""] UTF8String];
+ // m_wav.openFile(filepath);
+ break;
+
+ case WURLEY_MODE:
+ break;
+ }
+}
+
+void Voice::keyOn(float a) {
+
+ m_gain = a;
+ adsr.keyOn();
+
+ switch(m_mode) {
+
+ case BANDEDWG_MODE:
+ m_wg.noteOn(m_freq, a);
+ m_wg.pluck(a);
+ break;
+
+ case BLIT_MODE:
+ break;
+
+ case SINE_MODE:
+ case NOISE_MODE:
+ setFrequency(m_freq);
+ break;
+
+ case WAVFILE_MODE:
+ break;
+
+ case WURLEY_MODE:
+ m_wurley.noteOn(m_freq, m_gain);
+ break;
+ }
+}
+
+void Voice::keyOff(float a) {
+
+ adsr.keyOff();
+
+ switch(m_mode) {
+
+ case BANDEDWG_MODE:
+ m_wg.noteOff(a);
+ break;
+
+ case BLIT_MODE:
+ break;
+
+ case SINE_MODE:
+ case NOISE_MODE:
+ break;
+
+ case WAVFILE_MODE:
+ break;
+ case WURLEY_MODE:
+ m_wurley.noteOff(a);
+ break;
+ }
+}
+
+void Voice::setFrequency(float f) {
+
+ m_freq = f;
+
+ switch(m_mode) {
+
+ case BANDEDWG_MODE:
+ m_wg.noteOn(m_freq, 1.0);
+ break;
+
+ case BLIT_MODE:
+ m_blit.setFrequency(m_freq);
+ break;
+
+ case SINE_MODE:
+ m_sin.setFrequency(m_freq);
+ break;
+
+ case NOISE_MODE:
+ m_noiseFilter.setResonance(m_freq, 0.99999, true);
+ m_noiseFilter.setEqualGainZeroes();
+ break;
+
+ case WAVFILE_MODE:
+ // float base = mtof(56);
+ // m_wav.setRate(m_freq/base);
+ break;
+
+ case WURLEY_MODE:
+ m_wurley.setFrequency(m_freq);
+ break;
+ }
+}
+
+float Voice::tick() {
+
+ float samp = 0;
+
+ switch(m_mode) {
+
+ case BANDEDWG_MODE:
+ samp = m_gain * m_wg.tick();
+ break;
+ case BLIT_MODE:
+ samp = m_gain * m_blit.tick() * adsr.tick() * 0.25 ;
+ break;
+ case SINE_MODE:
+ // samp = m_gain * m_sin.tick() * adsr.tick() * .2;
+ samp = m_gain * maxiOsc.triangle(m_freq) * adsr.tick() * .2;
+ break;
+ case NOISE_MODE:
+ samp = m_gain *
+ m_noiseFilter.tick(m_noise.tick() * 0.001) *
+ adsr.tick() * .55;
+ break;
+ case WAVFILE_MODE:
+ samp = m_gain * m_wav.tick() * 0.1;
+ if(m_wav.isFinished()) m_wav.reset();
+ break;
+
+ case WURLEY_MODE:
+ samp = m_gain * m_wurley.tick() * adsr.tick();
+ break;
+ }
+ return samp;
+}
+
+void Voice::destroy() {
+}
--- /dev/null
+//
+// Voice.h
+// cinder_ios_stk
+//
+// Created by Gabriel Dunne on 12/29/12.
+//
+//
+
+#ifndef cinder_ios_stk_Voice_h
+#define cinder_ios_stk_Voice_h
+
+#include "BandedWG.h"
+#include "Blit.h"
+#include "Noise.h"
+#include "BiQuad.h"
+#include "FileWvIn.h"
+#include "Rhodey.h"
+#include "ADSR.h"
+#include "SineWave.h"
+#include "maximilian.h"
+#include "Wurley.h"
+
+using namespace stk;
+
+class Voice
+{
+public:
+
+ Voice();
+ ~Voice();
+
+ void init();
+ float tick();
+ void destroy();
+
+ void setFrequency(float f);
+ void setGain(float g) { m_gain = g; }
+ void keyOn( float amp );
+ void keyOff( float amp );
+
+ enum SoundMode
+ {
+ BLIT_MODE,
+ BANDEDWG_MODE,
+ WAVFILE_MODE,
+ NOISE_MODE,
+ SINE_MODE,
+ WURLEY_MODE
+ };
+
+ static void setGlobalSoundMode(SoundMode mode) { s_globalMode = mode; }
+ void setSoundMode(SoundMode mode) { m_mode = mode; }
+
+ ADSR adsr;
+
+private:
+ static SoundMode s_globalMode;
+
+ const float m_fs;
+
+ float m_gain;
+ float m_freq;
+
+ SoundMode m_mode;
+ BandedWG m_wg;
+ Blit m_blit;
+ Noise m_noise;
+ BiQuad m_noiseFilter;
+ SineWave m_sin;
+ maxiOsc maxiOsc;
+ Rhodey m_rhodey;
+ FileWvIn m_wav;
+ Wurley m_wurley;
+};
+
+#endif
-#include "cinder/app/AppNative.h"
-#include "cinder/gl/gl.h"
+#include "iosynthApp.h"
-using namespace ci;
-using namespace ci::app;
-using namespace std;
-class iosynthApp : public AppNative {
- public:
- void setup();
- void mouseDown( MouseEvent event );
- void update();
- void draw();
-};
void iosynthApp::setup()
{
void iosynthApp::draw()
{
- // clear out the window with black
- gl::clear( Color( 0, 0, 0 ) );
+ gl::clear( Color( 0, 1.0f, 0 ) );
}
+
+void iosynthApp::touchesBegan( TouchEvent t )
+{
+}
+
+void iosynthApp::touchesMoved( TouchEvent t )
+{
+}
+
+void iosynthApp::touchesEnded( TouchEvent t )
+{
+}
+
+
CINDER_APP_NATIVE( iosynthApp, RendererGl )
--- /dev/null
+//
+// iosynthApp.h
+// iosynth
+//
+// Created by Gabriel Dunne on 12/7/13.
+//
+//
+#ifndef iosynth_iosynthApp_h
+#define iosynth_iosynthApp_h
+
+#include "cinder/app/AppNative.h"
+// #include "cinder/app/AppCocoaTouch.h"
+#include "cinder/app/TouchEvent.h"
+#include "cinder/app/Renderer.h"
+#include "cinder/gl/gl.h"
+
+#include "cinder/Rand.h"
+#include "cinder/CinderMath.h"
+#include "cinder/Utilities.h"
+#include "cinder/audio/Output.h"
+#include "cinder/audio/Callback.h"
+
+// STK
+#include "Stk.h"
+#include "NRev.h"
+#include "JCRev.h"
+#include "Sitar.h"
+
+// maximilian
+#include "maximilian.h"
+
+#include "Voice.h"
+
+using namespace ci;
+using namespace ci::app;
+using namespace std;
+
+// num voices = num touchpoints
+#define NUM_VOICES 11
+#define BUFFER_SIZE 1024
+
+class iosynthApp : public AppNative {
+public:
+ void setup();
+ void mouseDown( MouseEvent event );
+ void update();
+ void draw();
+
+ void processAudio( uint64_t inSampleOffset, uint32_t ioSampleCount,
+ audio::Buffer32f *ioBuffer );
+ void touchesBegan( TouchEvent event );
+ void touchesMoved( TouchEvent event );
+ void touchesEnded( TouchEvent event );
+
+ float mMasterGain;
+ float mAudioSamples[2][BUFFER_SIZE];
+
+ int mAppWidth, mAppHeight;
+
+ std::vector<Voice *> voices;
+ std::vector<ADSR *> envelopes;
+
+ JCRev reverb;
+ maxiDelayline maxiDelay;
+ maxiDyn maxiDyn;
+ maxiFilter maxiFilter;
+};
+
+#endif
objects = {
/* Begin PBXBuildFile section */
+ 00748058165D41390024B57A /* assets in Resources */ = {isa = PBXBuildFile; fileRef = 00748057165D41390024B57A /* assets */; };
0087D25512CD809F002CD69F /* CoreText.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0087D25412CD809F002CD69F /* CoreText.framework */; };
00CFDF6B1138442D0091E310 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00CFDF6A1138442D0091E310 /* CoreGraphics.framework */; };
- C725E001121DAC8FFFFA18FF /* ImageIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00CFDF6A1138442D0091FFFF /* ImageIO.framework */; };
- DDDDE001121DAC8FFFFADDDD /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DDDDDF6A1138442D0091DDDD /* MobileCoreServices.framework */; };
1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; };
1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */; };
28FD15000DC6FC520079059D /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 28FD14FF0DC6FC520079059D /* OpenGLES.framework */; };
28FD15080DC6FC5B0079059D /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 28FD15070DC6FC5B0079059D /* QuartzCore.framework */; };
- C725DFFE121DAC7F00FA186B /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C727C02B121B400300192073 /* CoreMedia.framework */; settings = {
- ATTRIBUTES = (
- Weak,
- );
-}; };
- C725E001121DAC8F00FA186B /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C725E000121DAC8F00FA186B /* AVFoundation.framework */; settings = {
- ATTRIBUTES = (
- Weak,
- );
-}; };
- C727C02E121B400300192073 /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C727C02D121B400300192073 /* CoreVideo.framework */; settings = {
- ATTRIBUTES = (
- Weak,
- );
-}; };
- C7FB19D6124BC0D70045AFD2 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C7FB19D5124BC0D70045AFD2 /* AudioToolbox.framework */; };
- 00748058165D41390024B57A /* assets in Resources */ = {isa = PBXBuildFile; fileRef = 00748057165D41390024B57A /* assets */; };
- D6D8A6B842AA4BF6AD3A0D87 /* iosynth_Prefix.pch in Headers */ = {isa = PBXBuildFile; fileRef = 5F24CD9B8A5949E0B1828046 /* iosynth_Prefix.pch */; };
- FDB524FC93AD48DE9DEE5102 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 27664426CDC048598E09896C /* Default-568h@2x.png */; };
31EF3990B82C404DB705930E /* CinderApp_ios.png in Resources */ = {isa = PBXBuildFile; fileRef = C9BCD27FE5CA496094E38DC7 /* CinderApp_ios.png */; };
- 24D3F6D65770461E999C667B /* Resources.h in Headers */ = {isa = PBXBuildFile; fileRef = 359BF798F4294C6BB6836DC9 /* Resources.h */; };
3280A26996EF49D98A7F86C6 /* iosynthApp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 11CEB50DDC2D442F828EFE49 /* iosynthApp.cpp */; };
+ 68CAAF0C1854556E00DB5318 /* Voice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAF0A1854556E00DB5318 /* Voice.cpp */; };
+ 68CAAFFC185456F100DB5318 /* maximilian.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAF0F185456F000DB5318 /* maximilian.cpp */; };
+ 68CAB02F185456F100DB5318 /* ADSR.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFA7185456F100DB5318 /* ADSR.cpp */; };
+ 68CAB030185456F100DB5318 /* Asymp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFA8185456F100DB5318 /* Asymp.cpp */; };
+ 68CAB031185456F100DB5318 /* BandedWG.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFA9185456F100DB5318 /* BandedWG.cpp */; };
+ 68CAB032185456F100DB5318 /* BeeThree.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFAA185456F100DB5318 /* BeeThree.cpp */; };
+ 68CAB033185456F100DB5318 /* BiQuad.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFAB185456F100DB5318 /* BiQuad.cpp */; };
+ 68CAB034185456F100DB5318 /* Blit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFAC185456F100DB5318 /* Blit.cpp */; };
+ 68CAB035185456F100DB5318 /* BlitSaw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFAD185456F100DB5318 /* BlitSaw.cpp */; };
+ 68CAB036185456F100DB5318 /* BlitSquare.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFAE185456F100DB5318 /* BlitSquare.cpp */; };
+ 68CAB037185456F100DB5318 /* BlowBotl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFAF185456F100DB5318 /* BlowBotl.cpp */; };
+ 68CAB038185456F100DB5318 /* BlowHole.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFB0185456F100DB5318 /* BlowHole.cpp */; };
+ 68CAB039185456F100DB5318 /* Bowed.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFB1185456F100DB5318 /* Bowed.cpp */; };
+ 68CAB03A185456F100DB5318 /* Brass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFB2185456F100DB5318 /* Brass.cpp */; };
+ 68CAB03B185456F100DB5318 /* Chorus.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFB3185456F100DB5318 /* Chorus.cpp */; };
+ 68CAB03C185456F100DB5318 /* Clarinet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFB4185456F100DB5318 /* Clarinet.cpp */; };
+ 68CAB03D185456F100DB5318 /* Delay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFB5185456F100DB5318 /* Delay.cpp */; };
+ 68CAB03E185456F100DB5318 /* DelayA.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFB6185456F100DB5318 /* DelayA.cpp */; };
+ 68CAB03F185456F100DB5318 /* DelayL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFB7185456F100DB5318 /* DelayL.cpp */; };
+ 68CAB040185456F100DB5318 /* Drummer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFB8185456F100DB5318 /* Drummer.cpp */; };
+ 68CAB041185456F100DB5318 /* Echo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFB9185456F100DB5318 /* Echo.cpp */; };
+ 68CAB042185456F100DB5318 /* Envelope.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFBA185456F100DB5318 /* Envelope.cpp */; };
+ 68CAB043185456F100DB5318 /* FileLoop.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFBB185456F100DB5318 /* FileLoop.cpp */; };
+ 68CAB044185456F100DB5318 /* FileRead.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFBC185456F100DB5318 /* FileRead.cpp */; };
+ 68CAB045185456F100DB5318 /* FileWrite.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFBD185456F100DB5318 /* FileWrite.cpp */; };
+ 68CAB046185456F100DB5318 /* FileWvIn.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFBE185456F100DB5318 /* FileWvIn.cpp */; };
+ 68CAB047185456F100DB5318 /* FileWvOut.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFBF185456F100DB5318 /* FileWvOut.cpp */; };
+ 68CAB048185456F100DB5318 /* Fir.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFC0185456F100DB5318 /* Fir.cpp */; };
+ 68CAB049185456F100DB5318 /* Flute.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFC1185456F100DB5318 /* Flute.cpp */; };
+ 68CAB04A185456F100DB5318 /* FM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFC2185456F100DB5318 /* FM.cpp */; };
+ 68CAB04B185456F100DB5318 /* FMVoices.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFC3185456F100DB5318 /* FMVoices.cpp */; };
+ 68CAB04C185456F100DB5318 /* FormSwep.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFC4185456F100DB5318 /* FormSwep.cpp */; };
+ 68CAB04D185456F100DB5318 /* Granulate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFC5185456F100DB5318 /* Granulate.cpp */; };
+ 68CAB04E185456F100DB5318 /* HevyMetl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFC6185456F100DB5318 /* HevyMetl.cpp */; };
+ 68CAB04F185456F100DB5318 /* Iir.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFC7185456F100DB5318 /* Iir.cpp */; };
+ 68CAB050185456F100DB5318 /* InetWvIn.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFC8185456F100DB5318 /* InetWvIn.cpp */; };
+ 68CAB051185456F100DB5318 /* InetWvOut.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFC9185456F100DB5318 /* InetWvOut.cpp */; };
+ 68CAB052185456F100DB5318 /* JCRev.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFCA185456F100DB5318 /* JCRev.cpp */; };
+ 68CAB053185456F100DB5318 /* LentPitShift.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFCB185456F100DB5318 /* LentPitShift.cpp */; };
+ 68CAB054185456F100DB5318 /* Mandolin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFCC185456F100DB5318 /* Mandolin.cpp */; };
+ 68CAB055185456F100DB5318 /* Mesh2D.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFCD185456F100DB5318 /* Mesh2D.cpp */; };
+ 68CAB056185456F100DB5318 /* Messager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFCE185456F100DB5318 /* Messager.cpp */; };
+ 68CAB057185456F100DB5318 /* MidiFileIn.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFCF185456F100DB5318 /* MidiFileIn.cpp */; };
+ 68CAB058185456F100DB5318 /* Modal.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFD0185456F100DB5318 /* Modal.cpp */; };
+ 68CAB059185456F100DB5318 /* ModalBar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFD1185456F100DB5318 /* ModalBar.cpp */; };
+ 68CAB05A185456F100DB5318 /* Modulate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFD2185456F100DB5318 /* Modulate.cpp */; };
+ 68CAB05B185456F100DB5318 /* Moog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFD3185456F100DB5318 /* Moog.cpp */; };
+ 68CAB05C185456F100DB5318 /* Mutex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFD4185456F100DB5318 /* Mutex.cpp */; };
+ 68CAB05D185456F100DB5318 /* Noise.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFD5185456F100DB5318 /* Noise.cpp */; };
+ 68CAB05E185456F100DB5318 /* NRev.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFD6185456F100DB5318 /* NRev.cpp */; };
+ 68CAB05F185456F100DB5318 /* OnePole.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFD7185456F100DB5318 /* OnePole.cpp */; };
+ 68CAB060185456F100DB5318 /* OneZero.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFD8185456F100DB5318 /* OneZero.cpp */; };
+ 68CAB061185456F100DB5318 /* PercFlut.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFD9185456F100DB5318 /* PercFlut.cpp */; };
+ 68CAB062185456F100DB5318 /* Phonemes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFDA185456F100DB5318 /* Phonemes.cpp */; };
+ 68CAB063185456F100DB5318 /* PitShift.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFDB185456F100DB5318 /* PitShift.cpp */; };
+ 68CAB064185456F100DB5318 /* Plucked.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFDC185456F100DB5318 /* Plucked.cpp */; };
+ 68CAB065185456F100DB5318 /* PluckTwo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFDD185456F100DB5318 /* PluckTwo.cpp */; };
+ 68CAB066185456F100DB5318 /* PoleZero.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFDE185456F100DB5318 /* PoleZero.cpp */; };
+ 68CAB067185456F100DB5318 /* PRCRev.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFDF185456F100DB5318 /* PRCRev.cpp */; };
+ 68CAB068185456F100DB5318 /* Resonate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFE0185456F100DB5318 /* Resonate.cpp */; };
+ 68CAB069185456F100DB5318 /* Rhodey.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFE1185456F100DB5318 /* Rhodey.cpp */; };
+ 68CAB06A185456F100DB5318 /* Sampler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFE2185456F100DB5318 /* Sampler.cpp */; };
+ 68CAB06B185456F100DB5318 /* Saxofony.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFE3185456F100DB5318 /* Saxofony.cpp */; };
+ 68CAB06C185456F100DB5318 /* Shakers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFE4185456F100DB5318 /* Shakers.cpp */; };
+ 68CAB06D185456F100DB5318 /* Simple.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFE5185456F100DB5318 /* Simple.cpp */; };
+ 68CAB06E185456F100DB5318 /* SineWave.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFE6185456F100DB5318 /* SineWave.cpp */; };
+ 68CAB06F185456F100DB5318 /* SingWave.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFE7185456F100DB5318 /* SingWave.cpp */; };
+ 68CAB070185456F100DB5318 /* Sitar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFE8185456F100DB5318 /* Sitar.cpp */; };
+ 68CAB071185456F100DB5318 /* Skini.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFE9185456F100DB5318 /* Skini.cpp */; };
+ 68CAB072185456F100DB5318 /* Socket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFEA185456F100DB5318 /* Socket.cpp */; };
+ 68CAB073185456F100DB5318 /* Sphere.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFEB185456F100DB5318 /* Sphere.cpp */; };
+ 68CAB074185456F100DB5318 /* StifKarp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFEC185456F100DB5318 /* StifKarp.cpp */; };
+ 68CAB075185456F100DB5318 /* Stk.mm in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFED185456F100DB5318 /* Stk.mm */; };
+ 68CAB076185456F100DB5318 /* StkUdpSocket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFEE185456F100DB5318 /* StkUdpSocket.cpp */; };
+ 68CAB077185456F100DB5318 /* TapDelay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFEF185456F100DB5318 /* TapDelay.cpp */; };
+ 68CAB078185456F100DB5318 /* TcpClient.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFF0185456F100DB5318 /* TcpClient.cpp */; };
+ 68CAB079185456F100DB5318 /* TcpServer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFF1185456F100DB5318 /* TcpServer.cpp */; };
+ 68CAB07A185456F100DB5318 /* Thread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFF2185456F100DB5318 /* Thread.cpp */; };
+ 68CAB07B185456F100DB5318 /* TubeBell.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFF3185456F100DB5318 /* TubeBell.cpp */; };
+ 68CAB07C185456F100DB5318 /* TwoPole.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFF4185456F100DB5318 /* TwoPole.cpp */; };
+ 68CAB07D185456F100DB5318 /* TwoZero.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFF5185456F100DB5318 /* TwoZero.cpp */; };
+ 68CAB07E185456F100DB5318 /* Voicer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFF6185456F100DB5318 /* Voicer.cpp */; };
+ 68CAB07F185456F100DB5318 /* VoicForm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFF7185456F100DB5318 /* VoicForm.cpp */; };
+ 68CAB080185456F100DB5318 /* Whistle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFF8185456F100DB5318 /* Whistle.cpp */; };
+ 68CAB081185456F100DB5318 /* Wurley.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 68CAAFF9185456F100DB5318 /* Wurley.cpp */; };
+ C725DFFE121DAC7F00FA186B /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C727C02B121B400300192073 /* CoreMedia.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
+ C725E001121DAC8F00FA186B /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C725E000121DAC8F00FA186B /* AVFoundation.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
+ C725E001121DAC8FFFFA18FF /* ImageIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00CFDF6A1138442D0091FFFF /* ImageIO.framework */; };
+ C727C02E121B400300192073 /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C727C02D121B400300192073 /* CoreVideo.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
+ C7FB19D6124BC0D70045AFD2 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C7FB19D5124BC0D70045AFD2 /* AudioToolbox.framework */; };
+ DDDDE001121DAC8FFFFADDDD /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DDDDDF6A1138442D0091DDDD /* MobileCoreServices.framework */; };
+ FDB524FC93AD48DE9DEE5102 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 27664426CDC048598E09896C /* Default-568h@2x.png */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
00692BCF14FF149000D0A05E /* iosynth.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iosynth.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 00748057165D41390024B57A /* assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = assets; path = ../assets; sourceTree = "<group>"; };
0087D25412CD809F002CD69F /* CoreText.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreText.framework; path = System/Library/Frameworks/CoreText.framework; sourceTree = SDKROOT; };
00CFDF6A1138442D0091E310 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
00CFDF6A1138442D0091FFFF /* ImageIO.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ImageIO.framework; path = System/Library/Frameworks/ImageIO.framework; sourceTree = SDKROOT; };
- DDDDDF6A1138442D0091DDDD /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; };
+ 11CEB50DDC2D442F828EFE49 /* iosynthApp.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.cpp; name = iosynthApp.cpp; path = ../src/iosynthApp.cpp; sourceTree = "<group>"; };
1D30AB110D05D00D00671497 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
1DF5F4DF0D08C38300B7A737 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
+ 27664426CDC048598E09896C /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = "\"\""; path = "Default-568h@2x.png"; sourceTree = "<group>"; };
28FD14FF0DC6FC520079059D /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; };
28FD15070DC6FC5B0079059D /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
+ 359BF798F4294C6BB6836DC9 /* Resources.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Resources.h; path = ../include/Resources.h; sourceTree = "<group>"; };
+ 3DCA5ADB4E5F41B8BC4AFF40 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ 5F24CD9B8A5949E0B1828046 /* iosynth_Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = "\"\""; path = iosynth_Prefix.pch; sourceTree = "<group>"; };
+ 68CAAF0918544B0700DB5318 /* iosynthApp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = iosynthApp.h; path = ../src/iosynthApp.h; sourceTree = "<group>"; };
+ 68CAAF0A1854556E00DB5318 /* Voice.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Voice.cpp; path = ../src/Voice.cpp; sourceTree = "<group>"; };
+ 68CAAF0B1854556E00DB5318 /* Voice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Voice.h; path = ../src/Voice.h; sourceTree = "<group>"; };
+ 68CAAF0F185456F000DB5318 /* maximilian.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = maximilian.cpp; sourceTree = "<group>"; };
+ 68CAAF10185456F000DB5318 /* maximilian.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = maximilian.h; sourceTree = "<group>"; };
+ 68CAAF16185456F000DB5318 /* ADSR.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADSR.h; sourceTree = "<group>"; };
+ 68CAAF17185456F000DB5318 /* Asymp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Asymp.h; sourceTree = "<group>"; };
+ 68CAAF18185456F000DB5318 /* BandedWG.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BandedWG.h; sourceTree = "<group>"; };
+ 68CAAF19185456F000DB5318 /* BeeThree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BeeThree.h; sourceTree = "<group>"; };
+ 68CAAF1A185456F000DB5318 /* BiQuad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BiQuad.h; sourceTree = "<group>"; };
+ 68CAAF1B185456F000DB5318 /* Blit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Blit.h; sourceTree = "<group>"; };
+ 68CAAF1C185456F000DB5318 /* BlitSaw.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BlitSaw.h; sourceTree = "<group>"; };
+ 68CAAF1D185456F000DB5318 /* BlitSquare.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BlitSquare.h; sourceTree = "<group>"; };
+ 68CAAF1E185456F000DB5318 /* BlowBotl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BlowBotl.h; sourceTree = "<group>"; };
+ 68CAAF1F185456F000DB5318 /* BlowHole.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BlowHole.h; sourceTree = "<group>"; };
+ 68CAAF20185456F000DB5318 /* Bowed.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Bowed.h; sourceTree = "<group>"; };
+ 68CAAF21185456F000DB5318 /* BowTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BowTable.h; sourceTree = "<group>"; };
+ 68CAAF22185456F000DB5318 /* Brass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Brass.h; sourceTree = "<group>"; };
+ 68CAAF23185456F000DB5318 /* Chorus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Chorus.h; sourceTree = "<group>"; };
+ 68CAAF24185456F000DB5318 /* Clarinet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Clarinet.h; sourceTree = "<group>"; };
+ 68CAAF25185456F000DB5318 /* Delay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Delay.h; sourceTree = "<group>"; };
+ 68CAAF26185456F000DB5318 /* DelayA.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DelayA.h; sourceTree = "<group>"; };
+ 68CAAF27185456F000DB5318 /* DelayL.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DelayL.h; sourceTree = "<group>"; };
+ 68CAAF28185456F000DB5318 /* Drummer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Drummer.h; sourceTree = "<group>"; };
+ 68CAAF29185456F000DB5318 /* Echo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Echo.h; sourceTree = "<group>"; };
+ 68CAAF2A185456F000DB5318 /* Effect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Effect.h; sourceTree = "<group>"; };
+ 68CAAF2B185456F000DB5318 /* Envelope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Envelope.h; sourceTree = "<group>"; };
+ 68CAAF2C185456F000DB5318 /* FileLoop.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FileLoop.h; sourceTree = "<group>"; };
+ 68CAAF2D185456F000DB5318 /* FileRead.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FileRead.h; sourceTree = "<group>"; };
+ 68CAAF2E185456F000DB5318 /* FileWrite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FileWrite.h; sourceTree = "<group>"; };
+ 68CAAF2F185456F000DB5318 /* FileWvIn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FileWvIn.h; sourceTree = "<group>"; };
+ 68CAAF30185456F000DB5318 /* FileWvOut.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FileWvOut.h; sourceTree = "<group>"; };
+ 68CAAF31185456F000DB5318 /* Filter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Filter.h; sourceTree = "<group>"; };
+ 68CAAF32185456F000DB5318 /* Fir.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Fir.h; sourceTree = "<group>"; };
+ 68CAAF33185456F000DB5318 /* Flute.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Flute.h; sourceTree = "<group>"; };
+ 68CAAF34185456F000DB5318 /* FM.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FM.h; sourceTree = "<group>"; };
+ 68CAAF35185456F000DB5318 /* FMVoices.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FMVoices.h; sourceTree = "<group>"; };
+ 68CAAF36185456F000DB5318 /* FormSwep.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FormSwep.h; sourceTree = "<group>"; };
+ 68CAAF37185456F000DB5318 /* Function.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Function.h; sourceTree = "<group>"; };
+ 68CAAF38185456F000DB5318 /* Generator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Generator.h; sourceTree = "<group>"; };
+ 68CAAF39185456F000DB5318 /* Granulate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Granulate.h; sourceTree = "<group>"; };
+ 68CAAF3A185456F000DB5318 /* HevyMetl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HevyMetl.h; sourceTree = "<group>"; };
+ 68CAAF3B185456F000DB5318 /* Iir.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Iir.h; sourceTree = "<group>"; };
+ 68CAAF3C185456F000DB5318 /* InetWvIn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InetWvIn.h; sourceTree = "<group>"; };
+ 68CAAF3D185456F000DB5318 /* InetWvOut.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InetWvOut.h; sourceTree = "<group>"; };
+ 68CAAF3E185456F000DB5318 /* Instrmnt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Instrmnt.h; sourceTree = "<group>"; };
+ 68CAAF3F185456F000DB5318 /* JCRev.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JCRev.h; sourceTree = "<group>"; };
+ 68CAAF40185456F000DB5318 /* JetTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JetTable.h; sourceTree = "<group>"; };
+ 68CAAF41185456F000DB5318 /* LentPitShift.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LentPitShift.h; sourceTree = "<group>"; };
+ 68CAAF42185456F000DB5318 /* Mandolin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Mandolin.h; sourceTree = "<group>"; };
+ 68CAAF43185456F000DB5318 /* Mesh2D.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Mesh2D.h; sourceTree = "<group>"; };
+ 68CAAF44185456F000DB5318 /* Messager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Messager.h; sourceTree = "<group>"; };
+ 68CAAF45185456F000DB5318 /* MidiFileIn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MidiFileIn.h; sourceTree = "<group>"; };
+ 68CAAF46185456F000DB5318 /* Modal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Modal.h; sourceTree = "<group>"; };
+ 68CAAF47185456F000DB5318 /* ModalBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ModalBar.h; sourceTree = "<group>"; };
+ 68CAAF48185456F000DB5318 /* Modulate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Modulate.h; sourceTree = "<group>"; };
+ 68CAAF49185456F000DB5318 /* Moog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Moog.h; sourceTree = "<group>"; };
+ 68CAAF4A185456F000DB5318 /* Mutex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Mutex.h; sourceTree = "<group>"; };
+ 68CAAF4B185456F000DB5318 /* Noise.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Noise.h; sourceTree = "<group>"; };
+ 68CAAF4C185456F000DB5318 /* NRev.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NRev.h; sourceTree = "<group>"; };
+ 68CAAF4D185456F000DB5318 /* OnePole.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OnePole.h; sourceTree = "<group>"; };
+ 68CAAF4E185456F000DB5318 /* OneZero.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OneZero.h; sourceTree = "<group>"; };
+ 68CAAF4F185456F000DB5318 /* PercFlut.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PercFlut.h; sourceTree = "<group>"; };
+ 68CAAF50185456F000DB5318 /* Phonemes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Phonemes.h; sourceTree = "<group>"; };
+ 68CAAF51185456F000DB5318 /* PitShift.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PitShift.h; sourceTree = "<group>"; };
+ 68CAAF52185456F000DB5318 /* Plucked.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Plucked.h; sourceTree = "<group>"; };
+ 68CAAF53185456F100DB5318 /* PluckTwo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PluckTwo.h; sourceTree = "<group>"; };
+ 68CAAF54185456F100DB5318 /* PoleZero.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PoleZero.h; sourceTree = "<group>"; };
+ 68CAAF55185456F100DB5318 /* PRCRev.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PRCRev.h; sourceTree = "<group>"; };
+ 68CAAF56185456F100DB5318 /* ReedTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReedTable.h; sourceTree = "<group>"; };
+ 68CAAF57185456F100DB5318 /* Resonate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Resonate.h; sourceTree = "<group>"; };
+ 68CAAF58185456F100DB5318 /* Rhodey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Rhodey.h; sourceTree = "<group>"; };
+ 68CAAF59185456F100DB5318 /* Sampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Sampler.h; sourceTree = "<group>"; };
+ 68CAAF5A185456F100DB5318 /* Saxofony.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Saxofony.h; sourceTree = "<group>"; };
+ 68CAAF5B185456F100DB5318 /* Shakers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Shakers.h; sourceTree = "<group>"; };
+ 68CAAF5C185456F100DB5318 /* Simple.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Simple.h; sourceTree = "<group>"; };
+ 68CAAF5D185456F100DB5318 /* SineWave.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SineWave.h; sourceTree = "<group>"; };
+ 68CAAF5E185456F100DB5318 /* SingWave.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SingWave.h; sourceTree = "<group>"; };
+ 68CAAF5F185456F100DB5318 /* Sitar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Sitar.h; sourceTree = "<group>"; };
+ 68CAAF60185456F100DB5318 /* Skini.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Skini.h; sourceTree = "<group>"; };
+ 68CAAF61185456F100DB5318 /* Skini_msg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Skini_msg.h; sourceTree = "<group>"; };
+ 68CAAF62185456F100DB5318 /* Skini_tbl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Skini_tbl.h; sourceTree = "<group>"; };
+ 68CAAF63185456F100DB5318 /* Socket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Socket.h; sourceTree = "<group>"; };
+ 68CAAF64185456F100DB5318 /* Sphere.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Sphere.h; sourceTree = "<group>"; };
+ 68CAAF65185456F100DB5318 /* StifKarp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StifKarp.h; sourceTree = "<group>"; };
+ 68CAAF66185456F100DB5318 /* Stk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Stk.h; sourceTree = "<group>"; };
+ 68CAAF67185456F100DB5318 /* StkUdpSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StkUdpSocket.h; sourceTree = "<group>"; };
+ 68CAAF68185456F100DB5318 /* TapDelay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TapDelay.h; sourceTree = "<group>"; };
+ 68CAAF69185456F100DB5318 /* TcpClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TcpClient.h; sourceTree = "<group>"; };
+ 68CAAF6A185456F100DB5318 /* TcpServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TcpServer.h; sourceTree = "<group>"; };
+ 68CAAF6B185456F100DB5318 /* Thread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Thread.h; sourceTree = "<group>"; };
+ 68CAAF6C185456F100DB5318 /* TubeBell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TubeBell.h; sourceTree = "<group>"; };
+ 68CAAF6D185456F100DB5318 /* TwoPole.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TwoPole.h; sourceTree = "<group>"; };
+ 68CAAF6E185456F100DB5318 /* TwoZero.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TwoZero.h; sourceTree = "<group>"; };
+ 68CAAF6F185456F100DB5318 /* Vector3D.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Vector3D.h; sourceTree = "<group>"; };
+ 68CAAF70185456F100DB5318 /* Voicer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Voicer.h; sourceTree = "<group>"; };
+ 68CAAF71185456F100DB5318 /* VoicForm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VoicForm.h; sourceTree = "<group>"; };
+ 68CAAF72185456F100DB5318 /* Whistle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Whistle.h; sourceTree = "<group>"; };
+ 68CAAF73185456F100DB5318 /* Wurley.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Wurley.h; sourceTree = "<group>"; };
+ 68CAAF74185456F100DB5318 /* WvIn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WvIn.h; sourceTree = "<group>"; };
+ 68CAAF75185456F100DB5318 /* WvOut.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WvOut.h; sourceTree = "<group>"; };
+ 68CAAFA7185456F100DB5318 /* ADSR.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ADSR.cpp; sourceTree = "<group>"; };
+ 68CAAFA8185456F100DB5318 /* Asymp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Asymp.cpp; sourceTree = "<group>"; };
+ 68CAAFA9185456F100DB5318 /* BandedWG.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BandedWG.cpp; sourceTree = "<group>"; };
+ 68CAAFAA185456F100DB5318 /* BeeThree.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BeeThree.cpp; sourceTree = "<group>"; };
+ 68CAAFAB185456F100DB5318 /* BiQuad.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BiQuad.cpp; sourceTree = "<group>"; };
+ 68CAAFAC185456F100DB5318 /* Blit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Blit.cpp; sourceTree = "<group>"; };
+ 68CAAFAD185456F100DB5318 /* BlitSaw.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BlitSaw.cpp; sourceTree = "<group>"; };
+ 68CAAFAE185456F100DB5318 /* BlitSquare.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BlitSquare.cpp; sourceTree = "<group>"; };
+ 68CAAFAF185456F100DB5318 /* BlowBotl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BlowBotl.cpp; sourceTree = "<group>"; };
+ 68CAAFB0185456F100DB5318 /* BlowHole.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BlowHole.cpp; sourceTree = "<group>"; };
+ 68CAAFB1185456F100DB5318 /* Bowed.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Bowed.cpp; sourceTree = "<group>"; };
+ 68CAAFB2185456F100DB5318 /* Brass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Brass.cpp; sourceTree = "<group>"; };
+ 68CAAFB3185456F100DB5318 /* Chorus.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Chorus.cpp; sourceTree = "<group>"; };
+ 68CAAFB4185456F100DB5318 /* Clarinet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Clarinet.cpp; sourceTree = "<group>"; };
+ 68CAAFB5185456F100DB5318 /* Delay.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Delay.cpp; sourceTree = "<group>"; };
+ 68CAAFB6185456F100DB5318 /* DelayA.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DelayA.cpp; sourceTree = "<group>"; };
+ 68CAAFB7185456F100DB5318 /* DelayL.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DelayL.cpp; sourceTree = "<group>"; };
+ 68CAAFB8185456F100DB5318 /* Drummer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Drummer.cpp; sourceTree = "<group>"; };
+ 68CAAFB9185456F100DB5318 /* Echo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Echo.cpp; sourceTree = "<group>"; };
+ 68CAAFBA185456F100DB5318 /* Envelope.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Envelope.cpp; sourceTree = "<group>"; };
+ 68CAAFBB185456F100DB5318 /* FileLoop.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileLoop.cpp; sourceTree = "<group>"; };
+ 68CAAFBC185456F100DB5318 /* FileRead.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileRead.cpp; sourceTree = "<group>"; };
+ 68CAAFBD185456F100DB5318 /* FileWrite.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileWrite.cpp; sourceTree = "<group>"; };
+ 68CAAFBE185456F100DB5318 /* FileWvIn.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileWvIn.cpp; sourceTree = "<group>"; };
+ 68CAAFBF185456F100DB5318 /* FileWvOut.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileWvOut.cpp; sourceTree = "<group>"; };
+ 68CAAFC0185456F100DB5318 /* Fir.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Fir.cpp; sourceTree = "<group>"; };
+ 68CAAFC1185456F100DB5318 /* Flute.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Flute.cpp; sourceTree = "<group>"; };
+ 68CAAFC2185456F100DB5318 /* FM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FM.cpp; sourceTree = "<group>"; };
+ 68CAAFC3185456F100DB5318 /* FMVoices.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FMVoices.cpp; sourceTree = "<group>"; };
+ 68CAAFC4185456F100DB5318 /* FormSwep.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FormSwep.cpp; sourceTree = "<group>"; };
+ 68CAAFC5185456F100DB5318 /* Granulate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Granulate.cpp; sourceTree = "<group>"; };
+ 68CAAFC6185456F100DB5318 /* HevyMetl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HevyMetl.cpp; sourceTree = "<group>"; };
+ 68CAAFC7185456F100DB5318 /* Iir.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Iir.cpp; sourceTree = "<group>"; };
+ 68CAAFC8185456F100DB5318 /* InetWvIn.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InetWvIn.cpp; sourceTree = "<group>"; };
+ 68CAAFC9185456F100DB5318 /* InetWvOut.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InetWvOut.cpp; sourceTree = "<group>"; };
+ 68CAAFCA185456F100DB5318 /* JCRev.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JCRev.cpp; sourceTree = "<group>"; };
+ 68CAAFCB185456F100DB5318 /* LentPitShift.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LentPitShift.cpp; sourceTree = "<group>"; };
+ 68CAAFCC185456F100DB5318 /* Mandolin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Mandolin.cpp; sourceTree = "<group>"; };
+ 68CAAFCD185456F100DB5318 /* Mesh2D.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Mesh2D.cpp; sourceTree = "<group>"; };
+ 68CAAFCE185456F100DB5318 /* Messager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Messager.cpp; sourceTree = "<group>"; };
+ 68CAAFCF185456F100DB5318 /* MidiFileIn.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MidiFileIn.cpp; sourceTree = "<group>"; };
+ 68CAAFD0185456F100DB5318 /* Modal.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Modal.cpp; sourceTree = "<group>"; };
+ 68CAAFD1185456F100DB5318 /* ModalBar.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ModalBar.cpp; sourceTree = "<group>"; };
+ 68CAAFD2185456F100DB5318 /* Modulate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Modulate.cpp; sourceTree = "<group>"; };
+ 68CAAFD3185456F100DB5318 /* Moog.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Moog.cpp; sourceTree = "<group>"; };
+ 68CAAFD4185456F100DB5318 /* Mutex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Mutex.cpp; sourceTree = "<group>"; };
+ 68CAAFD5185456F100DB5318 /* Noise.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Noise.cpp; sourceTree = "<group>"; };
+ 68CAAFD6185456F100DB5318 /* NRev.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NRev.cpp; sourceTree = "<group>"; };
+ 68CAAFD7185456F100DB5318 /* OnePole.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OnePole.cpp; sourceTree = "<group>"; };
+ 68CAAFD8185456F100DB5318 /* OneZero.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OneZero.cpp; sourceTree = "<group>"; };
+ 68CAAFD9185456F100DB5318 /* PercFlut.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PercFlut.cpp; sourceTree = "<group>"; };
+ 68CAAFDA185456F100DB5318 /* Phonemes.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Phonemes.cpp; sourceTree = "<group>"; };
+ 68CAAFDB185456F100DB5318 /* PitShift.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PitShift.cpp; sourceTree = "<group>"; };
+ 68CAAFDC185456F100DB5318 /* Plucked.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Plucked.cpp; sourceTree = "<group>"; };
+ 68CAAFDD185456F100DB5318 /* PluckTwo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PluckTwo.cpp; sourceTree = "<group>"; };
+ 68CAAFDE185456F100DB5318 /* PoleZero.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PoleZero.cpp; sourceTree = "<group>"; };
+ 68CAAFDF185456F100DB5318 /* PRCRev.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PRCRev.cpp; sourceTree = "<group>"; };
+ 68CAAFE0185456F100DB5318 /* Resonate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Resonate.cpp; sourceTree = "<group>"; };
+ 68CAAFE1185456F100DB5318 /* Rhodey.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Rhodey.cpp; sourceTree = "<group>"; };
+ 68CAAFE2185456F100DB5318 /* Sampler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Sampler.cpp; sourceTree = "<group>"; };
+ 68CAAFE3185456F100DB5318 /* Saxofony.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Saxofony.cpp; sourceTree = "<group>"; };
+ 68CAAFE4185456F100DB5318 /* Shakers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Shakers.cpp; sourceTree = "<group>"; };
+ 68CAAFE5185456F100DB5318 /* Simple.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Simple.cpp; sourceTree = "<group>"; };
+ 68CAAFE6185456F100DB5318 /* SineWave.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SineWave.cpp; sourceTree = "<group>"; };
+ 68CAAFE7185456F100DB5318 /* SingWave.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SingWave.cpp; sourceTree = "<group>"; };
+ 68CAAFE8185456F100DB5318 /* Sitar.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Sitar.cpp; sourceTree = "<group>"; };
+ 68CAAFE9185456F100DB5318 /* Skini.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Skini.cpp; sourceTree = "<group>"; };
+ 68CAAFEA185456F100DB5318 /* Socket.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Socket.cpp; sourceTree = "<group>"; };
+ 68CAAFEB185456F100DB5318 /* Sphere.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Sphere.cpp; sourceTree = "<group>"; };
+ 68CAAFEC185456F100DB5318 /* StifKarp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StifKarp.cpp; sourceTree = "<group>"; };
+ 68CAAFED185456F100DB5318 /* Stk.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Stk.mm; sourceTree = "<group>"; };
+ 68CAAFEE185456F100DB5318 /* StkUdpSocket.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StkUdpSocket.cpp; sourceTree = "<group>"; };
+ 68CAAFEF185456F100DB5318 /* TapDelay.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TapDelay.cpp; sourceTree = "<group>"; };
+ 68CAAFF0185456F100DB5318 /* TcpClient.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TcpClient.cpp; sourceTree = "<group>"; };
+ 68CAAFF1185456F100DB5318 /* TcpServer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TcpServer.cpp; sourceTree = "<group>"; };
+ 68CAAFF2185456F100DB5318 /* Thread.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Thread.cpp; sourceTree = "<group>"; };
+ 68CAAFF3185456F100DB5318 /* TubeBell.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TubeBell.cpp; sourceTree = "<group>"; };
+ 68CAAFF4185456F100DB5318 /* TwoPole.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TwoPole.cpp; sourceTree = "<group>"; };
+ 68CAAFF5185456F100DB5318 /* TwoZero.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TwoZero.cpp; sourceTree = "<group>"; };
+ 68CAAFF6185456F100DB5318 /* Voicer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Voicer.cpp; sourceTree = "<group>"; };
+ 68CAAFF7185456F100DB5318 /* VoicForm.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VoicForm.cpp; sourceTree = "<group>"; };
+ 68CAAFF8185456F100DB5318 /* Whistle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Whistle.cpp; sourceTree = "<group>"; };
+ 68CAAFF9185456F100DB5318 /* Wurley.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Wurley.cpp; sourceTree = "<group>"; };
C725E000121DAC8F00FA186B /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; };
C727C02B121B400300192073 /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; };
C727C02D121B400300192073 /* CoreVideo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreVideo.framework; path = System/Library/Frameworks/CoreVideo.framework; sourceTree = SDKROOT; };
C7FB19D5124BC0D70045AFD2 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };
- 00748057165D41390024B57A /* assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = assets; path = ../assets; sourceTree = "<group>"; };
- 11CEB50DDC2D442F828EFE49 /* iosynthApp.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.cpp; path = ../src/iosynthApp.cpp; sourceTree = "<group>"; name = iosynthApp.cpp; };
- 359BF798F4294C6BB6836DC9 /* Resources.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ../include/Resources.h; sourceTree = "<group>"; name = Resources.h; };
- C9BCD27FE5CA496094E38DC7 /* CinderApp_ios.png */ = {isa = PBXFileReference; lastKnownFileType = "\"\""; path = ../resources/CinderApp_ios.png; sourceTree = "<group>"; name = CinderApp_ios.png; };
- 27664426CDC048598E09896C /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = "\"\""; path = "Default-568h@2x.png"; sourceTree = "<group>"; name = "Default-568h@2x.png"; };
- 3DCA5ADB4E5F41B8BC4AFF40 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; name = Info.plist; };
- 5F24CD9B8A5949E0B1828046 /* iosynth_Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = "\"\""; path = iosynth_Prefix.pch; sourceTree = "<group>"; name = iosynth_Prefix.pch; };
+ C9BCD27FE5CA496094E38DC7 /* CinderApp_ios.png */ = {isa = PBXFileReference; lastKnownFileType = "\"\""; name = CinderApp_ios.png; path = ../resources/CinderApp_ios.png; sourceTree = "<group>"; };
+ DDDDDF6A1138442D0091DDDD /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
00692BC414FF149000D0A05E = {
isa = PBXGroup;
children = (
- 99692BD914FF149000DFFFFF /* Blocks */,
+ 68CAAF0D185456CC00DB5318 /* lib */,
99692BD914FF149000D0A05F /* Headers */,
00692BD914FF149000D0A05E /* Source */,
00692BD914FF149000D0FFFF /* Resources */,
name = Frameworks;
sourceTree = "<group>";
};
- 99692BD914FF149000DFFFFF /* Blocks */ = {
+ 00692BD914FF149000D0A05E /* Source */ = {
isa = PBXGroup;
children = (
+ 11CEB50DDC2D442F828EFE49 /* iosynthApp.cpp */,
+ 68CAAF0918544B0700DB5318 /* iosynthApp.h */,
+ 68CAAF0A1854556E00DB5318 /* Voice.cpp */,
+ 68CAAF0B1854556E00DB5318 /* Voice.h */,
);
- name = Blocks;
+ name = Source;
sourceTree = "<group>";
};
- 99692BD914FF149000D0A05F /* Headers */ = {
+ 00692BD914FF149000D0FFFF /* Resources */ = {
isa = PBXGroup;
children = (
- 359BF798F4294C6BB6836DC9 /* Resources.h */,
- 5F24CD9B8A5949E0B1828046 /* iosynth_Prefix.pch */,
+ 00748057165D41390024B57A /* assets */,
+ C9BCD27FE5CA496094E38DC7 /* CinderApp_ios.png */,
+ 27664426CDC048598E09896C /* Default-568h@2x.png */,
+ 3DCA5ADB4E5F41B8BC4AFF40 /* Info.plist */,
);
- name = Headers;
+ name = Resources;
sourceTree = "<group>";
};
- 00692BD914FF149000D0A05E /* Source */ = {
+ 68CAAF0D185456CC00DB5318 /* lib */ = {
isa = PBXGroup;
children = (
- 11CEB50DDC2D442F828EFE49 /* iosynthApp.cpp */,
+ 68CAAF0E185456F000DB5318 /* Maximilian */,
+ 68CAAF11185456F000DB5318 /* MoMu-STK-1.0.0 */,
);
- name = Source;
+ name = lib;
sourceTree = "<group>";
};
- 00692BD914FF149000D0FFFF /* Resources */ = {
+ 68CAAF0E185456F000DB5318 /* Maximilian */ = {
isa = PBXGroup;
children = (
- 00748057165D41390024B57A /* assets */,
- C9BCD27FE5CA496094E38DC7 /* CinderApp_ios.png */,
- 27664426CDC048598E09896C /* Default-568h@2x.png */,
- 3DCA5ADB4E5F41B8BC4AFF40 /* Info.plist */,
+ 68CAAF0F185456F000DB5318 /* maximilian.cpp */,
+ 68CAAF10185456F000DB5318 /* maximilian.h */,
);
- name = Resources;
+ name = Maximilian;
+ path = ../lib/Maximilian;
+ sourceTree = "<group>";
+ };
+ 68CAAF11185456F000DB5318 /* MoMu-STK-1.0.0 */ = {
+ isa = PBXGroup;
+ children = (
+ 68CAAF15185456F000DB5318 /* include */,
+ 68CAAFA6185456F100DB5318 /* src */,
+ );
+ name = "MoMu-STK-1.0.0";
+ path = "../lib/MoMu-STK-1.0.0";
+ sourceTree = "<group>";
+ };
+ 68CAAF15185456F000DB5318 /* include */ = {
+ isa = PBXGroup;
+ children = (
+ 68CAAF16185456F000DB5318 /* ADSR.h */,
+ 68CAAF17185456F000DB5318 /* Asymp.h */,
+ 68CAAF18185456F000DB5318 /* BandedWG.h */,
+ 68CAAF19185456F000DB5318 /* BeeThree.h */,
+ 68CAAF1A185456F000DB5318 /* BiQuad.h */,
+ 68CAAF1B185456F000DB5318 /* Blit.h */,
+ 68CAAF1C185456F000DB5318 /* BlitSaw.h */,
+ 68CAAF1D185456F000DB5318 /* BlitSquare.h */,
+ 68CAAF1E185456F000DB5318 /* BlowBotl.h */,
+ 68CAAF1F185456F000DB5318 /* BlowHole.h */,
+ 68CAAF20185456F000DB5318 /* Bowed.h */,
+ 68CAAF21185456F000DB5318 /* BowTable.h */,
+ 68CAAF22185456F000DB5318 /* Brass.h */,
+ 68CAAF23185456F000DB5318 /* Chorus.h */,
+ 68CAAF24185456F000DB5318 /* Clarinet.h */,
+ 68CAAF25185456F000DB5318 /* Delay.h */,
+ 68CAAF26185456F000DB5318 /* DelayA.h */,
+ 68CAAF27185456F000DB5318 /* DelayL.h */,
+ 68CAAF28185456F000DB5318 /* Drummer.h */,
+ 68CAAF29185456F000DB5318 /* Echo.h */,
+ 68CAAF2A185456F000DB5318 /* Effect.h */,
+ 68CAAF2B185456F000DB5318 /* Envelope.h */,
+ 68CAAF2C185456F000DB5318 /* FileLoop.h */,
+ 68CAAF2D185456F000DB5318 /* FileRead.h */,
+ 68CAAF2E185456F000DB5318 /* FileWrite.h */,
+ 68CAAF2F185456F000DB5318 /* FileWvIn.h */,
+ 68CAAF30185456F000DB5318 /* FileWvOut.h */,
+ 68CAAF31185456F000DB5318 /* Filter.h */,
+ 68CAAF32185456F000DB5318 /* Fir.h */,
+ 68CAAF33185456F000DB5318 /* Flute.h */,
+ 68CAAF34185456F000DB5318 /* FM.h */,
+ 68CAAF35185456F000DB5318 /* FMVoices.h */,
+ 68CAAF36185456F000DB5318 /* FormSwep.h */,
+ 68CAAF37185456F000DB5318 /* Function.h */,
+ 68CAAF38185456F000DB5318 /* Generator.h */,
+ 68CAAF39185456F000DB5318 /* Granulate.h */,
+ 68CAAF3A185456F000DB5318 /* HevyMetl.h */,
+ 68CAAF3B185456F000DB5318 /* Iir.h */,
+ 68CAAF3C185456F000DB5318 /* InetWvIn.h */,
+ 68CAAF3D185456F000DB5318 /* InetWvOut.h */,
+ 68CAAF3E185456F000DB5318 /* Instrmnt.h */,
+ 68CAAF3F185456F000DB5318 /* JCRev.h */,
+ 68CAAF40185456F000DB5318 /* JetTable.h */,
+ 68CAAF41185456F000DB5318 /* LentPitShift.h */,
+ 68CAAF42185456F000DB5318 /* Mandolin.h */,
+ 68CAAF43185456F000DB5318 /* Mesh2D.h */,
+ 68CAAF44185456F000DB5318 /* Messager.h */,
+ 68CAAF45185456F000DB5318 /* MidiFileIn.h */,
+ 68CAAF46185456F000DB5318 /* Modal.h */,
+ 68CAAF47185456F000DB5318 /* ModalBar.h */,
+ 68CAAF48185456F000DB5318 /* Modulate.h */,
+ 68CAAF49185456F000DB5318 /* Moog.h */,
+ 68CAAF4A185456F000DB5318 /* Mutex.h */,
+ 68CAAF4B185456F000DB5318 /* Noise.h */,
+ 68CAAF4C185456F000DB5318 /* NRev.h */,
+ 68CAAF4D185456F000DB5318 /* OnePole.h */,
+ 68CAAF4E185456F000DB5318 /* OneZero.h */,
+ 68CAAF4F185456F000DB5318 /* PercFlut.h */,
+ 68CAAF50185456F000DB5318 /* Phonemes.h */,
+ 68CAAF51185456F000DB5318 /* PitShift.h */,
+ 68CAAF52185456F000DB5318 /* Plucked.h */,
+ 68CAAF53185456F100DB5318 /* PluckTwo.h */,
+ 68CAAF54185456F100DB5318 /* PoleZero.h */,
+ 68CAAF55185456F100DB5318 /* PRCRev.h */,
+ 68CAAF56185456F100DB5318 /* ReedTable.h */,
+ 68CAAF57185456F100DB5318 /* Resonate.h */,
+ 68CAAF58185456F100DB5318 /* Rhodey.h */,
+ 68CAAF59185456F100DB5318 /* Sampler.h */,
+ 68CAAF5A185456F100DB5318 /* Saxofony.h */,
+ 68CAAF5B185456F100DB5318 /* Shakers.h */,
+ 68CAAF5C185456F100DB5318 /* Simple.h */,
+ 68CAAF5D185456F100DB5318 /* SineWave.h */,
+ 68CAAF5E185456F100DB5318 /* SingWave.h */,
+ 68CAAF5F185456F100DB5318 /* Sitar.h */,
+ 68CAAF60185456F100DB5318 /* Skini.h */,
+ 68CAAF61185456F100DB5318 /* Skini_msg.h */,
+ 68CAAF62185456F100DB5318 /* Skini_tbl.h */,
+ 68CAAF63185456F100DB5318 /* Socket.h */,
+ 68CAAF64185456F100DB5318 /* Sphere.h */,
+ 68CAAF65185456F100DB5318 /* StifKarp.h */,
+ 68CAAF66185456F100DB5318 /* Stk.h */,
+ 68CAAF67185456F100DB5318 /* StkUdpSocket.h */,
+ 68CAAF68185456F100DB5318 /* TapDelay.h */,
+ 68CAAF69185456F100DB5318 /* TcpClient.h */,
+ 68CAAF6A185456F100DB5318 /* TcpServer.h */,
+ 68CAAF6B185456F100DB5318 /* Thread.h */,
+ 68CAAF6C185456F100DB5318 /* TubeBell.h */,
+ 68CAAF6D185456F100DB5318 /* TwoPole.h */,
+ 68CAAF6E185456F100DB5318 /* TwoZero.h */,
+ 68CAAF6F185456F100DB5318 /* Vector3D.h */,
+ 68CAAF70185456F100DB5318 /* Voicer.h */,
+ 68CAAF71185456F100DB5318 /* VoicForm.h */,
+ 68CAAF72185456F100DB5318 /* Whistle.h */,
+ 68CAAF73185456F100DB5318 /* Wurley.h */,
+ 68CAAF74185456F100DB5318 /* WvIn.h */,
+ 68CAAF75185456F100DB5318 /* WvOut.h */,
+ );
+ path = include;
+ sourceTree = "<group>";
+ };
+ 68CAAFA6185456F100DB5318 /* src */ = {
+ isa = PBXGroup;
+ children = (
+ 68CAAFA7185456F100DB5318 /* ADSR.cpp */,
+ 68CAAFA8185456F100DB5318 /* Asymp.cpp */,
+ 68CAAFA9185456F100DB5318 /* BandedWG.cpp */,
+ 68CAAFAA185456F100DB5318 /* BeeThree.cpp */,
+ 68CAAFAB185456F100DB5318 /* BiQuad.cpp */,
+ 68CAAFAC185456F100DB5318 /* Blit.cpp */,
+ 68CAAFAD185456F100DB5318 /* BlitSaw.cpp */,
+ 68CAAFAE185456F100DB5318 /* BlitSquare.cpp */,
+ 68CAAFAF185456F100DB5318 /* BlowBotl.cpp */,
+ 68CAAFB0185456F100DB5318 /* BlowHole.cpp */,
+ 68CAAFB1185456F100DB5318 /* Bowed.cpp */,
+ 68CAAFB2185456F100DB5318 /* Brass.cpp */,
+ 68CAAFB3185456F100DB5318 /* Chorus.cpp */,
+ 68CAAFB4185456F100DB5318 /* Clarinet.cpp */,
+ 68CAAFB5185456F100DB5318 /* Delay.cpp */,
+ 68CAAFB6185456F100DB5318 /* DelayA.cpp */,
+ 68CAAFB7185456F100DB5318 /* DelayL.cpp */,
+ 68CAAFB8185456F100DB5318 /* Drummer.cpp */,
+ 68CAAFB9185456F100DB5318 /* Echo.cpp */,
+ 68CAAFBA185456F100DB5318 /* Envelope.cpp */,
+ 68CAAFBB185456F100DB5318 /* FileLoop.cpp */,
+ 68CAAFBC185456F100DB5318 /* FileRead.cpp */,
+ 68CAAFBD185456F100DB5318 /* FileWrite.cpp */,
+ 68CAAFBE185456F100DB5318 /* FileWvIn.cpp */,
+ 68CAAFBF185456F100DB5318 /* FileWvOut.cpp */,
+ 68CAAFC0185456F100DB5318 /* Fir.cpp */,
+ 68CAAFC1185456F100DB5318 /* Flute.cpp */,
+ 68CAAFC2185456F100DB5318 /* FM.cpp */,
+ 68CAAFC3185456F100DB5318 /* FMVoices.cpp */,
+ 68CAAFC4185456F100DB5318 /* FormSwep.cpp */,
+ 68CAAFC5185456F100DB5318 /* Granulate.cpp */,
+ 68CAAFC6185456F100DB5318 /* HevyMetl.cpp */,
+ 68CAAFC7185456F100DB5318 /* Iir.cpp */,
+ 68CAAFC8185456F100DB5318 /* InetWvIn.cpp */,
+ 68CAAFC9185456F100DB5318 /* InetWvOut.cpp */,
+ 68CAAFCA185456F100DB5318 /* JCRev.cpp */,
+ 68CAAFCB185456F100DB5318 /* LentPitShift.cpp */,
+ 68CAAFCC185456F100DB5318 /* Mandolin.cpp */,
+ 68CAAFCD185456F100DB5318 /* Mesh2D.cpp */,
+ 68CAAFCE185456F100DB5318 /* Messager.cpp */,
+ 68CAAFCF185456F100DB5318 /* MidiFileIn.cpp */,
+ 68CAAFD0185456F100DB5318 /* Modal.cpp */,
+ 68CAAFD1185456F100DB5318 /* ModalBar.cpp */,
+ 68CAAFD2185456F100DB5318 /* Modulate.cpp */,
+ 68CAAFD3185456F100DB5318 /* Moog.cpp */,
+ 68CAAFD4185456F100DB5318 /* Mutex.cpp */,
+ 68CAAFD5185456F100DB5318 /* Noise.cpp */,
+ 68CAAFD6185456F100DB5318 /* NRev.cpp */,
+ 68CAAFD7185456F100DB5318 /* OnePole.cpp */,
+ 68CAAFD8185456F100DB5318 /* OneZero.cpp */,
+ 68CAAFD9185456F100DB5318 /* PercFlut.cpp */,
+ 68CAAFDA185456F100DB5318 /* Phonemes.cpp */,
+ 68CAAFDB185456F100DB5318 /* PitShift.cpp */,
+ 68CAAFDC185456F100DB5318 /* Plucked.cpp */,
+ 68CAAFDD185456F100DB5318 /* PluckTwo.cpp */,
+ 68CAAFDE185456F100DB5318 /* PoleZero.cpp */,
+ 68CAAFDF185456F100DB5318 /* PRCRev.cpp */,
+ 68CAAFE0185456F100DB5318 /* Resonate.cpp */,
+ 68CAAFE1185456F100DB5318 /* Rhodey.cpp */,
+ 68CAAFE2185456F100DB5318 /* Sampler.cpp */,
+ 68CAAFE3185456F100DB5318 /* Saxofony.cpp */,
+ 68CAAFE4185456F100DB5318 /* Shakers.cpp */,
+ 68CAAFE5185456F100DB5318 /* Simple.cpp */,
+ 68CAAFE6185456F100DB5318 /* SineWave.cpp */,
+ 68CAAFE7185456F100DB5318 /* SingWave.cpp */,
+ 68CAAFE8185456F100DB5318 /* Sitar.cpp */,
+ 68CAAFE9185456F100DB5318 /* Skini.cpp */,
+ 68CAAFEA185456F100DB5318 /* Socket.cpp */,
+ 68CAAFEB185456F100DB5318 /* Sphere.cpp */,
+ 68CAAFEC185456F100DB5318 /* StifKarp.cpp */,
+ 68CAAFED185456F100DB5318 /* Stk.mm */,
+ 68CAAFEE185456F100DB5318 /* StkUdpSocket.cpp */,
+ 68CAAFEF185456F100DB5318 /* TapDelay.cpp */,
+ 68CAAFF0185456F100DB5318 /* TcpClient.cpp */,
+ 68CAAFF1185456F100DB5318 /* TcpServer.cpp */,
+ 68CAAFF2185456F100DB5318 /* Thread.cpp */,
+ 68CAAFF3185456F100DB5318 /* TubeBell.cpp */,
+ 68CAAFF4185456F100DB5318 /* TwoPole.cpp */,
+ 68CAAFF5185456F100DB5318 /* TwoZero.cpp */,
+ 68CAAFF6185456F100DB5318 /* Voicer.cpp */,
+ 68CAAFF7185456F100DB5318 /* VoicForm.cpp */,
+ 68CAAFF8185456F100DB5318 /* Whistle.cpp */,
+ 68CAAFF9185456F100DB5318 /* Wurley.cpp */,
+ );
+ path = src;
+ sourceTree = "<group>";
+ };
+ 99692BD914FF149000D0A05F /* Headers */ = {
+ isa = PBXGroup;
+ children = (
+ 359BF798F4294C6BB6836DC9 /* Resources.h */,
+ 5F24CD9B8A5949E0B1828046 /* iosynth_Prefix.pch */,
+ );
+ name = Headers;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXProject section */
00692BC614FF149000D0A05E /* Project object */ = {
isa = PBXProject;
+ attributes = {
+ };
buildConfigurationList = 00692BC914FF149000D0A05E /* Build configuration list for PBXProject "iosynth" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ 68CAB035185456F100DB5318 /* BlitSaw.cpp in Sources */,
+ 68CAB062185456F100DB5318 /* Phonemes.cpp in Sources */,
+ 68CAAF0C1854556E00DB5318 /* Voice.cpp in Sources */,
+ 68CAB03A185456F100DB5318 /* Brass.cpp in Sources */,
+ 68CAB048185456F100DB5318 /* Fir.cpp in Sources */,
+ 68CAB04F185456F100DB5318 /* Iir.cpp in Sources */,
+ 68CAB050185456F100DB5318 /* InetWvIn.cpp in Sources */,
+ 68CAB06D185456F100DB5318 /* Simple.cpp in Sources */,
+ 68CAB047185456F100DB5318 /* FileWvOut.cpp in Sources */,
+ 68CAB06F185456F100DB5318 /* SingWave.cpp in Sources */,
+ 68CAB06C185456F100DB5318 /* Shakers.cpp in Sources */,
+ 68CAB065185456F100DB5318 /* PluckTwo.cpp in Sources */,
+ 68CAB053185456F100DB5318 /* LentPitShift.cpp in Sources */,
+ 68CAB037185456F100DB5318 /* BlowBotl.cpp in Sources */,
+ 68CAB073185456F100DB5318 /* Sphere.cpp in Sources */,
+ 68CAB033185456F100DB5318 /* BiQuad.cpp in Sources */,
+ 68CAB05C185456F100DB5318 /* Mutex.cpp in Sources */,
+ 68CAB067185456F100DB5318 /* PRCRev.cpp in Sources */,
+ 68CAB03C185456F100DB5318 /* Clarinet.cpp in Sources */,
+ 68CAB03F185456F100DB5318 /* DelayL.cpp in Sources */,
+ 68CAB072185456F100DB5318 /* Socket.cpp in Sources */,
+ 68CAB070185456F100DB5318 /* Sitar.cpp in Sources */,
+ 68CAB044185456F100DB5318 /* FileRead.cpp in Sources */,
+ 68CAB049185456F100DB5318 /* Flute.cpp in Sources */,
+ 68CAB068185456F100DB5318 /* Resonate.cpp in Sources */,
+ 68CAB04C185456F100DB5318 /* FormSwep.cpp in Sources */,
+ 68CAB07F185456F100DB5318 /* VoicForm.cpp in Sources */,
+ 68CAB05B185456F100DB5318 /* Moog.cpp in Sources */,
+ 68CAB036185456F100DB5318 /* BlitSquare.cpp in Sources */,
+ 68CAB055185456F100DB5318 /* Mesh2D.cpp in Sources */,
+ 68CAB042185456F100DB5318 /* Envelope.cpp in Sources */,
+ 68CAB04B185456F100DB5318 /* FMVoices.cpp in Sources */,
+ 68CAB064185456F100DB5318 /* Plucked.cpp in Sources */,
+ 68CAB03B185456F100DB5318 /* Chorus.cpp in Sources */,
+ 68CAB03E185456F100DB5318 /* DelayA.cpp in Sources */,
+ 68CAB04E185456F100DB5318 /* HevyMetl.cpp in Sources */,
+ 68CAB030185456F100DB5318 /* Asymp.cpp in Sources */,
+ 68CAB032185456F100DB5318 /* BeeThree.cpp in Sources */,
+ 68CAB057185456F100DB5318 /* MidiFileIn.cpp in Sources */,
+ 68CAB051185456F100DB5318 /* InetWvOut.cpp in Sources */,
+ 68CAB054185456F100DB5318 /* Mandolin.cpp in Sources */,
+ 68CAB031185456F100DB5318 /* BandedWG.cpp in Sources */,
+ 68CAB056185456F100DB5318 /* Messager.cpp in Sources */,
+ 68CAB061185456F100DB5318 /* PercFlut.cpp in Sources */,
+ 68CAB039185456F100DB5318 /* Bowed.cpp in Sources */,
+ 68CAB03D185456F100DB5318 /* Delay.cpp in Sources */,
+ 68CAB06B185456F100DB5318 /* Saxofony.cpp in Sources */,
+ 68CAB069185456F100DB5318 /* Rhodey.cpp in Sources */,
+ 68CAB07B185456F100DB5318 /* TubeBell.cpp in Sources */,
+ 68CAB078185456F100DB5318 /* TcpClient.cpp in Sources */,
+ 68CAB05D185456F100DB5318 /* Noise.cpp in Sources */,
+ 68CAB040185456F100DB5318 /* Drummer.cpp in Sources */,
+ 68CAB02F185456F100DB5318 /* ADSR.cpp in Sources */,
+ 68CAB075185456F100DB5318 /* Stk.mm in Sources */,
+ 68CAB058185456F100DB5318 /* Modal.cpp in Sources */,
+ 68CAB07E185456F100DB5318 /* Voicer.cpp in Sources */,
+ 68CAB05A185456F100DB5318 /* Modulate.cpp in Sources */,
+ 68CAB081185456F100DB5318 /* Wurley.cpp in Sources */,
+ 68CAB052185456F100DB5318 /* JCRev.cpp in Sources */,
+ 68CAB066185456F100DB5318 /* PoleZero.cpp in Sources */,
+ 68CAB045185456F100DB5318 /* FileWrite.cpp in Sources */,
+ 68CAB038185456F100DB5318 /* BlowHole.cpp in Sources */,
+ 68CAB071185456F100DB5318 /* Skini.cpp in Sources */,
+ 68CAB080185456F100DB5318 /* Whistle.cpp in Sources */,
+ 68CAB059185456F100DB5318 /* ModalBar.cpp in Sources */,
+ 68CAB076185456F100DB5318 /* StkUdpSocket.cpp in Sources */,
3280A26996EF49D98A7F86C6 /* iosynthApp.cpp in Sources */,
+ 68CAB05F185456F100DB5318 /* OnePole.cpp in Sources */,
+ 68CAB07A185456F100DB5318 /* Thread.cpp in Sources */,
+ 68CAB077185456F100DB5318 /* TapDelay.cpp in Sources */,
+ 68CAB06E185456F100DB5318 /* SineWave.cpp in Sources */,
+ 68CAB07D185456F100DB5318 /* TwoZero.cpp in Sources */,
+ 68CAAFFC185456F100DB5318 /* maximilian.cpp in Sources */,
+ 68CAB04D185456F100DB5318 /* Granulate.cpp in Sources */,
+ 68CAB046185456F100DB5318 /* FileWvIn.cpp in Sources */,
+ 68CAB05E185456F100DB5318 /* NRev.cpp in Sources */,
+ 68CAB079185456F100DB5318 /* TcpServer.cpp in Sources */,
+ 68CAB04A185456F100DB5318 /* FM.cpp in Sources */,
+ 68CAB041185456F100DB5318 /* Echo.cpp in Sources */,
+ 68CAB063185456F100DB5318 /* PitShift.cpp in Sources */,
+ 68CAB07C185456F100DB5318 /* TwoPole.cpp in Sources */,
+ 68CAB074185456F100DB5318 /* StifKarp.cpp in Sources */,
+ 68CAB034185456F100DB5318 /* Blit.cpp in Sources */,
+ 68CAB06A185456F100DB5318 /* Sampler.cpp in Sources */,
+ 68CAB060185456F100DB5318 /* OneZero.cpp in Sources */,
+ 68CAB043185456F100DB5318 /* FileLoop.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
00692BF314FF149000D0A05E /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
- DEAD_CODE_STRIPPING = YES;
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ CINDER_PATH = ../../../Cinder;
CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
CLANG_CXX_LIBRARY = "libc++";
- ARCHS = "$(ARCHS_STANDARD_32_BIT)";
- ALWAYS_SEARCH_USER_PATHS = NO;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
+ DEAD_CODE_STRIPPING = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = "\"$(CINDER_PATH)/boost\"";
IPHONEOS_DEPLOYMENT_TARGET = 5.0;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
- CINDER_PATH = "../../../Cinder";
- HEADER_SEARCH_PATHS = "\"$(CINDER_PATH)/boost\"";
USER_HEADER_SEARCH_PATHS = "\"$(CINDER_PATH)/include\" ../include";
};
name = Debug;
00692BF414FF149000D0A05E /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
- DEAD_CODE_STRIPPING = YES;
- CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
- CLANG_CXX_LIBRARY = "libc++";
ALWAYS_SEARCH_USER_PATHS = NO;
ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ CINDER_PATH = ../../../Cinder;
+ CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
+ CLANG_CXX_LIBRARY = "libc++";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = YES;
+ DEAD_CODE_STRIPPING = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = "\"$(CINDER_PATH)/boost\"";
IPHONEOS_DEPLOYMENT_TARGET = 5.0;
OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1";
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
- VALIDATE_PRODUCT = YES;
- CINDER_PATH = "../../../Cinder";
- HEADER_SEARCH_PATHS = "\"$(CINDER_PATH)/boost\"";
USER_HEADER_SEARCH_PATHS = "\"$(CINDER_PATH)/include\" ../include";
+ VALIDATE_PRODUCT = YES;
};
name = Release;
};
isa = XCBuildConfiguration;
buildSettings = {
GCC_PRECOMPILE_PREFIX_HEADER = YES;
- GCC_PREFIX_HEADER = "iosynth_Prefix.pch";
- INFOPLIST_FILE = "Info.plist";
- PRODUCT_NAME = "$(TARGET_NAME)";
- WRAPPER_EXTENSION = app;
+ GCC_PREFIX_HEADER = iosynth_Prefix.pch;
+ INFOPLIST_FILE = Info.plist;
"OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = (
"\"$(CINDER_PATH)/lib/libcinder-iphone_d.a\"",
"-lz",
"\"$(CINDER_PATH)/lib/libcinder-iphone-sim_d.a\"",
"-lz",
);
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ WRAPPER_EXTENSION = app;
};
name = Debug;
};
isa = XCBuildConfiguration;
buildSettings = {
GCC_PRECOMPILE_PREFIX_HEADER = YES;
- GCC_PREFIX_HEADER = "iosynth_Prefix.pch";
- INFOPLIST_FILE = "Info.plist";
- PRODUCT_NAME = "$(TARGET_NAME)";
- WRAPPER_EXTENSION = app;
+ GCC_PREFIX_HEADER = iosynth_Prefix.pch;
+ INFOPLIST_FILE = Info.plist;
"OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = (
"\"$(CINDER_PATH)/lib/libcinder-iphone.a\"",
"-lz",
"\"$(CINDER_PATH)/lib/libcinder-iphone-sim.a\"",
"-lz",
);
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ WRAPPER_EXTENSION = app;
};
name = Release;
};