From: Gabriel Dunne Date: Mon, 9 Dec 2013 02:32:19 +0000 (-0800) Subject: Compiling X-Git-Url: https://git.quilime.com/?a=commitdiff_plain;h=00b78ba1840dc6ff73b9fffd329299927f45f7a5;p=iosynth.git Compiling --- diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e43b0f9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.DS_Store diff --git a/lib/Maximilian/maximilian.cpp b/lib/Maximilian/maximilian.cpp new file mode 100644 index 0000000..9537096 --- /dev/null +++ b/lib/Maximilian/maximilian.cpp @@ -0,0 +1,1270 @@ + +/* + * 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 (phaseduty) 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= 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(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;i1) { + int position=0; + int channel=readChannel*2; + for (int i=channel;i=0) { + + if ((long) position>=length-1) position=1; + 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= end ) pos = start; + 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= 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 (positionstart && 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=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= end ) position = start; + 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= 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 (positionstart && 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 (holdcount0.) { + 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) { + 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 (holdcount0.) { + 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 (holdcount0.) { + 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 ) ); +} + diff --git a/lib/Maximilian/maximilian.h b/lib/Maximilian/maximilian.h new file mode 100755 index 0000000..0cac59d --- /dev/null +++ b/lib/Maximilian/maximilian.h @@ -0,0 +1,501 @@ +/* + * 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 +#include +#include +#include +#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 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 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 diff --git a/lib/MoMu-STK-1.0.0/AUTHORS b/lib/MoMu-STK-1.0.0/AUTHORS new file mode 100644 index 0000000..8a9da28 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/AUTHORS @@ -0,0 +1,32 @@ +--- +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/ + diff --git a/lib/MoMu-STK-1.0.0/COPYING b/lib/MoMu-STK-1.0.0/COPYING new file mode 100644 index 0000000..f066b0f --- /dev/null +++ b/lib/MoMu-STK-1.0.0/COPYING @@ -0,0 +1 @@ +See README \ No newline at end of file diff --git a/lib/MoMu-STK-1.0.0/DEVELOPER b/lib/MoMu-STK-1.0.0/DEVELOPER new file mode 100644 index 0000000..22e5ce6 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/DEVELOPER @@ -0,0 +1,6 @@ +--- +Please check out the MoMu STK and toolkit page: + + http://momu.stanford.edu/stk/ + http://momu.stanford.edu/toolkit/ +--- diff --git a/lib/MoMu-STK-1.0.0/INSTALL b/lib/MoMu-STK-1.0.0/INSTALL new file mode 100644 index 0000000..66f7a13 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/INSTALL @@ -0,0 +1,11 @@ +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 diff --git a/lib/MoMu-STK-1.0.0/README b/lib/MoMu-STK-1.0.0/README new file mode 100644 index 0000000..ff3432e --- /dev/null +++ b/lib/MoMu-STK-1.0.0/README @@ -0,0 +1,232 @@ +----------------------------------------------------------------------- +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 . . . + + + + diff --git a/lib/MoMu-STK-1.0.0/TODO b/lib/MoMu-STK-1.0.0/TODO new file mode 100644 index 0000000..4825436 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/TODO @@ -0,0 +1 @@ +- Connect MoAudio (from MoMu) to RtWvIn.h/cpp and RtWvOut.h/cpp \ No newline at end of file diff --git a/lib/MoMu-STK-1.0.0/VERSIONS b/lib/MoMu-STK-1.0.0/VERSIONS new file mode 100644 index 0000000..4428418 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/VERSIONS @@ -0,0 +1,18 @@ +--- +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 + diff --git a/lib/MoMu-STK-1.0.0/include/ADSR.h b/lib/MoMu-STK-1.0.0/include/ADSR.h new file mode 100644 index 0000000..de6cb02 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/ADSR.h @@ -0,0 +1,163 @@ +#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 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 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 diff --git a/lib/MoMu-STK-1.0.0/include/BiQuad.h b/lib/MoMu-STK-1.0.0/include/BiQuad.h new file mode 100644 index 0000000..19cf61c --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/BiQuad.h @@ -0,0 +1,183 @@ +#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= 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 +#include + +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::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 +#include + +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::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 +#include + +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::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 + +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 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 1.0) *oSamples = 1.0; + } + + lastFrame_[0] = *(oSamples-oHop); + return iFrames; +} + +} // stk namespace + +#endif diff --git a/lib/MoMu-STK-1.0.0/include/Bowed.h b/lib/MoMu-STK-1.0.0/include/Bowed.h new file mode 100644 index 0000000..4d36967 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/Bowed.h @@ -0,0 +1,112 @@ +#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 diff --git a/lib/MoMu-STK-1.0.0/include/Brass.h b/lib/MoMu-STK-1.0.0/include/Brass.h new file mode 100644 index 0000000..1892c73 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/Brass.h @@ -0,0 +1,110 @@ +#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 diff --git a/lib/MoMu-STK-1.0.0/include/Chorus.h b/lib/MoMu-STK-1.0.0/include/Chorus.h new file mode 100644 index 0000000..5258cca --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/Chorus.h @@ -0,0 +1,168 @@ +#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= 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= 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= 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= 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= 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= 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= 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 soundOrder_; + std::vector soundNumber_; + int nSounding_; +}; + +inline StkFloat Drummer :: tick( unsigned int ) +{ + lastFrame_[0] = 0.0; + if ( nSounding_ == 0 ) return lastFrame_[0]; + + for ( int i=0; i= 0 ) { + if ( waves_[i].isFinished() ) { + // Re-order the list. + for ( int j=0; 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 diff --git a/lib/MoMu-STK-1.0.0/include/Echo.h b/lib/MoMu-STK-1.0.0/include/Echo.h new file mode 100644 index 0000000..473bd40 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/Echo.h @@ -0,0 +1,120 @@ +#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= 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 + +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 + diff --git a/lib/MoMu-STK-1.0.0/include/Envelope.h b/lib/MoMu-STK-1.0.0/include/Envelope.h new file mode 100644 index 0000000..358a7e8 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/Envelope.h @@ -0,0 +1,162 @@ +#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 adsr_; + std::vector waves_; + SineWave vibrato_; + TwoZero twozero_; + unsigned int nOperators_; + StkFloat baseFrequency_; + std::vector ratios_; + std::vector gains_; + StkFloat modDepth_; + StkFloat control1_; + StkFloat control2_; + StkFloat fmGains_[100]; + StkFloat fmSusLevels_[16]; + StkFloat fmAttTimes_[32]; + +}; + +} // stk namespace + +#endif diff --git a/lib/MoMu-STK-1.0.0/include/FMVoices.h b/lib/MoMu-STK-1.0.0/include/FMVoices.h new file mode 100644 index 0000000..5f5416e --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/FMVoices.h @@ -0,0 +1,98 @@ +#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 diff --git a/lib/MoMu-STK-1.0.0/include/FileLoop.h b/lib/MoMu-STK-1.0.0/include/FileLoop.h new file mode 100644 index 0000000..e93011a --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/FileLoop.h @@ -0,0 +1,161 @@ +#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 diff --git a/lib/MoMu-STK-1.0.0/include/FileRead.h b/lib/MoMu-STK-1.0.0/include/FileRead.h new file mode 100644 index 0000000..967572d --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/FileRead.h @@ -0,0 +1,133 @@ +#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 diff --git a/lib/MoMu-STK-1.0.0/include/FileWrite.h b/lib/MoMu-STK-1.0.0/include/FileWrite.h new file mode 100644 index 0000000..1692216 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/FileWrite.h @@ -0,0 +1,116 @@ +#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 diff --git a/lib/MoMu-STK-1.0.0/include/FileWvIn.h b/lib/MoMu-STK-1.0.0/include/FileWvIn.h new file mode 100644 index 0000000..64b782b --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/FileWvIn.h @@ -0,0 +1,193 @@ +#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 diff --git a/lib/MoMu-STK-1.0.0/include/FileWvOut.h b/lib/MoMu-STK-1.0.0/include/FileWvOut.h new file mode 100644 index 0000000..e6bf5ae --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/FileWvOut.h @@ -0,0 +1,102 @@ +#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 diff --git a/lib/MoMu-STK-1.0.0/include/Filter.h b/lib/MoMu-STK-1.0.0/include/Filter.h new file mode 100644 index 0000000..79963de --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/Filter.h @@ -0,0 +1,86 @@ +#ifndef STK_FILTER_H +#define STK_FILTER_H + +#include "Stk.h" +#include + +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 b_; + std::vector a_; + StkFrames outputs_; + StkFrames inputs_; + +}; + +inline void Filter :: clear( void ) +{ + unsigned int i; + for ( i=0; i &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 &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; j0; 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; j0; 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 diff --git a/lib/MoMu-STK-1.0.0/include/Flute.h b/lib/MoMu-STK-1.0.0/include/Flute.h new file mode 100644 index 0000000..ca7549d --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/Flute.h @@ -0,0 +1,129 @@ +#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 diff --git a/lib/MoMu-STK-1.0.0/include/FormSwep.h b/lib/MoMu-STK-1.0.0/include/FormSwep.h new file mode 100644 index 0000000..6155425 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/FormSwep.h @@ -0,0 +1,188 @@ +#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= 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 +#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 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; i2-- + -->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 diff --git a/lib/MoMu-STK-1.0.0/include/Iir.h b/lib/MoMu-STK-1.0.0/include/Iir.h new file mode 100644 index 0000000..28f9b47 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/Iir.h @@ -0,0 +1,202 @@ +#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 &bCoefficients, std::vector &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 &bCoefficients, std::vector &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 &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 &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; j0; 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; j0; 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 diff --git a/lib/MoMu-STK-1.0.0/include/InetWvIn.h b/lib/MoMu-STK-1.0.0/include/InetWvIn.h new file mode 100644 index 0000000..911c056 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/InetWvIn.h @@ -0,0 +1,157 @@ +#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 diff --git a/lib/MoMu-STK-1.0.0/include/InetWvOut.h b/lib/MoMu-STK-1.0.0/include/InetWvOut.h new file mode 100644 index 0000000..cf10786 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/InetWvOut.h @@ -0,0 +1,98 @@ +#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 diff --git a/lib/MoMu-STK-1.0.0/include/Instrmnt.h b/lib/MoMu-STK-1.0.0/include/Instrmnt.h new file mode 100644 index 0000000..6887b60 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/Instrmnt.h @@ -0,0 +1,129 @@ +#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 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 + diff --git a/lib/MoMu-STK-1.0.0/include/JetTable.h b/lib/MoMu-STK-1.0.0/include/JetTable.h new file mode 100644 index 0000000..73acc57 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/JetTable.h @@ -0,0 +1,112 @@ +#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 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 1.0) *oSamples = 1.0; + if ( *oSamples < -1.0) *oSamples = -1.0; + } + + lastFrame_[0] = *(oSamples-oHop); + return iFrames; +} + +} // stk namespace + +#endif diff --git a/lib/MoMu-STK-1.0.0/include/LentPitShift.h b/lib/MoMu-STK-1.0.0/include/LentPitShift.h new file mode 100644 index 0000000..f2a535f --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/LentPitShift.h @@ -0,0 +1,267 @@ +#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 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= 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; itick() * 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 diff --git a/lib/MoMu-STK-1.0.0/include/Mesh2D.h b/lib/MoMu-STK-1.0.0/include/Mesh2D.h new file mode 100644 index 0000000..91b83e4 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/Mesh2D.h @@ -0,0 +1,107 @@ +#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 diff --git a/lib/MoMu-STK-1.0.0/include/Messager.h b/lib/MoMu-STK-1.0.0/include/Messager.h new file mode 100644 index 0000000..a6fa0e4 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/Messager.h @@ -0,0 +1,166 @@ +#ifndef STK_MESSAGER_H +#define STK_MESSAGER_H + +#include "Stk.h" +#include "Skini.h" +#include + +#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 queue; + unsigned int queueLimit; + int sources; + +#if defined(__STK_REALTIME__) + Mutex mutex; + RtMidiIn *midi; + TcpServer *socket; + std::vector 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 diff --git a/lib/MoMu-STK-1.0.0/include/MidiFileIn.h b/lib/MoMu-STK-1.0.0/include/MidiFileIn.h new file mode 100644 index 0000000..9758a12 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/MidiFileIn.h @@ -0,0 +1,135 @@ +#ifndef STK_MIDIFILEIN_H +#define STK_MIDIFILEIN_H + +#include "Stk.h" +#include +#include +#include +#include + +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 *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 *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 tickSeconds_; + std::vector trackPointers_; + std::vector trackOffsets_; + std::vector trackLengths_; + std::vector 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 tempoEvents_; + std::vector trackCounters_; + std::vector trackTempoIndex_; +}; + +} // stk namespace + +#endif diff --git a/lib/MoMu-STK-1.0.0/include/Modal.h b/lib/MoMu-STK-1.0.0/include/Modal.h new file mode 100644 index 0000000..eba0008 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/Modal.h @@ -0,0 +1,117 @@ +#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 ratios_; + std::vector 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; itick(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 diff --git a/lib/MoMu-STK-1.0.0/include/ModalBar.h b/lib/MoMu-STK-1.0.0/include/ModalBar.h new file mode 100644 index 0000000..a61cee8 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/ModalBar.h @@ -0,0 +1,65 @@ +#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 diff --git a/lib/MoMu-STK-1.0.0/include/Modulate.h b/lib/MoMu-STK-1.0.0/include/Modulate.h new file mode 100644 index 0000000..1b77c9c --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/Modulate.h @@ -0,0 +1,108 @@ +#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; isetFrequency( 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 diff --git a/lib/MoMu-STK-1.0.0/include/Mutex.h b/lib/MoMu-STK-1.0.0/include/Mutex.h new file mode 100644 index 0000000..57ec712 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/Mutex.h @@ -0,0 +1,74 @@ +#ifndef STK_MUTEX_H +#define STK_MUTEX_H + +#include "Stk.h" + +#if (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__)) + + #include + typedef pthread_mutex_t MUTEX; + typedef pthread_cond_t CONDITION; + +#elif defined(__OS_WINDOWS__) + + #include + #include + 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 diff --git a/lib/MoMu-STK-1.0.0/include/NRev.h b/lib/MoMu-STK-1.0.0/include/NRev.h new file mode 100644 index 0000000..43933d1 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/NRev.h @@ -0,0 +1,160 @@ +#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 + diff --git a/lib/MoMu-STK-1.0.0/include/Noise.h b/lib/MoMu-STK-1.0.0/include/Noise.h new file mode 100644 index 0000000..12ecc18 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/Noise.h @@ -0,0 +1,83 @@ +#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.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= 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= 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= 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 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 + diff --git a/lib/MoMu-STK-1.0.0/include/PercFlut.h b/lib/MoMu-STK-1.0.0/include/PercFlut.h new file mode 100644 index 0000000..326d55c --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/PercFlut.h @@ -0,0 +1,90 @@ +#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 diff --git a/lib/MoMu-STK-1.0.0/include/Phonemes.h b/lib/MoMu-STK-1.0.0/include/Phonemes.h new file mode 100644 index 0000000..9b7a084 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/Phonemes.h @@ -0,0 +1,54 @@ +#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 diff --git a/lib/MoMu-STK-1.0.0/include/PitShift.h b/lib/MoMu-STK-1.0.0/include/PitShift.h new file mode 100644 index 0000000..a1551a2 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/PitShift.h @@ -0,0 +1,107 @@ +#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 + diff --git a/lib/MoMu-STK-1.0.0/include/PluckTwo.h b/lib/MoMu-STK-1.0.0/include/PluckTwo.h new file mode 100644 index 0000000..d39fe6a --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/PluckTwo.h @@ -0,0 +1,89 @@ +#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 diff --git a/lib/MoMu-STK-1.0.0/include/Plucked.h b/lib/MoMu-STK-1.0.0/include/Plucked.h new file mode 100644 index 0000000..ec3860b --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/Plucked.h @@ -0,0 +1,78 @@ +#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 + diff --git a/lib/MoMu-STK-1.0.0/include/PoleZero.h b/lib/MoMu-STK-1.0.0/include/PoleZero.h new file mode 100644 index 0000000..b0299b1 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/PoleZero.h @@ -0,0 +1,112 @@ +#ifndef STK_POLEZERO_H +#define STK_POLEZERO_H + +#include "Filter.h" + +namespace stk { + +/***************************************************/ +/*! \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. +*/ +/***************************************************/ + +class PoleZero : public Filter +{ + public: + + //! Default constructor creates a first-order pass-through filter. + PoleZero(); + + //! Class destructor. + ~PoleZero(); + + //! 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 a[1] coefficient value. + void setA1( StkFloat a1 ) { a_[1] = a1; }; + + //! Set all filter coefficients. + void setCoefficients( StkFloat b0, StkFloat b1, StkFloat a1, bool clearState = false ); + + //! Set the filter for allpass behavior using \e coefficient. + /*! + This method uses \e coefficient to create an allpass filter, + which has unity gain at all frequencies. Note that the \e + coefficient magnitude must be less than one to maintain stability. + */ + void setAllpass( StkFloat coefficient ); + + //! Create a DC blocking filter with the given pole position in the z-plane. + /*! + This method sets the given pole position, together with a zero + at z=1, to create a DC blocking filter. \e thePole should be + close to one to minimize low-frequency attenuation. + + */ + void setBlockZero( StkFloat thePole = 0.99 ); + + //! 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 \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 ); + +}; + +inline StkFloat PoleZero :: tick( StkFloat input ) +{ + inputs_[0] = gain_ * input; + lastFrame_[0] = b_[0] * inputs_[0] + b_[1] * inputs_[1] - a_[1] * outputs_[1]; + inputs_[1] = inputs_[0]; + outputs_[1] = lastFrame_[0]; + + return lastFrame_[0]; +} + +inline StkFrames& PoleZero :: tick( StkFrames& frames, unsigned int channel ) +{ +#if defined(_STK_DEBUG_) + if ( channel >= frames.channels() ) { + errorString_ << "PoleZero::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 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 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 1.0) *oSamples = 1.0; + if ( *oSamples < -1.0) *oSamples = -1.0; + } + + lastFrame_[0] = *(oSamples-oHop); + return iFrames; +} + +} // stk namespace + +#endif diff --git a/lib/MoMu-STK-1.0.0/include/Resonate.h b/lib/MoMu-STK-1.0.0/include/Resonate.h new file mode 100644 index 0000000..0627eb1 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/Resonate.h @@ -0,0 +1,90 @@ +#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 diff --git a/lib/MoMu-STK-1.0.0/include/Rhodey.h b/lib/MoMu-STK-1.0.0/include/Rhodey.h new file mode 100644 index 0000000..dce9f8e --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/Rhodey.h @@ -0,0 +1,91 @@ +#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 diff --git a/lib/MoMu-STK-1.0.0/include/Sampler.h b/lib/MoMu-STK-1.0.0/include/Sampler.h new file mode 100644 index 0000000..be6d2d8 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/Sampler.h @@ -0,0 +1,68 @@ +#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 attacks_; + std::vector loops_; + OnePole filter_; + StkFloat baseFrequency_; + std::vector attackRatios_; + std::vector loopRatios_; + StkFloat attackGain_; + StkFloat loopGain_; + +}; + +} // stk namespace + +#endif diff --git a/lib/MoMu-STK-1.0.0/include/Saxofony.h b/lib/MoMu-STK-1.0.0/include/Saxofony.h new file mode 100644 index 0000000..45f33b8 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/Saxofony.h @@ -0,0 +1,129 @@ +#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 diff --git a/lib/MoMu-STK-1.0.0/include/Shakers.h b/lib/MoMu-STK-1.0.0/include/Shakers.h new file mode 100644 index 0000000..dcad1eb --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/Shakers.h @@ -0,0 +1,131 @@ +#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 diff --git a/lib/MoMu-STK-1.0.0/include/Simple.h b/lib/MoMu-STK-1.0.0/include/Simple.h new file mode 100644 index 0000000..b2aeea7 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/Simple.h @@ -0,0 +1,92 @@ +#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 diff --git a/lib/MoMu-STK-1.0.0/include/SineWave.h b/lib/MoMu-STK-1.0.0/include/SineWave.h new file mode 100644 index 0000000..cb7785f --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/SineWave.h @@ -0,0 +1,159 @@ +#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= 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 + diff --git a/lib/MoMu-STK-1.0.0/include/SingWave.h b/lib/MoMu-STK-1.0.0/include/SingWave.h new file mode 100644 index 0000000..fcc3343 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/SingWave.h @@ -0,0 +1,136 @@ +#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 + +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 + diff --git a/lib/MoMu-STK-1.0.0/include/Skini.h b/lib/MoMu-STK-1.0.0/include/Skini.h new file mode 100644 index 0000000..6e25b96 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/Skini.h @@ -0,0 +1,121 @@ +#ifndef STK_SKINI_H +#define STK_SKINI_H + +#include "Stk.h" +#include +#include +#include + +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 floatValues; /*!< The message values read as floats (values are type-specific). */ + std::vector 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& 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 + + diff --git a/lib/MoMu-STK-1.0.0/include/Skini_msg.h b/lib/MoMu-STK-1.0.0/include/Skini_msg.h new file mode 100644 index 0000000..432f2cb --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/Skini_msg.h @@ -0,0 +1,137 @@ +#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__ + + where 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 diff --git a/lib/MoMu-STK-1.0.0/include/Skini_tbl.h b/lib/MoMu-STK-1.0.0/include/Skini_tbl.h new file mode 100644 index 0000000..63936dc --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/Skini_tbl.h @@ -0,0 +1,136 @@ +#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 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 diff --git a/lib/MoMu-STK-1.0.0/include/Socket.h b/lib/MoMu-STK-1.0.0/include/Socket.h new file mode 100644 index 0000000..a153845 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/Socket.h @@ -0,0 +1,89 @@ +#ifndef STK_SOCKET_H +#define STK_SOCKET_H + +#include "Stk.h" + +#if (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__)) + + #include + #include + #include + #include + #include + #include + #include + #include + +#elif defined(__OS_WINDOWS__) + + #include + +#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 diff --git a/lib/MoMu-STK-1.0.0/include/Sphere.h b/lib/MoMu-STK-1.0.0/include/Sphere.h new file mode 100644 index 0000000..48a6d76 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/Sphere.h @@ -0,0 +1,79 @@ +#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 diff --git a/lib/MoMu-STK-1.0.0/include/StifKarp.h b/lib/MoMu-STK-1.0.0/include/StifKarp.h new file mode 100644 index 0000000..002e31f --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/StifKarp.h @@ -0,0 +1,117 @@ +#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 diff --git a/lib/MoMu-STK-1.0.0/include/Stk.h b/lib/MoMu-STK-1.0.0/include/Stk.h new file mode 100644 index 0000000..f9a34c2 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/Stk.h @@ -0,0 +1,541 @@ +#ifndef STK_STK_H +#define STK_STK_H + +#include +#include +#include +#include +#include + +/*! \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 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 taps = std::vector( 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 taps ); + + //! Return the current delay-line length. + std::vector 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 outPoint_; + std::vector 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= 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= 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 + #define THREAD_TYPE + typedef pthread_t THREAD_HANDLE; + typedef void * THREAD_RETURN; + typedef void * (*THREAD_FUNCTION)(void *); + +#elif defined(__OS_WINDOWS__) + + #include + #include + #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 diff --git a/lib/MoMu-STK-1.0.0/include/TubeBell.h b/lib/MoMu-STK-1.0.0/include/TubeBell.h new file mode 100644 index 0000000..6b4d2a7 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/TubeBell.h @@ -0,0 +1,88 @@ +#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 diff --git a/lib/MoMu-STK-1.0.0/include/TwoPole.h b/lib/MoMu-STK-1.0.0/include/TwoPole.h new file mode 100644 index 0000000..adb4789 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/TwoPole.h @@ -0,0 +1,151 @@ +#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= 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= 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= 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 + +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 diff --git a/lib/MoMu-STK-1.0.0/include/VoicForm.h b/lib/MoMu-STK-1.0.0/include/VoicForm.h new file mode 100644 index 0000000..3617c71 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/VoicForm.h @@ -0,0 +1,124 @@ +#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 diff --git a/lib/MoMu-STK-1.0.0/include/Voicer.h b/lib/MoMu-STK-1.0.0/include/Voicer.h new file mode 100644 index 0000000..267b18b --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/Voicer.h @@ -0,0 +1,219 @@ +#ifndef STK_VOICER_H +#define STK_VOICER_H + +#include "Instrmnt.h" +#include + +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 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; jtick(); + for ( j=0; jchannelsOut(); 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; i3--\ + + --> 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 diff --git a/lib/MoMu-STK-1.0.0/include/WvIn.h b/lib/MoMu-STK-1.0.0/include/WvIn.h new file mode 100644 index 0000000..7baab99 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/WvIn.h @@ -0,0 +1,46 @@ +#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 diff --git a/lib/MoMu-STK-1.0.0/include/WvOut.h b/lib/MoMu-STK-1.0.0/include/WvOut.h new file mode 100644 index 0000000..f779308 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/include/WvOut.h @@ -0,0 +1,85 @@ +#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 diff --git a/lib/MoMu-STK-1.0.0/rawwaves/ahh.raw b/lib/MoMu-STK-1.0.0/rawwaves/ahh.raw new file mode 100644 index 0000000..dda5f55 Binary files /dev/null and b/lib/MoMu-STK-1.0.0/rawwaves/ahh.raw differ diff --git a/lib/MoMu-STK-1.0.0/rawwaves/bassdrum.raw b/lib/MoMu-STK-1.0.0/rawwaves/bassdrum.raw new file mode 100644 index 0000000..16b1ece Binary files /dev/null and b/lib/MoMu-STK-1.0.0/rawwaves/bassdrum.raw differ diff --git a/lib/MoMu-STK-1.0.0/rawwaves/britestk.raw b/lib/MoMu-STK-1.0.0/rawwaves/britestk.raw new file mode 100644 index 0000000..4bf9ba6 Binary files /dev/null and b/lib/MoMu-STK-1.0.0/rawwaves/britestk.raw differ diff --git a/lib/MoMu-STK-1.0.0/rawwaves/cowbell1.raw b/lib/MoMu-STK-1.0.0/rawwaves/cowbell1.raw new file mode 100644 index 0000000..4cd641f Binary files /dev/null and b/lib/MoMu-STK-1.0.0/rawwaves/cowbell1.raw differ diff --git a/lib/MoMu-STK-1.0.0/rawwaves/crashcym.raw b/lib/MoMu-STK-1.0.0/rawwaves/crashcym.raw new file mode 100644 index 0000000..21318b2 Binary files /dev/null and b/lib/MoMu-STK-1.0.0/rawwaves/crashcym.raw differ diff --git a/lib/MoMu-STK-1.0.0/rawwaves/dope.raw b/lib/MoMu-STK-1.0.0/rawwaves/dope.raw new file mode 100644 index 0000000..6a7a1ff Binary files /dev/null and b/lib/MoMu-STK-1.0.0/rawwaves/dope.raw differ diff --git a/lib/MoMu-STK-1.0.0/rawwaves/eee.raw b/lib/MoMu-STK-1.0.0/rawwaves/eee.raw new file mode 100644 index 0000000..d3888db Binary files /dev/null and b/lib/MoMu-STK-1.0.0/rawwaves/eee.raw differ diff --git a/lib/MoMu-STK-1.0.0/rawwaves/fwavblnk.raw b/lib/MoMu-STK-1.0.0/rawwaves/fwavblnk.raw new file mode 100644 index 0000000..14da074 Binary files /dev/null and b/lib/MoMu-STK-1.0.0/rawwaves/fwavblnk.raw differ diff --git a/lib/MoMu-STK-1.0.0/rawwaves/halfwave.raw b/lib/MoMu-STK-1.0.0/rawwaves/halfwave.raw new file mode 100644 index 0000000..b34639b Binary files /dev/null and b/lib/MoMu-STK-1.0.0/rawwaves/halfwave.raw differ diff --git a/lib/MoMu-STK-1.0.0/rawwaves/hihatcym.raw b/lib/MoMu-STK-1.0.0/rawwaves/hihatcym.raw new file mode 100644 index 0000000..f61389e Binary files /dev/null and b/lib/MoMu-STK-1.0.0/rawwaves/hihatcym.raw differ diff --git a/lib/MoMu-STK-1.0.0/rawwaves/impuls10.raw b/lib/MoMu-STK-1.0.0/rawwaves/impuls10.raw new file mode 100644 index 0000000..e18689d Binary files /dev/null and b/lib/MoMu-STK-1.0.0/rawwaves/impuls10.raw differ diff --git a/lib/MoMu-STK-1.0.0/rawwaves/impuls20.raw b/lib/MoMu-STK-1.0.0/rawwaves/impuls20.raw new file mode 100644 index 0000000..9d89aec Binary files /dev/null and b/lib/MoMu-STK-1.0.0/rawwaves/impuls20.raw differ diff --git a/lib/MoMu-STK-1.0.0/rawwaves/impuls40.raw b/lib/MoMu-STK-1.0.0/rawwaves/impuls40.raw new file mode 100644 index 0000000..9a3619b Binary files /dev/null and b/lib/MoMu-STK-1.0.0/rawwaves/impuls40.raw differ diff --git a/lib/MoMu-STK-1.0.0/rawwaves/makefunc.c b/lib/MoMu-STK-1.0.0/rawwaves/makefunc.c new file mode 100644 index 0000000..0068dce --- /dev/null +++ b/lib/MoMu-STK-1.0.0/rawwaves/makefunc.c @@ -0,0 +1,54 @@ +/**********************************************/ +/** 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 +#include +#include + +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); +} + diff --git a/lib/MoMu-STK-1.0.0/rawwaves/makemidi.c b/lib/MoMu-STK-1.0.0/rawwaves/makemidi.c new file mode 100644 index 0000000..cf82b7d --- /dev/null +++ b/lib/MoMu-STK-1.0.0/rawwaves/makemidi.c @@ -0,0 +1,33 @@ +/**********************************************/ +/** 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 +#include +#include + +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); +} + diff --git a/lib/MoMu-STK-1.0.0/rawwaves/makewavs.c b/lib/MoMu-STK-1.0.0/rawwaves/makewavs.c new file mode 100644 index 0000000..71863d0 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/rawwaves/makewavs.c @@ -0,0 +1,116 @@ +/**********************************************/ +/** 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 +#include +#include + +#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 +#include +#include + +#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; isetAttackTime( 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 diff --git a/lib/MoMu-STK-1.0.0/src/Asymp.cpp b/lib/MoMu-STK-1.0.0/src/Asymp.cpp new file mode 100644 index 0000000..c379b24 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/Asymp.cpp @@ -0,0 +1,103 @@ +/***************************************************/ +/*! \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 + +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 + diff --git a/lib/MoMu-STK-1.0.0/src/BandedWG.cpp b/lib/MoMu-STK-1.0.0/src/BandedWG.cpp new file mode 100644 index 0000000..1d102c1 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/BandedWG.cpp @@ -0,0 +1,380 @@ +/***************************************************/ +/*! \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 + +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 1568.0) frequency_ = 1568.0; + + StkFloat radius; + StkFloat base = Stk::sampleRate() / frequency_; + StkFloat length; + for (int i=0; i 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; isetFrequency(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 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; isetPreset((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 diff --git a/lib/MoMu-STK-1.0.0/src/BeeThree.cpp b/lib/MoMu-STK-1.0.0/src/BeeThree.cpp new file mode 100644 index 0000000..9272b3b --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/BeeThree.cpp @@ -0,0 +1,84 @@ +/***************************************************/ +/*! \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 diff --git a/lib/MoMu-STK-1.0.0/src/BiQuad.cpp b/lib/MoMu-STK-1.0.0/src/BiQuad.cpp new file mode 100644 index 0000000..b9de9a5 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/BiQuad.cpp @@ -0,0 +1,81 @@ +/***************************************************/ +/*! \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 + +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 diff --git a/lib/MoMu-STK-1.0.0/src/Blit.cpp b/lib/MoMu-STK-1.0.0/src/Blit.cpp new file mode 100644 index 0000000..f6a5cad --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/Blit.cpp @@ -0,0 +1,78 @@ +/***************************************************/ +/*! \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. +*/ +/***************************************************/ + +#include "Blit.h" + +namespace stk { + +Blit:: Blit( StkFloat frequency ) +{ + nHarmonics_ = 0; + this->setFrequency( frequency ); + this->reset(); +} + +Blit :: ~Blit() +{ +} + +void Blit :: reset() +{ + phase_ = 0.0; + lastFrame_[0] = 0.0; +} + +void Blit :: setFrequency( StkFloat frequency ) +{ +#if defined(_STK_DEBUG_) + errorString_ << "Blit::setFrequency: frequency = " << frequency << '.'; + handleError( StkError::DEBUG_WARNING ); +#endif + + p_ = Stk::sampleRate() / frequency; + rate_ = PI / p_; + this->updateHarmonics(); +} + +void Blit :: setHarmonics( unsigned int nHarmonics ) +{ + nHarmonics_ = nHarmonics; + this->updateHarmonics(); +} + +void Blit :: updateHarmonics( void ) +{ + if ( nHarmonics_ <= 0 ) { + unsigned int maxHarmonics = (unsigned int) floor( 0.5 * p_ ); + m_ = 2 * maxHarmonics + 1; + } + else + m_ = 2 * nHarmonics_ + 1; + +#if defined(_STK_DEBUG_) + errorString_ << "Blit::updateHarmonics: nHarmonics_ = " << nHarmonics_ << ", m_ = " << m_ << '.'; + handleError( StkError::DEBUG_WARNING ); +#endif +} + +} // stk namespace diff --git a/lib/MoMu-STK-1.0.0/src/BlitSaw.cpp b/lib/MoMu-STK-1.0.0/src/BlitSaw.cpp new file mode 100644 index 0000000..abde294 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/BlitSaw.cpp @@ -0,0 +1,91 @@ +/***************************************************/ +/*! \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. +*/ +/***************************************************/ + +#include "BlitSaw.h" + +namespace stk { + +BlitSaw:: BlitSaw( StkFloat frequency ) +{ + nHarmonics_ = 0; + this->reset(); + this->setFrequency( frequency ); +} + +BlitSaw :: ~BlitSaw() +{ +} + +void BlitSaw :: reset() +{ + phase_ = 0.0f; + state_ = 0.0; + lastFrame_[0] = 0.0; +} + +void BlitSaw :: setFrequency( StkFloat frequency ) +{ +#if defined(_STK_DEBUG_) + errorString_ << "BlitSaw::setFrequency: frequency = " << frequency << '.'; + handleError( StkError::DEBUG_WARNING ); +#endif + + p_ = Stk::sampleRate() / frequency; + C2_ = 1 / p_; + rate_ = PI * C2_; + this->updateHarmonics(); +} + +void BlitSaw :: setHarmonics( unsigned int nHarmonics ) +{ + nHarmonics_ = nHarmonics; + this->updateHarmonics(); + + // I found that the initial DC offset could be minimized with an + // initial state setting as given below. This initialization should + // only happen before starting the oscillator for the first time + // (but after setting the frequency and number of harmonics). I + // struggled a bit to decide where best to put this and finally + // settled on here. In general, the user shouldn't be messing with + // the number of harmonics once the oscillator is running because + // this is automatically taken care of in the setFrequency() + // function. (GPS - 1 October 2005) + state_ = -0.5 * a_; +} + +void BlitSaw :: updateHarmonics( void ) +{ + if ( nHarmonics_ <= 0 ) { + unsigned int maxHarmonics = (unsigned int) floor( 0.5 * p_ ); + m_ = 2 * maxHarmonics + 1; + } + else + m_ = 2 * nHarmonics_ + 1; + + a_ = m_ / p_; + +#if defined(_STK_DEBUG_) + errorString_ << "BlitSaw::updateHarmonics: nHarmonics_ = " << nHarmonics_ << ", m_ = " << m_ << '.'; + handleError( StkError::DEBUG_WARNING ); +#endif +} + +} // stk namespace diff --git a/lib/MoMu-STK-1.0.0/src/BlitSquare.cpp b/lib/MoMu-STK-1.0.0/src/BlitSquare.cpp new file mode 100644 index 0000000..6d7e44a --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/BlitSquare.cpp @@ -0,0 +1,95 @@ +/***************************************************/ +/*! \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 - 2010. +*/ +/***************************************************/ + +#include "BlitSquare.h" + +namespace stk { + +BlitSquare:: BlitSquare( StkFloat frequency ) +{ + nHarmonics_ = 0; + this->setFrequency( frequency ); + this->reset(); +} + +BlitSquare :: ~BlitSquare() +{ +} + +void BlitSquare :: reset() +{ + phase_ = 0.0; + lastFrame_[0] = 0.0; + dcbState_ = 0.0; + lastBlitOutput_ = 0; +} + +void BlitSquare :: setFrequency( StkFloat frequency ) +{ +#if defined(_STK_DEBUG_) + errorString_ << "BlitSquare::setFrequency: frequency = " << frequency << '.'; + handleError( StkError::DEBUG_WARNING ); +#endif + + // By using an even value of the parameter M, we get a bipolar blit + // waveform at half the blit frequency. Thus, we need to scale the + // frequency value here by 0.5. (GPS, 2006). + p_ = 0.5 * Stk::sampleRate() / frequency; + rate_ = PI / p_; + this->updateHarmonics(); +} + +void BlitSquare :: setHarmonics( unsigned int nHarmonics ) +{ + nHarmonics_ = nHarmonics; + this->updateHarmonics(); +} + +void BlitSquare :: updateHarmonics( void ) +{ + // Make sure we end up with an even value of the parameter M here. + if ( nHarmonics_ <= 0 ) { + unsigned int maxHarmonics = (unsigned int) floor( 0.5 * p_ ); + m_ = 2 * (maxHarmonics + 1); + } + else + m_ = 2 * (nHarmonics_ + 1); + + a_ = m_ / p_; + +#if defined(_STK_DEBUG_) + errorString_ << "BlitSquare::updateHarmonics: nHarmonics_ = " << nHarmonics_ << ", m_ = " << m_ << '.'; + handleError( StkError::DEBUG_WARNING ); +#endif +} + +} // stk namespace diff --git a/lib/MoMu-STK-1.0.0/src/BlowBotl.cpp b/lib/MoMu-STK-1.0.0/src/BlowBotl.cpp new file mode 100644 index 0000000..dd60593 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/BlowBotl.cpp @@ -0,0 +1,129 @@ +/***************************************************/ +/*! \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 diff --git a/lib/MoMu-STK-1.0.0/src/BlowHole.cpp b/lib/MoMu-STK-1.0.0/src/BlowHole.cpp new file mode 100644 index 0000000..6934f85 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/BlowHole.cpp @@ -0,0 +1,224 @@ +/***************************************************/ +/*! \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 + +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 diff --git a/lib/MoMu-STK-1.0.0/src/Bowed.cpp b/lib/MoMu-STK-1.0.0/src/Bowed.cpp new file mode 100644 index 0000000..09272a4 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/Bowed.cpp @@ -0,0 +1,162 @@ +/***************************************************/ +/*! \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 diff --git a/lib/MoMu-STK-1.0.0/src/Brass.cpp b/lib/MoMu-STK-1.0.0/src/Brass.cpp new file mode 100644 index 0000000..295660f --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/Brass.cpp @@ -0,0 +1,162 @@ +/***************************************************/ +/*! \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 + +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 diff --git a/lib/MoMu-STK-1.0.0/src/Chorus.cpp b/lib/MoMu-STK-1.0.0/src/Chorus.cpp new file mode 100644 index 0000000..7e968ba --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/Chorus.cpp @@ -0,0 +1,46 @@ +/***************************************************/ +/*! \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 diff --git a/lib/MoMu-STK-1.0.0/src/Clarinet.cpp b/lib/MoMu-STK-1.0.0/src/Clarinet.cpp new file mode 100644 index 0000000..ed38a8e --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/Clarinet.cpp @@ -0,0 +1,139 @@ +/***************************************************/ +/*! \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 diff --git a/lib/MoMu-STK-1.0.0/src/Delay.cpp b/lib/MoMu-STK-1.0.0/src/Delay.cpp new file mode 100644 index 0000000..fd3efb4 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/Delay.cpp @@ -0,0 +1,130 @@ +/***************************************************/ +/*! \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= 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 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 diff --git a/lib/MoMu-STK-1.0.0/src/DelayL.cpp b/lib/MoMu-STK-1.0.0/src/DelayL.cpp new file mode 100644 index 0000000..02e3fbb --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/DelayL.cpp @@ -0,0 +1,109 @@ +/***************************************************/ +/*! \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 diff --git a/lib/MoMu-STK-1.0.0/src/Drummer.cpp b/lib/MoMu-STK-1.0.0/src/Drummer.cpp new file mode 100644 index 0000000..24d5ebe --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/Drummer.cpp @@ -0,0 +1,160 @@ +/***************************************************/ +/*! \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 + +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 (DRUM_POLYPHONY, -1); + soundNumber_ = std::vector (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 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< + +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 diff --git a/lib/MoMu-STK-1.0.0/src/Envelope.cpp b/lib/MoMu-STK-1.0.0/src/Envelope.cpp new file mode 100644 index 0000000..2d33fe1 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/Envelope.cpp @@ -0,0 +1,50 @@ +/***************************************************/ +/*! \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 diff --git a/lib/MoMu-STK-1.0.0/src/FM.cpp b/lib/MoMu-STK-1.0.0/src/FM.cpp new file mode 100644 index 0000000..71e7ecd --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/FM.cpp @@ -0,0 +1,197 @@ +/***************************************************/ +/*! \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=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; isetFrequency( 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; ikeyOn(); +} + +void FM :: keyOff( void ) +{ + for ( unsigned int i=0; ikeyOff(); +} + +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 diff --git a/lib/MoMu-STK-1.0.0/src/FMVoices.cpp b/lib/MoMu-STK-1.0.0/src/FMVoices.cpp new file mode 100644 index 0000000..040c2e0 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/FMVoices.cpp @@ -0,0 +1,169 @@ +/***************************************************/ +/*! \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 diff --git a/lib/MoMu-STK-1.0.0/src/FileLoop.cpp b/lib/MoMu-STK-1.0.0/src/FileLoop.cpp new file mode 100644 index 0000000..528d057 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/FileLoop.cpp @@ -0,0 +1,224 @@ +/***************************************************/ +/*! \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 + +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; isetRate( 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; jtick(); + for ( j=0; j2) + 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 +#include +#include +#include +#include + +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>= 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 diff --git a/lib/MoMu-STK-1.0.0/src/FileWrite.cpp b/lib/MoMu-STK-1.0.0/src/FileWrite.cpp new file mode 100644 index 0000000..d50e73a --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/FileWrite.cpp @@ -0,0 +1,707 @@ +/***************************************************/ +/*! \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 +#include +#include + +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 + +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; inormalize( 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 max ) + max = (StkFloat) fabs((double) data_[i]); + } + + if ( max > 0.0 ) { + max = 1.0 / max; + max *= peak; + for ( i=0; i file_.fileSize() - 1.0 ) { + time_ = file_.fileSize() - 1.0; + for ( unsigned int i=0; i= 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 (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; itick(); + for ( j=0; jopenFile( 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; jincrementFrame(); +} + +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; iincrementFrame(); + } +} + +} // stk namespace diff --git a/lib/MoMu-STK-1.0.0/src/Fir.cpp b/lib/MoMu-STK-1.0.0/src/Fir.cpp new file mode 100644 index 0000000..2465009 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/Fir.cpp @@ -0,0 +1,73 @@ +/***************************************************/ +/*! \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 &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 &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; iclear(); +} + +} // stk namespace diff --git a/lib/MoMu-STK-1.0.0/src/Flute.cpp b/lib/MoMu-STK-1.0.0/src/Flute.cpp new file mode 100644 index 0000000..2cf6e58 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/Flute.cpp @@ -0,0 +1,180 @@ +/***************************************************/ +/*! \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 diff --git a/lib/MoMu-STK-1.0.0/src/FormSwep.cpp b/lib/MoMu-STK-1.0.0/src/FormSwep.cpp new file mode 100644 index 0000000..b47d75d --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/FormSwep.cpp @@ -0,0 +1,110 @@ +/***************************************************/ +/*! \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 + +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 diff --git a/lib/MoMu-STK-1.0.0/src/Granulate.cpp b/lib/MoMu-STK-1.0.0/src/Granulate.cpp new file mode 100644 index 0000000..7d3ef83 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/Granulate.cpp @@ -0,0 +1,294 @@ +/***************************************************/ +/*! \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 + +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; icalculateGrain( 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= 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 diff --git a/lib/MoMu-STK-1.0.0/src/HevyMetl.cpp b/lib/MoMu-STK-1.0.0/src/HevyMetl.cpp new file mode 100644 index 0000000..1ff75a6 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/HevyMetl.cpp @@ -0,0 +1,80 @@ +/***************************************************/ +/*! \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 diff --git a/lib/MoMu-STK-1.0.0/src/Iir.cpp b/lib/MoMu-STK-1.0.0/src/Iir.cpp new file mode 100644 index 0000000..e1224fa --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/Iir.cpp @@ -0,0 +1,125 @@ +/***************************************************/ +/*! \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 &bCoefficients, std::vector &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 &bCoefficients, std::vector &aCoefficients, bool clearState ) +{ + this->setNumerator( bCoefficients, false ); + this->setDenominator( aCoefficients, false ); + + if ( clearState ) this->clear(); +} + +void Iir :: setNumerator( std::vector &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; iclear(); +} + +void Iir :: setDenominator( std::vector &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; iclear(); + + // Scale coefficients by a[0] if necessary + if ( a_[0] != 1.0 ) { + unsigned int i; + for ( i=0; ifinished ) { + ((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 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; itick(); + for ( j=0; jisValid( 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; kclipTest( data_[k] ); + *ptr++ = (signed char) (data_[k] * 127.0); + } + } + else if ( dataType_ == STK_SINT16 ) { + SINT16 *ptr = (SINT16 *) buffer_; + for ( unsigned long k=0; kclipTest( 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; kclipTest( 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; kclipTest( 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; kclipTest( 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; jincrementFrame(); +} + +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; iincrementFrame(); + } +} + +} // stk namespace diff --git a/lib/MoMu-STK-1.0.0/src/JCRev.cpp b/lib/MoMu-STK-1.0.0/src/JCRev.cpp new file mode 100644 index 0000000..763b49b --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/JCRev.cpp @@ -0,0 +1,120 @@ +/***************************************************/ +/*! \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 + +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= 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; iisFinished(); +} + +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 diff --git a/lib/MoMu-STK-1.0.0/src/Mesh2D.cpp b/lib/MoMu-STK-1.0.0/src/Mesh2D.cpp new file mode 100644 index 0000000..c324569 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/Mesh2D.cpp @@ -0,0 +1,400 @@ +/***************************************************/ +/*! \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; iclearMesh(); + + counter_=0; + xInput_ = 0; + yInput_ = 0; +} + +Mesh2D :: ~Mesh2D( void ) +{ +} + +void Mesh2D :: clear( void ) +{ + this->clearMesh(); + + short i; + for (i=0; i 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 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 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 diff --git a/lib/MoMu-STK-1.0.0/src/Messager.cpp b/lib/MoMu-STK-1.0.0/src/Messager.cpp new file mode 100644 index 0000000..ac08cdc --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/Messager.cpp @@ -0,0 +1,428 @@ +/***************************************************/ +/*! \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 +#include +#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 *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 + #include +#endif + +THREAD_RETURN THREAD_TYPE socketHandler(void *ptr) +{ + Messager::MessagerData *data = (Messager::MessagerData *) ptr; + Skini::Message message; + std::vector& 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 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; imutex.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; isources &= ~STK_SOCKET; + if ( data->sources & STK_MIDI ) + std::cout << "MIDI input still running ... type 'exit' 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 + diff --git a/lib/MoMu-STK-1.0.0/src/MidiFileIn.cpp b/lib/MoMu-STK-1.0.0/src/MidiFileIn.cpp new file mode 100644 index 0000000..17fce6f --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/MidiFileIn.cpp @@ -0,0 +1,367 @@ +/**********************************************************************/ +/*! \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 +#include + +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 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_ ) { + 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 *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; ipush_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 *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; isize(); i++ ) + //std::cout << "event byte = " << i << ", value = " << (int)midiEvent->at(i) << std::endl; + ticks = getNextEvent( midiEvent, track ); + } + + //for ( unsigned int i=0; isize(); 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 diff --git a/lib/MoMu-STK-1.0.0/src/Modal.cpp b/lib/MoMu-STK-1.0.0/src/Modal.cpp new file mode 100644 index 0000000..7f2dadc --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/Modal.cpp @@ -0,0 +1,181 @@ +/***************************************************/ +/*! \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 + +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; isetEqualGainZeroes(); + } + + // 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; iclear(); +} + +void Modal :: setFrequency( StkFloat frequency ) +{ + baseFrequency_ = frequency; + for ( unsigned int i=0; isetRatioAndRadius( 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; isetResonance(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; isetResonance( temp, radii_[i]*amplitude ); + } +} + +} // stk namespace diff --git a/lib/MoMu-STK-1.0.0/src/ModalBar.cpp b/lib/MoMu-STK-1.0.0/src/ModalBar.cpp new file mode 100644 index 0000000..9a6c1a6 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/ModalBar.cpp @@ -0,0 +1,200 @@ +/***************************************************/ +/*! \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 + +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; isetRatioAndRadius(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 diff --git a/lib/MoMu-STK-1.0.0/src/Modulate.cpp b/lib/MoMu-STK-1.0.0/src/Modulate.cpp new file mode 100644 index 0000000..39743ca --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/Modulate.cpp @@ -0,0 +1,49 @@ +/***************************************************/ +/*! \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 diff --git a/lib/MoMu-STK-1.0.0/src/Moog.cpp b/lib/MoMu-STK-1.0.0/src/Moog.cpp new file mode 100644 index 0000000..35aa3c8 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/Moog.cpp @@ -0,0 +1,122 @@ +/***************************************************/ +/*! \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 diff --git a/lib/MoMu-STK-1.0.0/src/Mutex.cpp b/lib/MoMu-STK-1.0.0/src/Mutex.cpp new file mode 100644 index 0000000..896decf --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/Mutex.cpp @@ -0,0 +1,104 @@ +/***************************************************/ +/*! \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 diff --git a/lib/MoMu-STK-1.0.0/src/NRev.cpp b/lib/MoMu-STK-1.0.0/src/NRev.cpp new file mode 100644 index 0000000..3c81f81 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/NRev.cpp @@ -0,0 +1,110 @@ +/***************************************************/ +/*! \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 + +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= 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 + +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 + + diff --git a/lib/MoMu-STK-1.0.0/src/OnePole.cpp b/lib/MoMu-STK-1.0.0/src/OnePole.cpp new file mode 100644 index 0000000..0c33b4d --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/OnePole.cpp @@ -0,0 +1,50 @@ +/***************************************************/ +/*! \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 diff --git a/lib/MoMu-STK-1.0.0/src/OneZero.cpp b/lib/MoMu-STK-1.0.0/src/OneZero.cpp new file mode 100644 index 0000000..7d7fcac --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/OneZero.cpp @@ -0,0 +1,48 @@ +/***************************************************/ +/*! \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 diff --git a/lib/MoMu-STK-1.0.0/src/PRCRev.cpp b/lib/MoMu-STK-1.0.0/src/PRCRev.cpp new file mode 100644 index 0000000..7fd4cb2 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/PRCRev.cpp @@ -0,0 +1,111 @@ +/***************************************************/ +/*! \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 + +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= 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; i3--\ + 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 diff --git a/lib/MoMu-STK-1.0.0/src/Phonemes.cpp b/lib/MoMu-STK-1.0.0/src/Phonemes.cpp new file mode 100644 index 0000000..da7d52d --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/Phonemes.cpp @@ -0,0 +1,298 @@ +/***************************************************/ +/*! \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 + +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 diff --git a/lib/MoMu-STK-1.0.0/src/PitShift.cpp b/lib/MoMu-STK-1.0.0/src/PitShift.cpp new file mode 100644 index 0000000..d2f5212 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/PitShift.cpp @@ -0,0 +1,88 @@ +/***************************************************/ +/*! \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 + +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= 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 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 diff --git a/lib/MoMu-STK-1.0.0/src/Plucked.cpp b/lib/MoMu-STK-1.0.0/src/Plucked.cpp new file mode 100644 index 0000000..0cb239a --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/Plucked.cpp @@ -0,0 +1,117 @@ +/***************************************************/ +/*! \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; isetFrequency( 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 diff --git a/lib/MoMu-STK-1.0.0/src/PoleZero.cpp b/lib/MoMu-STK-1.0.0/src/PoleZero.cpp new file mode 100644 index 0000000..b90d203 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/PoleZero.cpp @@ -0,0 +1,58 @@ +/***************************************************/ +/*! \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 diff --git a/lib/MoMu-STK-1.0.0/src/Resonate.cpp b/lib/MoMu-STK-1.0.0/src/Resonate.cpp new file mode 100644 index 0000000..dbb4603 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/Resonate.cpp @@ -0,0 +1,137 @@ +/***************************************************/ +/*! \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 diff --git a/lib/MoMu-STK-1.0.0/src/Rhodey.cpp b/lib/MoMu-STK-1.0.0/src/Rhodey.cpp new file mode 100644 index 0000000..0fa7950 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/Rhodey.cpp @@ -0,0 +1,90 @@ +/***************************************************/ +/*! \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; isetFrequency( 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 diff --git a/lib/MoMu-STK-1.0.0/src/Sampler.cpp b/lib/MoMu-STK-1.0.0/src/Sampler.cpp new file mode 100644 index 0000000..7dd2bfc --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/Sampler.cpp @@ -0,0 +1,58 @@ +/***************************************************/ +/*! \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; ireset(); + + // 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 diff --git a/lib/MoMu-STK-1.0.0/src/Saxofony.cpp b/lib/MoMu-STK-1.0.0/src/Saxofony.cpp new file mode 100644 index 0000000..7d0ecb1 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/Saxofony.cpp @@ -0,0 +1,179 @@ +/***************************************************/ +/*! \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 diff --git a/lib/MoMu-STK-1.0.0/src/Shakers.cpp b/lib/MoMu-STK-1.0.0/src/Shakers.cpp new file mode 100644 index 0000000..d708d7e --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/Shakers.cpp @@ -0,0 +1,1135 @@ +/***************************************************/ +/*! \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 +#include +#include + +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; isetupNum(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;isetupNum(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;isetDecays(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 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 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 10000.0) data = 10000.0; + if (data < -10000.0) data = -10000.0; + data = data * 0.0001; + } + else data = 0.0; + return data; +} + +} // stk namespace diff --git a/lib/MoMu-STK-1.0.0/src/Simple.cpp b/lib/MoMu-STK-1.0.0/src/Simple.cpp new file mode 100644 index 0000000..7b3e724 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/Simple.cpp @@ -0,0 +1,115 @@ +/***************************************************/ +/*! \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 diff --git a/lib/MoMu-STK-1.0.0/src/SineWave.cpp b/lib/MoMu-STK-1.0.0/src/SineWave.cpp new file mode 100644 index 0000000..3bd8ecf --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/SineWave.cpp @@ -0,0 +1,78 @@ +/***************************************************/ +/*! \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 + +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 diff --git a/lib/MoMu-STK-1.0.0/src/SingWave.cpp b/lib/MoMu-STK-1.0.0/src/SingWave.cpp new file mode 100644 index 0000000..336693b --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/SingWave.cpp @@ -0,0 +1,53 @@ +/***************************************************/ +/*! \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 diff --git a/lib/MoMu-STK-1.0.0/src/Sitar.cpp b/lib/MoMu-STK-1.0.0/src/Sitar.cpp new file mode 100644 index 0000000..14035e7 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/Sitar.cpp @@ -0,0 +1,102 @@ +/***************************************************/ +/*! \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 diff --git a/lib/MoMu-STK-1.0.0/src/Skini.cpp b/lib/MoMu-STK-1.0.0/src/Skini.cpp new file mode 100644 index 0000000..69d2b38 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/Skini.cpp @@ -0,0 +1,222 @@ +/***************************************************/ +/*! \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 + +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& 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 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 diff --git a/lib/MoMu-STK-1.0.0/src/Socket.cpp b/lib/MoMu-STK-1.0.0/src/Socket.cpp new file mode 100644 index 0000000..ba20ce3 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/Socket.cpp @@ -0,0 +1,78 @@ +/***************************************************/ +/*! \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 diff --git a/lib/MoMu-STK-1.0.0/src/Sphere.cpp b/lib/MoMu-STK-1.0.0/src/Sphere.cpp new file mode 100644 index 0000000..707a67f --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/Sphere.cpp @@ -0,0 +1,50 @@ +/***************************************************/ +/*! \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 + +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 diff --git a/lib/MoMu-STK-1.0.0/src/StifKarp.cpp b/lib/MoMu-STK-1.0.0/src/StifKarp.cpp new file mode 100644 index 0000000..6b118ff --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/StifKarp.cpp @@ -0,0 +1,216 @@ +/***************************************************/ +/*! \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 + +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; itick() * 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 diff --git a/lib/MoMu-STK-1.0.0/src/Stk.mm b/lib/MoMu-STK-1.0.0/src/Stk.mm new file mode 100644 index 0000000..9af8abd --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/Stk.mm @@ -0,0 +1,345 @@ +/***************************************************/ +/*! \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 :: alertList_; + +std::string Stk::rawwavepath_ = ""; + + + +Stk :: Stk( void ) + : ignoreSampleRateChange_(false) +{ + std::string path([[[NSBundle mainBundle] resourcePath] UTF8String]); + setRawwavePath( path ); + //std::cout<<(rawwavepath_)< 0.0 && rate != srate_ ) { + StkFloat oldRate = srate_; + srate_ = rate; + + for ( unsigned int i=0; isampleRateChanged( 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 +#elif defined(__OS_WINDOWS__) + #include +#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 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 (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 diff --git a/lib/MoMu-STK-1.0.0/src/StkUdpSocket.cpp b/lib/MoMu-STK-1.0.0/src/StkUdpSocket.cpp new file mode 100644 index 0000000..c2d643d --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/StkUdpSocket.cpp @@ -0,0 +1,109 @@ +/***************************************************/ +/*! \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 + +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 diff --git a/lib/MoMu-STK-1.0.0/src/TapDelay.cpp b/lib/MoMu-STK-1.0.0/src/TapDelay.cpp new file mode 100644 index 0000000..a519d46 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/TapDelay.cpp @@ -0,0 +1,104 @@ +/***************************************************/ +/*! \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 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 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 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 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 + diff --git a/lib/MoMu-STK-1.0.0/src/TcpClient.cpp b/lib/MoMu-STK-1.0.0/src/TcpClient.cpp new file mode 100644 index 0000000..44e1999 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/TcpClient.cpp @@ -0,0 +1,104 @@ +/***************************************************/ +/*! \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 + +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 diff --git a/lib/MoMu-STK-1.0.0/src/TcpServer.cpp b/lib/MoMu-STK-1.0.0/src/TcpServer.cpp new file mode 100644 index 0000000..7ae930f --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/TcpServer.cpp @@ -0,0 +1,99 @@ +/***************************************************/ +/*! \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 diff --git a/lib/MoMu-STK-1.0.0/src/Thread.cpp b/lib/MoMu-STK-1.0.0/src/Thread.cpp new file mode 100644 index 0000000..dc1a473 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/Thread.cpp @@ -0,0 +1,106 @@ +/***************************************************/ +/*! \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 diff --git a/lib/MoMu-STK-1.0.0/src/TubeBell.cpp b/lib/MoMu-STK-1.0.0/src/TubeBell.cpp new file mode 100644 index 0000000..e534574 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/TubeBell.cpp @@ -0,0 +1,83 @@ +/***************************************************/ +/*! \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 diff --git a/lib/MoMu-STK-1.0.0/src/TwoPole.cpp b/lib/MoMu-STK-1.0.0/src/TwoPole.cpp new file mode 100644 index 0000000..b8ab30d --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/TwoPole.cpp @@ -0,0 +1,65 @@ +/***************************************************/ +/*! \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 + +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 diff --git a/lib/MoMu-STK-1.0.0/src/TwoZero.cpp b/lib/MoMu-STK-1.0.0/src/TwoZero.cpp new file mode 100644 index 0000000..e3ed25b --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/TwoZero.cpp @@ -0,0 +1,63 @@ +/***************************************************/ +/*! \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 + +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 diff --git a/lib/MoMu-STK-1.0.0/src/VoicForm.cpp b/lib/MoMu-STK-1.0.0/src/VoicForm.cpp new file mode 100644 index 0000000..8d40c3d --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/VoicForm.cpp @@ -0,0 +1,201 @@ +/***************************************************/ +/*! \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 +#include + +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 diff --git a/lib/MoMu-STK-1.0.0/src/Voicer.cpp b/lib/MoMu-STK-1.0.0/src/Voicer.cpp new file mode 100644 index 0000000..bf8549c --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/Voicer.cpp @@ -0,0 +1,219 @@ +/***************************************************/ +/*! \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 + +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::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; inoteOn( 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= 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; inoteOff( amplitude * ONE_OVER_128 ); + voices_[i].sounding = -muteTime_; + } + } +} + +void Voicer :: noteOff( long tag, StkFloat amplitude ) +{ + for ( unsigned int i=0; inoteOff( 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; isetFrequency( 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; isetFrequency( 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; isetFrequency( (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; isetFrequency( (StkFloat) (voices_[i].frequency * pitchScaler) ); + break; + } + } +} + +void Voicer :: controlChange( int number, StkFloat value, int group ) +{ + for ( unsigned int i=0; icontrolChange( number, value ); + } +} + +void Voicer :: controlChange( long tag, int number, StkFloat value ) +{ + for ( unsigned int i=0; icontrolChange( number, value ); + break; + } + } +} + +void Voicer :: silence( void ) +{ + for ( unsigned int i=0; i 0 ) + voices_[i].instrument->noteOff( 0.5 ); + } +} + +} // stk namespace diff --git a/lib/MoMu-STK-1.0.0/src/Whistle.cpp b/lib/MoMu-STK-1.0.0/src/Whistle.cpp new file mode 100644 index 0000000..257f072 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/Whistle.cpp @@ -0,0 +1,262 @@ +/***************************************************/ +/*! \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 + +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 diff --git a/lib/MoMu-STK-1.0.0/src/Wurley.cpp b/lib/MoMu-STK-1.0.0/src/Wurley.cpp new file mode 100644 index 0000000..88bd9fe --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/Wurley.cpp @@ -0,0 +1,92 @@ +/***************************************************/ +/*! \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 diff --git a/src/Voice.cpp b/src/Voice.cpp new file mode 100644 index 0000000..36e6c51 --- /dev/null +++ b/src/Voice.cpp @@ -0,0 +1,182 @@ +// +// 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() { +} diff --git a/src/Voice.h b/src/Voice.h new file mode 100644 index 0000000..0929ec8 --- /dev/null +++ b/src/Voice.h @@ -0,0 +1,76 @@ +// +// 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 diff --git a/src/iosynthApp.cpp b/src/iosynthApp.cpp index 5fee8fb..a7067b5 100644 --- a/src/iosynthApp.cpp +++ b/src/iosynthApp.cpp @@ -1,17 +1,6 @@ -#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() { @@ -27,8 +16,21 @@ void iosynthApp::update() 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 ) diff --git a/src/iosynthApp.h b/src/iosynthApp.h new file mode 100644 index 0000000..69cd467 --- /dev/null +++ b/src/iosynthApp.h @@ -0,0 +1,69 @@ +// +// 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 voices; + std::vector envelopes; + + JCRev reverb; + maxiDelayline maxiDelay; + maxiDyn maxiDyn; + maxiFilter maxiFilter; +}; + +#endif diff --git a/xcode_ios/iosynth.xcodeproj/project.pbxproj b/xcode_ios/iosynth.xcodeproj/project.pbxproj index bbcacde..9bd0031 100644 --- a/xcode_ios/iosynth.xcodeproj/project.pbxproj +++ b/xcode_ios/iosynth.xcodeproj/project.pbxproj @@ -7,59 +7,314 @@ 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 = ""; }; 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 = ""; }; 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 = ""; }; 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 = ""; }; + 3DCA5ADB4E5F41B8BC4AFF40 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 5F24CD9B8A5949E0B1828046 /* iosynth_Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = "\"\""; path = iosynth_Prefix.pch; sourceTree = ""; }; + 68CAAF0918544B0700DB5318 /* iosynthApp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = iosynthApp.h; path = ../src/iosynthApp.h; sourceTree = ""; }; + 68CAAF0A1854556E00DB5318 /* Voice.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Voice.cpp; path = ../src/Voice.cpp; sourceTree = ""; }; + 68CAAF0B1854556E00DB5318 /* Voice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Voice.h; path = ../src/Voice.h; sourceTree = ""; }; + 68CAAF0F185456F000DB5318 /* maximilian.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = maximilian.cpp; sourceTree = ""; }; + 68CAAF10185456F000DB5318 /* maximilian.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = maximilian.h; sourceTree = ""; }; + 68CAAF16185456F000DB5318 /* ADSR.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADSR.h; sourceTree = ""; }; + 68CAAF17185456F000DB5318 /* Asymp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Asymp.h; sourceTree = ""; }; + 68CAAF18185456F000DB5318 /* BandedWG.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BandedWG.h; sourceTree = ""; }; + 68CAAF19185456F000DB5318 /* BeeThree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BeeThree.h; sourceTree = ""; }; + 68CAAF1A185456F000DB5318 /* BiQuad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BiQuad.h; sourceTree = ""; }; + 68CAAF1B185456F000DB5318 /* Blit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Blit.h; sourceTree = ""; }; + 68CAAF1C185456F000DB5318 /* BlitSaw.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BlitSaw.h; sourceTree = ""; }; + 68CAAF1D185456F000DB5318 /* BlitSquare.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BlitSquare.h; sourceTree = ""; }; + 68CAAF1E185456F000DB5318 /* BlowBotl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BlowBotl.h; sourceTree = ""; }; + 68CAAF1F185456F000DB5318 /* BlowHole.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BlowHole.h; sourceTree = ""; }; + 68CAAF20185456F000DB5318 /* Bowed.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Bowed.h; sourceTree = ""; }; + 68CAAF21185456F000DB5318 /* BowTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BowTable.h; sourceTree = ""; }; + 68CAAF22185456F000DB5318 /* Brass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Brass.h; sourceTree = ""; }; + 68CAAF23185456F000DB5318 /* Chorus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Chorus.h; sourceTree = ""; }; + 68CAAF24185456F000DB5318 /* Clarinet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Clarinet.h; sourceTree = ""; }; + 68CAAF25185456F000DB5318 /* Delay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Delay.h; sourceTree = ""; }; + 68CAAF26185456F000DB5318 /* DelayA.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DelayA.h; sourceTree = ""; }; + 68CAAF27185456F000DB5318 /* DelayL.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DelayL.h; sourceTree = ""; }; + 68CAAF28185456F000DB5318 /* Drummer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Drummer.h; sourceTree = ""; }; + 68CAAF29185456F000DB5318 /* Echo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Echo.h; sourceTree = ""; }; + 68CAAF2A185456F000DB5318 /* Effect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Effect.h; sourceTree = ""; }; + 68CAAF2B185456F000DB5318 /* Envelope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Envelope.h; sourceTree = ""; }; + 68CAAF2C185456F000DB5318 /* FileLoop.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FileLoop.h; sourceTree = ""; }; + 68CAAF2D185456F000DB5318 /* FileRead.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FileRead.h; sourceTree = ""; }; + 68CAAF2E185456F000DB5318 /* FileWrite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FileWrite.h; sourceTree = ""; }; + 68CAAF2F185456F000DB5318 /* FileWvIn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FileWvIn.h; sourceTree = ""; }; + 68CAAF30185456F000DB5318 /* FileWvOut.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FileWvOut.h; sourceTree = ""; }; + 68CAAF31185456F000DB5318 /* Filter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Filter.h; sourceTree = ""; }; + 68CAAF32185456F000DB5318 /* Fir.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Fir.h; sourceTree = ""; }; + 68CAAF33185456F000DB5318 /* Flute.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Flute.h; sourceTree = ""; }; + 68CAAF34185456F000DB5318 /* FM.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FM.h; sourceTree = ""; }; + 68CAAF35185456F000DB5318 /* FMVoices.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FMVoices.h; sourceTree = ""; }; + 68CAAF36185456F000DB5318 /* FormSwep.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FormSwep.h; sourceTree = ""; }; + 68CAAF37185456F000DB5318 /* Function.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Function.h; sourceTree = ""; }; + 68CAAF38185456F000DB5318 /* Generator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Generator.h; sourceTree = ""; }; + 68CAAF39185456F000DB5318 /* Granulate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Granulate.h; sourceTree = ""; }; + 68CAAF3A185456F000DB5318 /* HevyMetl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HevyMetl.h; sourceTree = ""; }; + 68CAAF3B185456F000DB5318 /* Iir.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Iir.h; sourceTree = ""; }; + 68CAAF3C185456F000DB5318 /* InetWvIn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InetWvIn.h; sourceTree = ""; }; + 68CAAF3D185456F000DB5318 /* InetWvOut.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InetWvOut.h; sourceTree = ""; }; + 68CAAF3E185456F000DB5318 /* Instrmnt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Instrmnt.h; sourceTree = ""; }; + 68CAAF3F185456F000DB5318 /* JCRev.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JCRev.h; sourceTree = ""; }; + 68CAAF40185456F000DB5318 /* JetTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JetTable.h; sourceTree = ""; }; + 68CAAF41185456F000DB5318 /* LentPitShift.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LentPitShift.h; sourceTree = ""; }; + 68CAAF42185456F000DB5318 /* Mandolin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Mandolin.h; sourceTree = ""; }; + 68CAAF43185456F000DB5318 /* Mesh2D.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Mesh2D.h; sourceTree = ""; }; + 68CAAF44185456F000DB5318 /* Messager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Messager.h; sourceTree = ""; }; + 68CAAF45185456F000DB5318 /* MidiFileIn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MidiFileIn.h; sourceTree = ""; }; + 68CAAF46185456F000DB5318 /* Modal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Modal.h; sourceTree = ""; }; + 68CAAF47185456F000DB5318 /* ModalBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ModalBar.h; sourceTree = ""; }; + 68CAAF48185456F000DB5318 /* Modulate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Modulate.h; sourceTree = ""; }; + 68CAAF49185456F000DB5318 /* Moog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Moog.h; sourceTree = ""; }; + 68CAAF4A185456F000DB5318 /* Mutex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Mutex.h; sourceTree = ""; }; + 68CAAF4B185456F000DB5318 /* Noise.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Noise.h; sourceTree = ""; }; + 68CAAF4C185456F000DB5318 /* NRev.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NRev.h; sourceTree = ""; }; + 68CAAF4D185456F000DB5318 /* OnePole.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OnePole.h; sourceTree = ""; }; + 68CAAF4E185456F000DB5318 /* OneZero.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OneZero.h; sourceTree = ""; }; + 68CAAF4F185456F000DB5318 /* PercFlut.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PercFlut.h; sourceTree = ""; }; + 68CAAF50185456F000DB5318 /* Phonemes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Phonemes.h; sourceTree = ""; }; + 68CAAF51185456F000DB5318 /* PitShift.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PitShift.h; sourceTree = ""; }; + 68CAAF52185456F000DB5318 /* Plucked.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Plucked.h; sourceTree = ""; }; + 68CAAF53185456F100DB5318 /* PluckTwo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PluckTwo.h; sourceTree = ""; }; + 68CAAF54185456F100DB5318 /* PoleZero.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PoleZero.h; sourceTree = ""; }; + 68CAAF55185456F100DB5318 /* PRCRev.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PRCRev.h; sourceTree = ""; }; + 68CAAF56185456F100DB5318 /* ReedTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReedTable.h; sourceTree = ""; }; + 68CAAF57185456F100DB5318 /* Resonate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Resonate.h; sourceTree = ""; }; + 68CAAF58185456F100DB5318 /* Rhodey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Rhodey.h; sourceTree = ""; }; + 68CAAF59185456F100DB5318 /* Sampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Sampler.h; sourceTree = ""; }; + 68CAAF5A185456F100DB5318 /* Saxofony.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Saxofony.h; sourceTree = ""; }; + 68CAAF5B185456F100DB5318 /* Shakers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Shakers.h; sourceTree = ""; }; + 68CAAF5C185456F100DB5318 /* Simple.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Simple.h; sourceTree = ""; }; + 68CAAF5D185456F100DB5318 /* SineWave.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SineWave.h; sourceTree = ""; }; + 68CAAF5E185456F100DB5318 /* SingWave.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SingWave.h; sourceTree = ""; }; + 68CAAF5F185456F100DB5318 /* Sitar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Sitar.h; sourceTree = ""; }; + 68CAAF60185456F100DB5318 /* Skini.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Skini.h; sourceTree = ""; }; + 68CAAF61185456F100DB5318 /* Skini_msg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Skini_msg.h; sourceTree = ""; }; + 68CAAF62185456F100DB5318 /* Skini_tbl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Skini_tbl.h; sourceTree = ""; }; + 68CAAF63185456F100DB5318 /* Socket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Socket.h; sourceTree = ""; }; + 68CAAF64185456F100DB5318 /* Sphere.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Sphere.h; sourceTree = ""; }; + 68CAAF65185456F100DB5318 /* StifKarp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StifKarp.h; sourceTree = ""; }; + 68CAAF66185456F100DB5318 /* Stk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Stk.h; sourceTree = ""; }; + 68CAAF67185456F100DB5318 /* StkUdpSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StkUdpSocket.h; sourceTree = ""; }; + 68CAAF68185456F100DB5318 /* TapDelay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TapDelay.h; sourceTree = ""; }; + 68CAAF69185456F100DB5318 /* TcpClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TcpClient.h; sourceTree = ""; }; + 68CAAF6A185456F100DB5318 /* TcpServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TcpServer.h; sourceTree = ""; }; + 68CAAF6B185456F100DB5318 /* Thread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Thread.h; sourceTree = ""; }; + 68CAAF6C185456F100DB5318 /* TubeBell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TubeBell.h; sourceTree = ""; }; + 68CAAF6D185456F100DB5318 /* TwoPole.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TwoPole.h; sourceTree = ""; }; + 68CAAF6E185456F100DB5318 /* TwoZero.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TwoZero.h; sourceTree = ""; }; + 68CAAF6F185456F100DB5318 /* Vector3D.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Vector3D.h; sourceTree = ""; }; + 68CAAF70185456F100DB5318 /* Voicer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Voicer.h; sourceTree = ""; }; + 68CAAF71185456F100DB5318 /* VoicForm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VoicForm.h; sourceTree = ""; }; + 68CAAF72185456F100DB5318 /* Whistle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Whistle.h; sourceTree = ""; }; + 68CAAF73185456F100DB5318 /* Wurley.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Wurley.h; sourceTree = ""; }; + 68CAAF74185456F100DB5318 /* WvIn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WvIn.h; sourceTree = ""; }; + 68CAAF75185456F100DB5318 /* WvOut.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WvOut.h; sourceTree = ""; }; + 68CAAFA7185456F100DB5318 /* ADSR.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ADSR.cpp; sourceTree = ""; }; + 68CAAFA8185456F100DB5318 /* Asymp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Asymp.cpp; sourceTree = ""; }; + 68CAAFA9185456F100DB5318 /* BandedWG.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BandedWG.cpp; sourceTree = ""; }; + 68CAAFAA185456F100DB5318 /* BeeThree.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BeeThree.cpp; sourceTree = ""; }; + 68CAAFAB185456F100DB5318 /* BiQuad.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BiQuad.cpp; sourceTree = ""; }; + 68CAAFAC185456F100DB5318 /* Blit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Blit.cpp; sourceTree = ""; }; + 68CAAFAD185456F100DB5318 /* BlitSaw.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BlitSaw.cpp; sourceTree = ""; }; + 68CAAFAE185456F100DB5318 /* BlitSquare.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BlitSquare.cpp; sourceTree = ""; }; + 68CAAFAF185456F100DB5318 /* BlowBotl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BlowBotl.cpp; sourceTree = ""; }; + 68CAAFB0185456F100DB5318 /* BlowHole.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BlowHole.cpp; sourceTree = ""; }; + 68CAAFB1185456F100DB5318 /* Bowed.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Bowed.cpp; sourceTree = ""; }; + 68CAAFB2185456F100DB5318 /* Brass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Brass.cpp; sourceTree = ""; }; + 68CAAFB3185456F100DB5318 /* Chorus.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Chorus.cpp; sourceTree = ""; }; + 68CAAFB4185456F100DB5318 /* Clarinet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Clarinet.cpp; sourceTree = ""; }; + 68CAAFB5185456F100DB5318 /* Delay.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Delay.cpp; sourceTree = ""; }; + 68CAAFB6185456F100DB5318 /* DelayA.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DelayA.cpp; sourceTree = ""; }; + 68CAAFB7185456F100DB5318 /* DelayL.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DelayL.cpp; sourceTree = ""; }; + 68CAAFB8185456F100DB5318 /* Drummer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Drummer.cpp; sourceTree = ""; }; + 68CAAFB9185456F100DB5318 /* Echo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Echo.cpp; sourceTree = ""; }; + 68CAAFBA185456F100DB5318 /* Envelope.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Envelope.cpp; sourceTree = ""; }; + 68CAAFBB185456F100DB5318 /* FileLoop.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileLoop.cpp; sourceTree = ""; }; + 68CAAFBC185456F100DB5318 /* FileRead.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileRead.cpp; sourceTree = ""; }; + 68CAAFBD185456F100DB5318 /* FileWrite.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileWrite.cpp; sourceTree = ""; }; + 68CAAFBE185456F100DB5318 /* FileWvIn.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileWvIn.cpp; sourceTree = ""; }; + 68CAAFBF185456F100DB5318 /* FileWvOut.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileWvOut.cpp; sourceTree = ""; }; + 68CAAFC0185456F100DB5318 /* Fir.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Fir.cpp; sourceTree = ""; }; + 68CAAFC1185456F100DB5318 /* Flute.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Flute.cpp; sourceTree = ""; }; + 68CAAFC2185456F100DB5318 /* FM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FM.cpp; sourceTree = ""; }; + 68CAAFC3185456F100DB5318 /* FMVoices.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FMVoices.cpp; sourceTree = ""; }; + 68CAAFC4185456F100DB5318 /* FormSwep.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FormSwep.cpp; sourceTree = ""; }; + 68CAAFC5185456F100DB5318 /* Granulate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Granulate.cpp; sourceTree = ""; }; + 68CAAFC6185456F100DB5318 /* HevyMetl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HevyMetl.cpp; sourceTree = ""; }; + 68CAAFC7185456F100DB5318 /* Iir.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Iir.cpp; sourceTree = ""; }; + 68CAAFC8185456F100DB5318 /* InetWvIn.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InetWvIn.cpp; sourceTree = ""; }; + 68CAAFC9185456F100DB5318 /* InetWvOut.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InetWvOut.cpp; sourceTree = ""; }; + 68CAAFCA185456F100DB5318 /* JCRev.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JCRev.cpp; sourceTree = ""; }; + 68CAAFCB185456F100DB5318 /* LentPitShift.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LentPitShift.cpp; sourceTree = ""; }; + 68CAAFCC185456F100DB5318 /* Mandolin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Mandolin.cpp; sourceTree = ""; }; + 68CAAFCD185456F100DB5318 /* Mesh2D.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Mesh2D.cpp; sourceTree = ""; }; + 68CAAFCE185456F100DB5318 /* Messager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Messager.cpp; sourceTree = ""; }; + 68CAAFCF185456F100DB5318 /* MidiFileIn.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MidiFileIn.cpp; sourceTree = ""; }; + 68CAAFD0185456F100DB5318 /* Modal.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Modal.cpp; sourceTree = ""; }; + 68CAAFD1185456F100DB5318 /* ModalBar.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ModalBar.cpp; sourceTree = ""; }; + 68CAAFD2185456F100DB5318 /* Modulate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Modulate.cpp; sourceTree = ""; }; + 68CAAFD3185456F100DB5318 /* Moog.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Moog.cpp; sourceTree = ""; }; + 68CAAFD4185456F100DB5318 /* Mutex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Mutex.cpp; sourceTree = ""; }; + 68CAAFD5185456F100DB5318 /* Noise.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Noise.cpp; sourceTree = ""; }; + 68CAAFD6185456F100DB5318 /* NRev.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NRev.cpp; sourceTree = ""; }; + 68CAAFD7185456F100DB5318 /* OnePole.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OnePole.cpp; sourceTree = ""; }; + 68CAAFD8185456F100DB5318 /* OneZero.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OneZero.cpp; sourceTree = ""; }; + 68CAAFD9185456F100DB5318 /* PercFlut.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PercFlut.cpp; sourceTree = ""; }; + 68CAAFDA185456F100DB5318 /* Phonemes.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Phonemes.cpp; sourceTree = ""; }; + 68CAAFDB185456F100DB5318 /* PitShift.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PitShift.cpp; sourceTree = ""; }; + 68CAAFDC185456F100DB5318 /* Plucked.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Plucked.cpp; sourceTree = ""; }; + 68CAAFDD185456F100DB5318 /* PluckTwo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PluckTwo.cpp; sourceTree = ""; }; + 68CAAFDE185456F100DB5318 /* PoleZero.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PoleZero.cpp; sourceTree = ""; }; + 68CAAFDF185456F100DB5318 /* PRCRev.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PRCRev.cpp; sourceTree = ""; }; + 68CAAFE0185456F100DB5318 /* Resonate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Resonate.cpp; sourceTree = ""; }; + 68CAAFE1185456F100DB5318 /* Rhodey.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Rhodey.cpp; sourceTree = ""; }; + 68CAAFE2185456F100DB5318 /* Sampler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Sampler.cpp; sourceTree = ""; }; + 68CAAFE3185456F100DB5318 /* Saxofony.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Saxofony.cpp; sourceTree = ""; }; + 68CAAFE4185456F100DB5318 /* Shakers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Shakers.cpp; sourceTree = ""; }; + 68CAAFE5185456F100DB5318 /* Simple.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Simple.cpp; sourceTree = ""; }; + 68CAAFE6185456F100DB5318 /* SineWave.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SineWave.cpp; sourceTree = ""; }; + 68CAAFE7185456F100DB5318 /* SingWave.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SingWave.cpp; sourceTree = ""; }; + 68CAAFE8185456F100DB5318 /* Sitar.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Sitar.cpp; sourceTree = ""; }; + 68CAAFE9185456F100DB5318 /* Skini.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Skini.cpp; sourceTree = ""; }; + 68CAAFEA185456F100DB5318 /* Socket.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Socket.cpp; sourceTree = ""; }; + 68CAAFEB185456F100DB5318 /* Sphere.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Sphere.cpp; sourceTree = ""; }; + 68CAAFEC185456F100DB5318 /* StifKarp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StifKarp.cpp; sourceTree = ""; }; + 68CAAFED185456F100DB5318 /* Stk.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Stk.mm; sourceTree = ""; }; + 68CAAFEE185456F100DB5318 /* StkUdpSocket.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StkUdpSocket.cpp; sourceTree = ""; }; + 68CAAFEF185456F100DB5318 /* TapDelay.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TapDelay.cpp; sourceTree = ""; }; + 68CAAFF0185456F100DB5318 /* TcpClient.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TcpClient.cpp; sourceTree = ""; }; + 68CAAFF1185456F100DB5318 /* TcpServer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TcpServer.cpp; sourceTree = ""; }; + 68CAAFF2185456F100DB5318 /* Thread.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Thread.cpp; sourceTree = ""; }; + 68CAAFF3185456F100DB5318 /* TubeBell.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TubeBell.cpp; sourceTree = ""; }; + 68CAAFF4185456F100DB5318 /* TwoPole.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TwoPole.cpp; sourceTree = ""; }; + 68CAAFF5185456F100DB5318 /* TwoZero.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TwoZero.cpp; sourceTree = ""; }; + 68CAAFF6185456F100DB5318 /* Voicer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Voicer.cpp; sourceTree = ""; }; + 68CAAFF7185456F100DB5318 /* VoicForm.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VoicForm.cpp; sourceTree = ""; }; + 68CAAFF8185456F100DB5318 /* Whistle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Whistle.cpp; sourceTree = ""; }; + 68CAAFF9185456F100DB5318 /* Wurley.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Wurley.cpp; sourceTree = ""; }; 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 = ""; }; - 11CEB50DDC2D442F828EFE49 /* iosynthApp.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.cpp; path = ../src/iosynthApp.cpp; sourceTree = ""; name = iosynthApp.cpp; }; - 359BF798F4294C6BB6836DC9 /* Resources.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ../include/Resources.h; sourceTree = ""; name = Resources.h; }; - C9BCD27FE5CA496094E38DC7 /* CinderApp_ios.png */ = {isa = PBXFileReference; lastKnownFileType = "\"\""; path = ../resources/CinderApp_ios.png; sourceTree = ""; name = CinderApp_ios.png; }; - 27664426CDC048598E09896C /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = "\"\""; path = "Default-568h@2x.png"; sourceTree = ""; name = "Default-568h@2x.png"; }; - 3DCA5ADB4E5F41B8BC4AFF40 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; name = Info.plist; }; - 5F24CD9B8A5949E0B1828046 /* iosynth_Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = "\"\""; path = iosynth_Prefix.pch; sourceTree = ""; name = iosynth_Prefix.pch; }; + C9BCD27FE5CA496094E38DC7 /* CinderApp_ios.png */ = {isa = PBXFileReference; lastKnownFileType = "\"\""; name = CinderApp_ios.png; path = ../resources/CinderApp_ios.png; sourceTree = ""; }; + 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 */ @@ -88,7 +343,7 @@ 00692BC414FF149000D0A05E = { isa = PBXGroup; children = ( - 99692BD914FF149000DFFFFF /* Blocks */, + 68CAAF0D185456CC00DB5318 /* lib */, 99692BD914FF149000D0A05F /* Headers */, 00692BD914FF149000D0A05E /* Source */, 00692BD914FF149000D0FFFF /* Resources */, @@ -124,39 +379,257 @@ name = Frameworks; sourceTree = ""; }; - 99692BD914FF149000DFFFFF /* Blocks */ = { + 00692BD914FF149000D0A05E /* Source */ = { isa = PBXGroup; children = ( + 11CEB50DDC2D442F828EFE49 /* iosynthApp.cpp */, + 68CAAF0918544B0700DB5318 /* iosynthApp.h */, + 68CAAF0A1854556E00DB5318 /* Voice.cpp */, + 68CAAF0B1854556E00DB5318 /* Voice.h */, ); - name = Blocks; + name = Source; sourceTree = ""; }; - 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 = ""; }; - 00692BD914FF149000D0A05E /* Source */ = { + 68CAAF0D185456CC00DB5318 /* lib */ = { isa = PBXGroup; children = ( - 11CEB50DDC2D442F828EFE49 /* iosynthApp.cpp */, + 68CAAF0E185456F000DB5318 /* Maximilian */, + 68CAAF11185456F000DB5318 /* MoMu-STK-1.0.0 */, ); - name = Source; + name = lib; sourceTree = ""; }; - 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 = ""; + }; + 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 = ""; + }; + 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 = ""; + }; + 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 = ""; + }; + 99692BD914FF149000D0A05F /* Headers */ = { + isa = PBXGroup; + children = ( + 359BF798F4294C6BB6836DC9 /* Resources.h */, + 5F24CD9B8A5949E0B1828046 /* iosynth_Prefix.pch */, + ); + name = Headers; sourceTree = ""; }; /* End PBXGroup section */ @@ -184,6 +657,8 @@ /* Begin PBXProject section */ 00692BC614FF149000D0A05E /* Project object */ = { isa = PBXProject; + attributes = { + }; buildConfigurationList = 00692BC914FF149000D0A05E /* Build configuration list for PBXProject "iosynth" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; @@ -219,7 +694,92 @@ 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; }; @@ -229,13 +789,14 @@ 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; @@ -248,11 +809,10 @@ 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; @@ -260,26 +820,26 @@ 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; }; @@ -287,10 +847,8 @@ 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", @@ -299,6 +857,8 @@ "\"$(CINDER_PATH)/lib/libcinder-iphone-sim_d.a\"", "-lz", ); + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = app; }; name = Debug; }; @@ -306,10 +866,8 @@ 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", @@ -318,6 +876,8 @@ "\"$(CINDER_PATH)/lib/libcinder-iphone-sim.a\"", "-lz", ); + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = app; }; name = Release; };