From 00b78ba1840dc6ff73b9fffd329299927f45f7a5 Mon Sep 17 00:00:00 2001 From: Gabriel Dunne Date: Sun, 8 Dec 2013 18:32:19 -0800 Subject: [PATCH] Compiling --- .gitignore | 1 + lib/Maximilian/maximilian.cpp | 1270 +++++++++++++++++++ lib/Maximilian/maximilian.h | 501 ++++++++ lib/MoMu-STK-1.0.0/AUTHORS | 32 + lib/MoMu-STK-1.0.0/COPYING | 1 + lib/MoMu-STK-1.0.0/DEVELOPER | 6 + lib/MoMu-STK-1.0.0/INSTALL | 11 + lib/MoMu-STK-1.0.0/README | 232 ++++ lib/MoMu-STK-1.0.0/TODO | 1 + lib/MoMu-STK-1.0.0/VERSIONS | 18 + lib/MoMu-STK-1.0.0/include/ADSR.h | 163 +++ lib/MoMu-STK-1.0.0/include/Asymp.h | 143 +++ lib/MoMu-STK-1.0.0/include/BandedWG.h | 116 ++ lib/MoMu-STK-1.0.0/include/BeeThree.h | 90 ++ lib/MoMu-STK-1.0.0/include/BiQuad.h | 183 +++ lib/MoMu-STK-1.0.0/include/Blit.h | 151 +++ lib/MoMu-STK-1.0.0/include/BlitSaw.h | 148 +++ lib/MoMu-STK-1.0.0/include/BlitSquare.h | 170 +++ lib/MoMu-STK-1.0.0/include/BlowBotl.h | 107 ++ lib/MoMu-STK-1.0.0/include/BlowHole.h | 149 +++ lib/MoMu-STK-1.0.0/include/BowTable.h | 140 ++ lib/MoMu-STK-1.0.0/include/Bowed.h | 112 ++ lib/MoMu-STK-1.0.0/include/Brass.h | 110 ++ lib/MoMu-STK-1.0.0/include/Chorus.h | 168 +++ lib/MoMu-STK-1.0.0/include/Clarinet.h | 116 ++ lib/MoMu-STK-1.0.0/include/Delay.h | 182 +++ lib/MoMu-STK-1.0.0/include/DelayA.h | 201 +++ lib/MoMu-STK-1.0.0/include/DelayL.h | 197 +++ lib/MoMu-STK-1.0.0/include/Drummer.h | 92 ++ lib/MoMu-STK-1.0.0/include/Echo.h | 120 ++ lib/MoMu-STK-1.0.0/include/Effect.h | 79 ++ lib/MoMu-STK-1.0.0/include/Envelope.h | 162 +++ lib/MoMu-STK-1.0.0/include/FM.h | 112 ++ lib/MoMu-STK-1.0.0/include/FMVoices.h | 98 ++ lib/MoMu-STK-1.0.0/include/FileLoop.h | 161 +++ lib/MoMu-STK-1.0.0/include/FileRead.h | 133 ++ lib/MoMu-STK-1.0.0/include/FileWrite.h | 116 ++ lib/MoMu-STK-1.0.0/include/FileWvIn.h | 193 +++ lib/MoMu-STK-1.0.0/include/FileWvOut.h | 102 ++ lib/MoMu-STK-1.0.0/include/Filter.h | 86 ++ lib/MoMu-STK-1.0.0/include/Fir.h | 155 +++ lib/MoMu-STK-1.0.0/include/Flute.h | 129 ++ lib/MoMu-STK-1.0.0/include/FormSwep.h | 188 +++ lib/MoMu-STK-1.0.0/include/Function.h | 41 + lib/MoMu-STK-1.0.0/include/Generator.h | 50 + lib/MoMu-STK-1.0.0/include/Granulate.h | 209 +++ lib/MoMu-STK-1.0.0/include/HevyMetl.h | 89 ++ lib/MoMu-STK-1.0.0/include/Iir.h | 202 +++ lib/MoMu-STK-1.0.0/include/InetWvIn.h | 157 +++ lib/MoMu-STK-1.0.0/include/InetWvOut.h | 98 ++ lib/MoMu-STK-1.0.0/include/Instrmnt.h | 129 ++ lib/MoMu-STK-1.0.0/include/JCRev.h | 158 +++ lib/MoMu-STK-1.0.0/include/JetTable.h | 112 ++ lib/MoMu-STK-1.0.0/include/LentPitShift.h | 267 ++++ lib/MoMu-STK-1.0.0/include/Mandolin.h | 105 ++ lib/MoMu-STK-1.0.0/include/Mesh2D.h | 107 ++ lib/MoMu-STK-1.0.0/include/Messager.h | 166 +++ lib/MoMu-STK-1.0.0/include/MidiFileIn.h | 135 ++ lib/MoMu-STK-1.0.0/include/Modal.h | 117 ++ lib/MoMu-STK-1.0.0/include/ModalBar.h | 65 + lib/MoMu-STK-1.0.0/include/Modulate.h | 108 ++ lib/MoMu-STK-1.0.0/include/Moog.h | 88 ++ lib/MoMu-STK-1.0.0/include/Mutex.h | 74 ++ lib/MoMu-STK-1.0.0/include/NRev.h | 160 +++ lib/MoMu-STK-1.0.0/include/Noise.h | 83 ++ lib/MoMu-STK-1.0.0/include/OnePole.h | 133 ++ lib/MoMu-STK-1.0.0/include/OneZero.h | 134 ++ lib/MoMu-STK-1.0.0/include/PRCRev.h | 140 ++ lib/MoMu-STK-1.0.0/include/PercFlut.h | 90 ++ lib/MoMu-STK-1.0.0/include/Phonemes.h | 54 + lib/MoMu-STK-1.0.0/include/PitShift.h | 107 ++ lib/MoMu-STK-1.0.0/include/PluckTwo.h | 89 ++ lib/MoMu-STK-1.0.0/include/Plucked.h | 78 ++ lib/MoMu-STK-1.0.0/include/PoleZero.h | 112 ++ lib/MoMu-STK-1.0.0/include/ReedTable.h | 143 +++ lib/MoMu-STK-1.0.0/include/Resonate.h | 90 ++ lib/MoMu-STK-1.0.0/include/Rhodey.h | 91 ++ lib/MoMu-STK-1.0.0/include/Sampler.h | 68 + lib/MoMu-STK-1.0.0/include/Saxofony.h | 129 ++ lib/MoMu-STK-1.0.0/include/Shakers.h | 131 ++ lib/MoMu-STK-1.0.0/include/Simple.h | 92 ++ lib/MoMu-STK-1.0.0/include/SineWave.h | 159 +++ lib/MoMu-STK-1.0.0/include/SingWave.h | 136 ++ lib/MoMu-STK-1.0.0/include/Sitar.h | 92 ++ lib/MoMu-STK-1.0.0/include/Skini.h | 121 ++ lib/MoMu-STK-1.0.0/include/Skini_msg.h | 137 ++ lib/MoMu-STK-1.0.0/include/Skini_tbl.h | 136 ++ lib/MoMu-STK-1.0.0/include/Socket.h | 89 ++ lib/MoMu-STK-1.0.0/include/Sphere.h | 79 ++ lib/MoMu-STK-1.0.0/include/StifKarp.h | 117 ++ lib/MoMu-STK-1.0.0/include/Stk.h | 541 ++++++++ lib/MoMu-STK-1.0.0/include/StkUdpSocket.h | 76 ++ lib/MoMu-STK-1.0.0/include/TapDelay.h | 216 ++++ lib/MoMu-STK-1.0.0/include/TcpClient.h | 65 + lib/MoMu-STK-1.0.0/include/TcpServer.h | 65 + lib/MoMu-STK-1.0.0/include/Thread.h | 98 ++ lib/MoMu-STK-1.0.0/include/TubeBell.h | 88 ++ lib/MoMu-STK-1.0.0/include/TwoPole.h | 151 +++ lib/MoMu-STK-1.0.0/include/TwoZero.h | 147 +++ lib/MoMu-STK-1.0.0/include/Vector3D.h | 68 + lib/MoMu-STK-1.0.0/include/VoicForm.h | 124 ++ lib/MoMu-STK-1.0.0/include/Voicer.h | 219 ++++ lib/MoMu-STK-1.0.0/include/Whistle.h | 91 ++ lib/MoMu-STK-1.0.0/include/Wurley.h | 91 ++ lib/MoMu-STK-1.0.0/include/WvIn.h | 46 + lib/MoMu-STK-1.0.0/include/WvOut.h | 85 ++ lib/MoMu-STK-1.0.0/rawwaves/ahh.raw | Bin 0 -> 184 bytes lib/MoMu-STK-1.0.0/rawwaves/bassdrum.raw | Bin 0 -> 4288 bytes lib/MoMu-STK-1.0.0/rawwaves/britestk.raw | Bin 0 -> 4096 bytes lib/MoMu-STK-1.0.0/rawwaves/cowbell1.raw | Bin 0 -> 6438 bytes lib/MoMu-STK-1.0.0/rawwaves/crashcym.raw | Bin 0 -> 40776 bytes lib/MoMu-STK-1.0.0/rawwaves/dope.raw | Bin 0 -> 20480 bytes lib/MoMu-STK-1.0.0/rawwaves/eee.raw | Bin 0 -> 184 bytes lib/MoMu-STK-1.0.0/rawwaves/fwavblnk.raw | Bin 0 -> 512 bytes lib/MoMu-STK-1.0.0/rawwaves/halfwave.raw | Bin 0 -> 512 bytes lib/MoMu-STK-1.0.0/rawwaves/hihatcym.raw | Bin 0 -> 4976 bytes lib/MoMu-STK-1.0.0/rawwaves/impuls10.raw | Bin 0 -> 512 bytes lib/MoMu-STK-1.0.0/rawwaves/impuls20.raw | Bin 0 -> 512 bytes lib/MoMu-STK-1.0.0/rawwaves/impuls40.raw | Bin 0 -> 512 bytes lib/MoMu-STK-1.0.0/rawwaves/makefunc.c | 54 + lib/MoMu-STK-1.0.0/rawwaves/makemidi.c | 33 + lib/MoMu-STK-1.0.0/rawwaves/makewavs.c | 116 ++ lib/MoMu-STK-1.0.0/rawwaves/mand1.raw | Bin 0 -> 2048 bytes lib/MoMu-STK-1.0.0/rawwaves/mand10.raw | Bin 0 -> 2048 bytes lib/MoMu-STK-1.0.0/rawwaves/mand11.raw | Bin 0 -> 2048 bytes lib/MoMu-STK-1.0.0/rawwaves/mand12.raw | Bin 0 -> 2048 bytes lib/MoMu-STK-1.0.0/rawwaves/mand2.raw | Bin 0 -> 2048 bytes lib/MoMu-STK-1.0.0/rawwaves/mand3.raw | Bin 0 -> 2048 bytes lib/MoMu-STK-1.0.0/rawwaves/mand4.raw | Bin 0 -> 2048 bytes lib/MoMu-STK-1.0.0/rawwaves/mand5.raw | Bin 0 -> 2048 bytes lib/MoMu-STK-1.0.0/rawwaves/mand6.raw | Bin 0 -> 2048 bytes lib/MoMu-STK-1.0.0/rawwaves/mand7.raw | Bin 0 -> 2048 bytes lib/MoMu-STK-1.0.0/rawwaves/mand8.raw | Bin 0 -> 2048 bytes lib/MoMu-STK-1.0.0/rawwaves/mand9.raw | Bin 0 -> 2048 bytes lib/MoMu-STK-1.0.0/rawwaves/mandpluk.raw | Bin 0 -> 8900 bytes lib/MoMu-STK-1.0.0/rawwaves/marmstk1.raw | Bin 0 -> 512 bytes lib/MoMu-STK-1.0.0/rawwaves/ooo.raw | Bin 0 -> 184 bytes lib/MoMu-STK-1.0.0/rawwaves/peksblnk.raw | Bin 0 -> 512 bytes lib/MoMu-STK-1.0.0/rawwaves/ppksblnk.raw | Bin 0 -> 512 bytes lib/MoMu-STK-1.0.0/rawwaves/ridecymb.raw | Bin 0 -> 32394 bytes lib/MoMu-STK-1.0.0/rawwaves/silence.raw | Bin 0 -> 448 bytes lib/MoMu-STK-1.0.0/rawwaves/sine.c | 22 + lib/MoMu-STK-1.0.0/rawwaves/sineblnk.raw | Bin 0 -> 512 bytes lib/MoMu-STK-1.0.0/rawwaves/sinewave.raw | Bin 0 -> 2048 bytes lib/MoMu-STK-1.0.0/rawwaves/snardrum.raw | Bin 0 -> 16660 bytes lib/MoMu-STK-1.0.0/rawwaves/snglpeak.raw | Bin 0 -> 512 bytes lib/MoMu-STK-1.0.0/rawwaves/tambourn.raw | Bin 0 -> 9240 bytes lib/MoMu-STK-1.0.0/rawwaves/tomhidrm.raw | Bin 0 -> 27642 bytes lib/MoMu-STK-1.0.0/rawwaves/tomlowdr.raw | Bin 0 -> 39200 bytes lib/MoMu-STK-1.0.0/rawwaves/tommiddr.raw | Bin 0 -> 28292 bytes lib/MoMu-STK-1.0.0/rawwaves/twopeaks.raw | Bin 0 -> 512 bytes lib/MoMu-STK-1.0.0/src/ADSR.cpp | 155 +++ lib/MoMu-STK-1.0.0/src/Asymp.cpp | 103 ++ lib/MoMu-STK-1.0.0/src/BandedWG.cpp | 380 ++++++ lib/MoMu-STK-1.0.0/src/BeeThree.cpp | 84 ++ lib/MoMu-STK-1.0.0/src/BiQuad.cpp | 81 ++ lib/MoMu-STK-1.0.0/src/Blit.cpp | 78 ++ lib/MoMu-STK-1.0.0/src/BlitSaw.cpp | 91 ++ lib/MoMu-STK-1.0.0/src/BlitSquare.cpp | 95 ++ lib/MoMu-STK-1.0.0/src/BlowBotl.cpp | 129 ++ lib/MoMu-STK-1.0.0/src/BlowHole.cpp | 224 ++++ lib/MoMu-STK-1.0.0/src/Bowed.cpp | 162 +++ lib/MoMu-STK-1.0.0/src/Brass.cpp | 162 +++ lib/MoMu-STK-1.0.0/src/Chorus.cpp | 46 + lib/MoMu-STK-1.0.0/src/Clarinet.cpp | 139 ++ lib/MoMu-STK-1.0.0/src/Delay.cpp | 130 ++ lib/MoMu-STK-1.0.0/src/DelayA.cpp | 130 ++ lib/MoMu-STK-1.0.0/src/DelayL.cpp | 109 ++ lib/MoMu-STK-1.0.0/src/Drummer.cpp | 160 +++ lib/MoMu-STK-1.0.0/src/Echo.cpp | 54 + lib/MoMu-STK-1.0.0/src/Envelope.cpp | 50 + lib/MoMu-STK-1.0.0/src/FM.cpp | 197 +++ lib/MoMu-STK-1.0.0/src/FMVoices.cpp | 169 +++ lib/MoMu-STK-1.0.0/src/FileLoop.cpp | 224 ++++ lib/MoMu-STK-1.0.0/src/FileRead.cpp | 737 +++++++++++ lib/MoMu-STK-1.0.0/src/FileWrite.cpp | 707 +++++++++++ lib/MoMu-STK-1.0.0/src/FileWvIn.cpp | 258 ++++ lib/MoMu-STK-1.0.0/src/FileWvOut.cpp | 140 ++ lib/MoMu-STK-1.0.0/src/Fir.cpp | 73 ++ lib/MoMu-STK-1.0.0/src/Flute.cpp | 180 +++ lib/MoMu-STK-1.0.0/src/FormSwep.cpp | 110 ++ lib/MoMu-STK-1.0.0/src/Granulate.cpp | 294 +++++ lib/MoMu-STK-1.0.0/src/HevyMetl.cpp | 80 ++ lib/MoMu-STK-1.0.0/src/Iir.cpp | 125 ++ lib/MoMu-STK-1.0.0/src/InetWvIn.cpp | 320 +++++ lib/MoMu-STK-1.0.0/src/InetWvOut.cpp | 230 ++++ lib/MoMu-STK-1.0.0/src/JCRev.cpp | 120 ++ lib/MoMu-STK-1.0.0/src/LentPitShift.cpp | 52 + lib/MoMu-STK-1.0.0/src/Mandolin.cpp | 160 +++ lib/MoMu-STK-1.0.0/src/Mesh2D.cpp | 400 ++++++ lib/MoMu-STK-1.0.0/src/Messager.cpp | 428 +++++++ lib/MoMu-STK-1.0.0/src/MidiFileIn.cpp | 367 ++++++ lib/MoMu-STK-1.0.0/src/Modal.cpp | 181 +++ lib/MoMu-STK-1.0.0/src/ModalBar.cpp | 200 +++ lib/MoMu-STK-1.0.0/src/Modulate.cpp | 49 + lib/MoMu-STK-1.0.0/src/Moog.cpp | 122 ++ lib/MoMu-STK-1.0.0/src/Mutex.cpp | 104 ++ lib/MoMu-STK-1.0.0/src/NRev.cpp | 110 ++ lib/MoMu-STK-1.0.0/src/Noise.cpp | 34 + lib/MoMu-STK-1.0.0/src/OnePole.cpp | 50 + lib/MoMu-STK-1.0.0/src/OneZero.cpp | 48 + lib/MoMu-STK-1.0.0/src/PRCRev.cpp | 111 ++ lib/MoMu-STK-1.0.0/src/PercFlut.cpp | 83 ++ lib/MoMu-STK-1.0.0/src/Phonemes.cpp | 298 +++++ lib/MoMu-STK-1.0.0/src/PitShift.cpp | 88 ++ lib/MoMu-STK-1.0.0/src/PluckTwo.cpp | 132 ++ lib/MoMu-STK-1.0.0/src/Plucked.cpp | 117 ++ lib/MoMu-STK-1.0.0/src/PoleZero.cpp | 58 + lib/MoMu-STK-1.0.0/src/Resonate.cpp | 137 ++ lib/MoMu-STK-1.0.0/src/Rhodey.cpp | 90 ++ lib/MoMu-STK-1.0.0/src/Sampler.cpp | 58 + lib/MoMu-STK-1.0.0/src/Saxofony.cpp | 179 +++ lib/MoMu-STK-1.0.0/src/Shakers.cpp | 1135 +++++++++++++++++ lib/MoMu-STK-1.0.0/src/Simple.cpp | 115 ++ lib/MoMu-STK-1.0.0/src/SineWave.cpp | 78 ++ lib/MoMu-STK-1.0.0/src/SingWave.cpp | 53 + lib/MoMu-STK-1.0.0/src/Sitar.cpp | 102 ++ lib/MoMu-STK-1.0.0/src/Skini.cpp | 222 ++++ lib/MoMu-STK-1.0.0/src/Socket.cpp | 78 ++ lib/MoMu-STK-1.0.0/src/Sphere.cpp | 50 + lib/MoMu-STK-1.0.0/src/StifKarp.cpp | 216 ++++ lib/MoMu-STK-1.0.0/src/Stk.mm | 345 +++++ lib/MoMu-STK-1.0.0/src/StkUdpSocket.cpp | 109 ++ lib/MoMu-STK-1.0.0/src/TapDelay.cpp | 104 ++ lib/MoMu-STK-1.0.0/src/TcpClient.cpp | 104 ++ lib/MoMu-STK-1.0.0/src/TcpServer.cpp | 99 ++ lib/MoMu-STK-1.0.0/src/Thread.cpp | 106 ++ lib/MoMu-STK-1.0.0/src/TubeBell.cpp | 83 ++ lib/MoMu-STK-1.0.0/src/TwoPole.cpp | 65 + lib/MoMu-STK-1.0.0/src/TwoZero.cpp | 63 + lib/MoMu-STK-1.0.0/src/VoicForm.cpp | 201 +++ lib/MoMu-STK-1.0.0/src/Voicer.cpp | 219 ++++ lib/MoMu-STK-1.0.0/src/Whistle.cpp | 262 ++++ lib/MoMu-STK-1.0.0/src/Wurley.cpp | 92 ++ src/Voice.cpp | 182 +++ src/Voice.h | 76 ++ src/iosynthApp.cpp | 30 +- src/iosynthApp.h | 69 + xcode_ios/iosynth.xcodeproj/project.pbxproj | 690 +++++++++- 239 files changed, 29559 insertions(+), 79 deletions(-) create mode 100644 .gitignore create mode 100644 lib/Maximilian/maximilian.cpp create mode 100755 lib/Maximilian/maximilian.h create mode 100644 lib/MoMu-STK-1.0.0/AUTHORS create mode 100644 lib/MoMu-STK-1.0.0/COPYING create mode 100644 lib/MoMu-STK-1.0.0/DEVELOPER create mode 100644 lib/MoMu-STK-1.0.0/INSTALL create mode 100644 lib/MoMu-STK-1.0.0/README create mode 100644 lib/MoMu-STK-1.0.0/TODO create mode 100644 lib/MoMu-STK-1.0.0/VERSIONS create mode 100644 lib/MoMu-STK-1.0.0/include/ADSR.h create mode 100644 lib/MoMu-STK-1.0.0/include/Asymp.h create mode 100644 lib/MoMu-STK-1.0.0/include/BandedWG.h create mode 100644 lib/MoMu-STK-1.0.0/include/BeeThree.h create mode 100644 lib/MoMu-STK-1.0.0/include/BiQuad.h create mode 100644 lib/MoMu-STK-1.0.0/include/Blit.h create mode 100644 lib/MoMu-STK-1.0.0/include/BlitSaw.h create mode 100644 lib/MoMu-STK-1.0.0/include/BlitSquare.h create mode 100644 lib/MoMu-STK-1.0.0/include/BlowBotl.h create mode 100644 lib/MoMu-STK-1.0.0/include/BlowHole.h create mode 100644 lib/MoMu-STK-1.0.0/include/BowTable.h create mode 100644 lib/MoMu-STK-1.0.0/include/Bowed.h create mode 100644 lib/MoMu-STK-1.0.0/include/Brass.h create mode 100644 lib/MoMu-STK-1.0.0/include/Chorus.h create mode 100644 lib/MoMu-STK-1.0.0/include/Clarinet.h create mode 100644 lib/MoMu-STK-1.0.0/include/Delay.h create mode 100644 lib/MoMu-STK-1.0.0/include/DelayA.h create mode 100644 lib/MoMu-STK-1.0.0/include/DelayL.h create mode 100644 lib/MoMu-STK-1.0.0/include/Drummer.h create mode 100644 lib/MoMu-STK-1.0.0/include/Echo.h create mode 100644 lib/MoMu-STK-1.0.0/include/Effect.h create mode 100644 lib/MoMu-STK-1.0.0/include/Envelope.h create mode 100644 lib/MoMu-STK-1.0.0/include/FM.h create mode 100644 lib/MoMu-STK-1.0.0/include/FMVoices.h create mode 100644 lib/MoMu-STK-1.0.0/include/FileLoop.h create mode 100644 lib/MoMu-STK-1.0.0/include/FileRead.h create mode 100644 lib/MoMu-STK-1.0.0/include/FileWrite.h create mode 100644 lib/MoMu-STK-1.0.0/include/FileWvIn.h create mode 100644 lib/MoMu-STK-1.0.0/include/FileWvOut.h create mode 100644 lib/MoMu-STK-1.0.0/include/Filter.h create mode 100644 lib/MoMu-STK-1.0.0/include/Fir.h create mode 100644 lib/MoMu-STK-1.0.0/include/Flute.h create mode 100644 lib/MoMu-STK-1.0.0/include/FormSwep.h create mode 100644 lib/MoMu-STK-1.0.0/include/Function.h create mode 100644 lib/MoMu-STK-1.0.0/include/Generator.h create mode 100644 lib/MoMu-STK-1.0.0/include/Granulate.h create mode 100644 lib/MoMu-STK-1.0.0/include/HevyMetl.h create mode 100644 lib/MoMu-STK-1.0.0/include/Iir.h create mode 100644 lib/MoMu-STK-1.0.0/include/InetWvIn.h create mode 100644 lib/MoMu-STK-1.0.0/include/InetWvOut.h create mode 100644 lib/MoMu-STK-1.0.0/include/Instrmnt.h create mode 100644 lib/MoMu-STK-1.0.0/include/JCRev.h create mode 100644 lib/MoMu-STK-1.0.0/include/JetTable.h create mode 100644 lib/MoMu-STK-1.0.0/include/LentPitShift.h create mode 100644 lib/MoMu-STK-1.0.0/include/Mandolin.h create mode 100644 lib/MoMu-STK-1.0.0/include/Mesh2D.h create mode 100644 lib/MoMu-STK-1.0.0/include/Messager.h create mode 100644 lib/MoMu-STK-1.0.0/include/MidiFileIn.h create mode 100644 lib/MoMu-STK-1.0.0/include/Modal.h create mode 100644 lib/MoMu-STK-1.0.0/include/ModalBar.h create mode 100644 lib/MoMu-STK-1.0.0/include/Modulate.h create mode 100644 lib/MoMu-STK-1.0.0/include/Moog.h create mode 100644 lib/MoMu-STK-1.0.0/include/Mutex.h create mode 100644 lib/MoMu-STK-1.0.0/include/NRev.h create mode 100644 lib/MoMu-STK-1.0.0/include/Noise.h create mode 100644 lib/MoMu-STK-1.0.0/include/OnePole.h create mode 100644 lib/MoMu-STK-1.0.0/include/OneZero.h create mode 100644 lib/MoMu-STK-1.0.0/include/PRCRev.h create mode 100644 lib/MoMu-STK-1.0.0/include/PercFlut.h create mode 100644 lib/MoMu-STK-1.0.0/include/Phonemes.h create mode 100644 lib/MoMu-STK-1.0.0/include/PitShift.h create mode 100644 lib/MoMu-STK-1.0.0/include/PluckTwo.h create mode 100644 lib/MoMu-STK-1.0.0/include/Plucked.h create mode 100644 lib/MoMu-STK-1.0.0/include/PoleZero.h create mode 100644 lib/MoMu-STK-1.0.0/include/ReedTable.h create mode 100644 lib/MoMu-STK-1.0.0/include/Resonate.h create mode 100644 lib/MoMu-STK-1.0.0/include/Rhodey.h create mode 100644 lib/MoMu-STK-1.0.0/include/Sampler.h create mode 100644 lib/MoMu-STK-1.0.0/include/Saxofony.h create mode 100644 lib/MoMu-STK-1.0.0/include/Shakers.h create mode 100644 lib/MoMu-STK-1.0.0/include/Simple.h create mode 100644 lib/MoMu-STK-1.0.0/include/SineWave.h create mode 100644 lib/MoMu-STK-1.0.0/include/SingWave.h create mode 100644 lib/MoMu-STK-1.0.0/include/Sitar.h create mode 100644 lib/MoMu-STK-1.0.0/include/Skini.h create mode 100644 lib/MoMu-STK-1.0.0/include/Skini_msg.h create mode 100644 lib/MoMu-STK-1.0.0/include/Skini_tbl.h create mode 100644 lib/MoMu-STK-1.0.0/include/Socket.h create mode 100644 lib/MoMu-STK-1.0.0/include/Sphere.h create mode 100644 lib/MoMu-STK-1.0.0/include/StifKarp.h create mode 100644 lib/MoMu-STK-1.0.0/include/Stk.h create mode 100644 lib/MoMu-STK-1.0.0/include/StkUdpSocket.h create mode 100644 lib/MoMu-STK-1.0.0/include/TapDelay.h create mode 100644 lib/MoMu-STK-1.0.0/include/TcpClient.h create mode 100644 lib/MoMu-STK-1.0.0/include/TcpServer.h create mode 100644 lib/MoMu-STK-1.0.0/include/Thread.h create mode 100644 lib/MoMu-STK-1.0.0/include/TubeBell.h create mode 100644 lib/MoMu-STK-1.0.0/include/TwoPole.h create mode 100644 lib/MoMu-STK-1.0.0/include/TwoZero.h create mode 100644 lib/MoMu-STK-1.0.0/include/Vector3D.h create mode 100644 lib/MoMu-STK-1.0.0/include/VoicForm.h create mode 100644 lib/MoMu-STK-1.0.0/include/Voicer.h create mode 100644 lib/MoMu-STK-1.0.0/include/Whistle.h create mode 100644 lib/MoMu-STK-1.0.0/include/Wurley.h create mode 100644 lib/MoMu-STK-1.0.0/include/WvIn.h create mode 100644 lib/MoMu-STK-1.0.0/include/WvOut.h create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/ahh.raw create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/bassdrum.raw create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/britestk.raw create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/cowbell1.raw create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/crashcym.raw create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/dope.raw create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/eee.raw create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/fwavblnk.raw create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/halfwave.raw create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/hihatcym.raw create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/impuls10.raw create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/impuls20.raw create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/impuls40.raw create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/makefunc.c create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/makemidi.c create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/makewavs.c create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/mand1.raw create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/mand10.raw create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/mand11.raw create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/mand12.raw create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/mand2.raw create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/mand3.raw create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/mand4.raw create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/mand5.raw create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/mand6.raw create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/mand7.raw create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/mand8.raw create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/mand9.raw create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/mandpluk.raw create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/marmstk1.raw create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/ooo.raw create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/peksblnk.raw create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/ppksblnk.raw create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/ridecymb.raw create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/silence.raw create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/sine.c create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/sineblnk.raw create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/sinewave.raw create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/snardrum.raw create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/snglpeak.raw create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/tambourn.raw create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/tomhidrm.raw create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/tomlowdr.raw create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/tommiddr.raw create mode 100644 lib/MoMu-STK-1.0.0/rawwaves/twopeaks.raw create mode 100644 lib/MoMu-STK-1.0.0/src/ADSR.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/Asymp.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/BandedWG.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/BeeThree.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/BiQuad.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/Blit.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/BlitSaw.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/BlitSquare.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/BlowBotl.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/BlowHole.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/Bowed.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/Brass.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/Chorus.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/Clarinet.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/Delay.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/DelayA.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/DelayL.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/Drummer.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/Echo.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/Envelope.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/FM.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/FMVoices.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/FileLoop.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/FileRead.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/FileWrite.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/FileWvIn.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/FileWvOut.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/Fir.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/Flute.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/FormSwep.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/Granulate.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/HevyMetl.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/Iir.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/InetWvIn.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/InetWvOut.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/JCRev.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/LentPitShift.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/Mandolin.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/Mesh2D.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/Messager.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/MidiFileIn.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/Modal.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/ModalBar.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/Modulate.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/Moog.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/Mutex.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/NRev.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/Noise.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/OnePole.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/OneZero.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/PRCRev.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/PercFlut.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/Phonemes.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/PitShift.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/PluckTwo.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/Plucked.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/PoleZero.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/Resonate.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/Rhodey.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/Sampler.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/Saxofony.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/Shakers.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/Simple.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/SineWave.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/SingWave.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/Sitar.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/Skini.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/Socket.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/Sphere.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/StifKarp.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/Stk.mm create mode 100644 lib/MoMu-STK-1.0.0/src/StkUdpSocket.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/TapDelay.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/TcpClient.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/TcpServer.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/Thread.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/TubeBell.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/TwoPole.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/TwoZero.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/VoicForm.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/Voicer.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/Whistle.cpp create mode 100644 lib/MoMu-STK-1.0.0/src/Wurley.cpp create mode 100644 src/Voice.cpp create mode 100644 src/Voice.h create mode 100644 src/iosynthApp.h 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 0000000000000000000000000000000000000000..dda5f557f55beb212e4d1561e29ec0bef5577a1c GIT binary patch literal 184 zcmV;p07w7*m-&VAgX=x#J>~M~!}VDT103`#-8qaw2R$pwOYkS>qvBxVZs?-$L-wuwRR2%^&;kPm zy$HJw{Ta9*ups;%T^KM81^+PfL+uXjkn?E#TLy~|Bo>wzJrarxiU+m?1p$lz`U5=% mjRznE&H`Qlll}VpCHsK@5(Q8P`3RZ{O$ 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 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..6a7a1ff6831fc3d254809aea99e51acb83430cc7 GIT binary patch literal 20480 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 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..14da0748110b02d3f8acff38c37b3948cdc42d55 GIT binary patch literal 512 zcmZQzU~}i`7CJ8RLtauFB zGKY%hs+t;D6BV%?nD&Kk|Cnu_K!hvKaT4|7ju<)ocU`WSaDsxkCS ops|m=yNu&mn=rGT2EVoCRMq7rC4LAU=jmp1XBcq%8Adb!00;GMEdT%j literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..b34639b0be745e0779f14f7afd5a93398ba73310 GIT binary patch literal 512 zcmZQzU{+ys=gi{i=3gyzT=b#D4;gNGNhM`fbqzIbIXwY`-^TaMc3Sq>gxQNZo^`2m zm+{=}WAC>=&^UNj=$8nmsK%Jhan}-FCw)wLo^~!{X;w~-a_-6exPpg8A;nuunado? zvn!e_JF9A{V`?;O9@Tc%$<)oM=crGtUsiv;{%iezAifS{C)RV+&8d^A?W}oJqgfqO zRa4nn(OjNg=1|I9ytOE#;9-7T?#UeGtelLcY3EX&Cw)wK9d|8eb5vu5Q|OoAS%JoW z`+e*^H@nNYR5_lt7qbbo>@nMEe9z#wo`ANThMKCnlCr#{47bD&(T76E`B(FFb7rx* KGpjI+Z~y@L*J#TC literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..f61389ec8eb6b5e14b9b3967b03bee47c680d7bd GIT binary patch literal 4976 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 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..9d89aec1040720ac5d9cb26d74fce5cf04c7cbb6 GIT binary patch literal 512 zcmWNOJxC)_6ouc*7>O{kkQ9Phf2u5+N`}~p7@JiQM6{GeK|~CKg@Vl@SSVtlSS66y zSt>@>Mr6Q3(ghI_Z5Cpum>H9odH24*o&Lag&UgOko&7a7cQWGkEJpginziG9*_!w) z1-rD~aUI{bYq3(K6TK$$m%ZmkIw;6GeTt^re?{Z;L%EP|ZLxNC5Il%pU8d*Olr>3j zOq+OzWU$a;+`?h$nIpOyNzhGGR@3;xeIDbpa49M}K?v=pNz$dqWj{Kc@e5c-lnwn# zGUP8A)xH`K6HtX8Fpn$JR&QpBjFGI#sc-4v8RX$N7%?NcJ~g-Gr*U;r*&>H2ID|XA zl7p&ZQpPjB8B$f5!FzawB06G25xr*$gqVWfQ$%c_14Vemdzn#HGZf}MlTsBqh*xk2 zhnNyMW$U7GL&mK>m0Zk#3E6o(laBf}Ig%w~W=XwC8&_aH>{}HRYC!vBG~AKVud;y% z>->TH*NIBnzW|q zxh{*|;DH^m_SP2Ul}kUO@$io{eUkN{&`5jF{&JI{7wL?Z>{@)g&|;Vyt}hF&vSm~dGb7U+z*k=$55qH??q$rVx&dazBhGMRU0-O z7d<`jH_NWmzSga%q1Yx7U-DkY1YvkdK3y=XF?t z0+(>X)aU{_R9v?3(`M(%jv9qUDw;|2!Y3-H=J?R8*57DNB|

qiqiiGvTzlMn7n+ qhos$!I!)~U&FTU49JgUZRdv;NT8p&Ai_w_gt8{)0MKb*`b^H&@0XE41 literal 0 HcmV?d00001 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;i4U<*XzxtyK?6J+I&Ux_18)`^~w3xXyj9>%Kmp>-v0d0Q|+;t90|t zRWD2Z2E6Yduvb~vZfD>cuPi0TG{rJdOEb0U7}D)Uk4uKqdjGmq+j!Fj!*+7EENxuf zvOw%|4Q~!_N^2Nqb=u1G^Y-6re|m)V_n^00(3;!u%6hoj;)a8bcdWY_-mQJBHrl%Q_0(6Rn}Z!8&P6Ym)*fw~X8XqFYnyEU z8KO-YZ3@f-Ob1juXNs*DIn3had%VLHi*6{_5=>Q|S)#5r)>&`3 zWqD}Y#JgN2?j7W$P!Rxr$_7;^NA$;z+xE5&v-@k&TW`^KayuNtjiN-{pc9~}gN^xy zKWM+B%uz`N%C9(`m%(=Rsh*BpR=NTV(bT=iNjvKpbUfOWO zWy53bOG8_a3eVRb<=PbWjM2v<-q=U8Yf;JsDig~o9!iy7fO@ODST7La`WbhQbA`Rd zk>;Ktz?E;Wu{Ss`y9PU+JEC1)`exy&57HM1IS-k|Hk!$4e4A^a0cSul?8ax>YU5>( zRmLWxmsYHd^JzwuHX46%U=RMFJeuuwc zDEm-Pu~>hg7wSiJtMC^|;+j~dKh;m_6=JMtp%qlcV|Xdm(kYJM3ck*{5Qx*1wQ65A zLhU4Z>)KN7n3gX2C#c?PKXr+ksSZ;fDy8aY8mKSSP{kXENVGWU%sSWbez^%>`j#|t zTI>`FqNi@xAM0229eSo@SR?w0d1AXL6)u`c#XOd)pd0veJ)f2D+EWSbrE~O>!}v55 z;wB`lz(ni@MKFk+@D41J^X`L6jKD11iHk4_$KotZ#>v`AZ5A| zuZ&Q-pi}XdF-GyjBAL&^5-h_^w7_B50NIcPA3#?KfI#q+O04H`+>!1{q%~5d6pEu! z6hdJ%myXd>s;4S?!Ui768@W){PUJp3m_O%C-p3dCCO_m_c0&+Mg%pT~DA_p#!XOet zW%myy)?KKELWwvBHp-X}UqLG5z(ug(0GugVhoTvz?cpCd2P+^N2Ek}ZlkO{m^YUDj zF5CjiFad@@ko0s3=Wqgl$|HC@C-HZDh!1cU&*3N@$bC78J*Zml^cK~#g@dKGVH_@V ziM)>UWL*v)=1S@5NSF+BB}zKvNi7RtuT=UZ+?SjX9MA$n{)k|yT`<0lCiFyK?1U;j Og7P=#%?AFz4g3d5T&>dp literal 0 HcmV?d00001 diff --git a/lib/MoMu-STK-1.0.0/rawwaves/mand10.raw b/lib/MoMu-STK-1.0.0/rawwaves/mand10.raw new file mode 100644 index 0000000000000000000000000000000000000000..4b35376aeacdfc50cbef89ea76259403ac542b69 GIT binary patch literal 2048 zcmeHF`BRov6h8O9tA4nYpkfT8d@_h;peUoc1nLk$8n}R?;*ySNpbai#iA#!!1}bXm zFp7+rVkRy)WT-(z>P*r&G^hxfD2igEv3%S6-uJzy`%m@qeR<*-8@Dpx8UT7Vp)^wZ|a8MKt_fo^yp{irU{gL>rYL)91Rc6kgP%^k)C zGt`*mE%TmnZ|hpr-Q>yleD9jmS=I5PE6IJ&9pEyoNmM59*y+{{s8)*fMAct@OPlD3 zaCAEKp01v44%zQ^pAo$q93!-!)I#;KR-iKJ8ie3VI3i7uyCi}atN`1 z1Q?8MGuzDmzD}><`ObaXRprX^NWNCKkY$@qb}teq=PQ*;rt(1jTB(s6XdPUF0 ztRyHWmGjDOHCQXrB9-GxfaIe0>F?4rxkOqHQ|%5r-tt-%qRu^5YJG0)WOZhZQD-bP zf_;_|0M()u~s|V&cGD1n3l;%IG@Fbf-$CDS-%Q^KZ@ag_+v2VD2701B zC0@gHSkvvtSVS`DCp4B`mCniMl^iuxEmk^}Xf;f0*RScD^elac9<3c!)0HTBhvbs> zORFR&O(zo|3a{Zj9%B8#?yyvr!E)IZ##j@pXKpJ{_;Az3X0iFEX+C7l_Brf>9dL=n zkWHkNj-n4}H!YwG=oP6iMOrQ<2%+ILltzLYcH{H*cMObRX7eSAP_c!kK~ee8buT7Y?@4y=yrOVmeGAQQ=B5HA9+ol zkUOM?ToidJq&M7!n{Wj(@ii{xjJNQoyn)}~ukc-*kLehLL(m@`+~m*r-@KmRMGdE8 z5xx?=Cc|nd7yV?YgF{dNr=SM@5cTfDW!Md$!cc6+ay*JT0+ETR^G06A5AtLDrohqU zh&np3FAhK_j=@-*himbG$gjoc5Co~P70$wQ5=17DSTd7*MmCVI$Zk?XD#&q?MP`#E zl1{dhy<`vBO45iETHpj^!28e(pWqo>ff3y1&0>>Uep?`UlrQGvxRZzS(R>n56sOJn zqYFd0u$Ne0OzbID{fj0_+;xS$a##J1~UE=+|8 z2!{U916_jcdi+f={w?mu!*~pfu~ewC5nZ5(n&A)$qlArx@h}mlz(+6xk|6=6i5edW z9H+p?;wE1BI7ops5sw0Yw6Fz##)D#)M8QK0j>j+@C@fUW8-c@we-Ec&8m<<4+lV^_ z(pT}3=r>aQUjdt7k3i%)Gz*6O$RH9zoC3{$#6c85@IouxhDs=dlW-XFAqO_VQkW?w zih@A&U;|#py_kt9n2bsIp-^?0;3*uV1e5VNN3gY6s3Q~C;TGJ5`69Ov%Y^Fd@dfl0 s+a?GG)5H`T1dm%_t%#PwN?0S}Z{Psz6FvhLh>Tf~^v2#G@P8ukAJ5hp%>V!Z literal 0 HcmV?d00001 diff --git a/lib/MoMu-STK-1.0.0/rawwaves/mand11.raw b/lib/MoMu-STK-1.0.0/rawwaves/mand11.raw new file mode 100644 index 0000000000000000000000000000000000000000..94889be6f0d6dfeaa63449e06a39df1356508dac GIT binary patch literal 2048 zcmeH``EyTa6vm(P-ft2imKrLUPLYXff1tHjky?sQgrI62YY|(SAf(oIbc$+4Ofb|^ zBGQsB7!{&w9W6nW+DRp?C2do!toQrAPfz>}{n0#g-@D8`=RWV}ITv88{mZrr&h+b7 z`mU3=BT$Yw2NMXr6H;oD%z%*akn3hMZhEakhlSjfbUQIP(&b^iOZP|lbNI--&D6?6 zWfRIb`v1B@oU?N)QC_XAU&TWIt{d&T*noe}o-uvAp%TXrINvl35+?Z7bkR>HmZq16Lfxa}&~2tLx>tl+%hKI>eJjrV6&3@KY) zp6CR~z;lee$|w@|=Tx5g#27B{+V8|M4gv*os%KdCZ0*v^$Q$NlWm@T(W= zEioB#N+OYqBe*G_m@@CWcf-3EXdf6BXzk54ZKXDrVH3_ueaVy*Sljl5FN_g0&74_>mDWU`G&vFT+B%w9PlJ!O??XL?Fs^ko4vIEVe&lH%68Np7b* zuiEYE*c6-R2D^Q(#1**9F2lvUsV>#!y0b2uk=%n$B$sh2i?IhKIEsmA%ODT)LvBNT zBw-$+c$F7nSjKe5v4`$(GbgjFer+~~>$(<#mdxi4UO+3vBLXe37C{*-{iUCbl&;4>vx~Ha_L{wD zkJ`ibq&;gNIB_-YW1DBsxezzUopSjMa2aX}Ew{W>u z#&e_+T*+-br0-v55uQOi-9djO;A3pZ0i6MnX3}0>f1()W6))W-TEfMX0E%!3tFREs z%5EH9LnJGBhv%5h?b>w)W7*VIxEt=G=3eN0He@??VH-AMV@9(B`*IW$bXO~McB&j) zXNe}>9M7Syo}vTou%LF6BRb45;6lst8n9MWBJQ?tm`JDHd^0 P99Ox1s;310cLM(bY{@Uw literal 0 HcmV?d00001 diff --git a/lib/MoMu-STK-1.0.0/rawwaves/mand12.raw b/lib/MoMu-STK-1.0.0/rawwaves/mand12.raw new file mode 100644 index 0000000000000000000000000000000000000000..a128642bf6de4fdac74a1fa03bf32bc6003bb685 GIT binary patch literal 2048 zcmeH``BPR^7{|ZQ``*hwfI=>$Ah<atq$A=ExTNBe8y2P`3QlM>BW-H# zD`{%DP`RW|7AlG(I)UOOxgd(5rYyeid+#|<&-6F+qx1dYo^#K==lMRL^F08n?Gvv1 z9%tj;`a&zm$2;(=z-s?<&Jy-;r7nWuw2W*oZ|^9t0_RXWR~74Hjt|TTdRgcJ{JZ0|9R+=?ey+*?* zLC>~B+{fJc?%u9KPl~<8?%_&*neOgkC0O@7yFFo6KP%Dp;VU#vKd^GF?s|iBy!T4q zOa62G-ZFx?t^S>UFiMS`G@S1`CL529SnN>StuIufexxt*UbMis80|Y$EP*HlLpuXd?2wbpi6 zBkeprm}g)Db|L|tv6C7cb&mOtAZM5nYs5QGJGU80W{P>;JZgSt&N1#eD;!&BG4^0G z>gXcfq_xxr1-xIC+l%e)_I=f;r-~kME4@~S>r8!8N2@(5&d##RtQyrxSMY6Kq0ey~ zR-qPMIUm6kO!2sf8@Nv)xQ!S-&82(?2F4->tJuZqynxs7e!j&w`2cT|@p$gRgV=?K zG>t~$3I4$MSdD@5t&5*Z&G5HWTzDovO2SF%x&@6yA>z zER_09BAY^G&(XAlDyfvx$zQ515=Kq*Gv$h#4Dy$*+i?>s^u|1?nVG4$z8M_gNQCNWKvR5el_$B|wnLL3< zaW8J6EnTIH^*+5tAJCQDio1#10P!5m?Rg-l@p`_%FQocdakNVqoI)8a3Y0Ex;3}@8 z5-w^-skD){(#Jw>BF&^UN}y0w;V`nL?hK3*-)UHZZ?Fc5Z1YK8!&A8rhiKLfTC+c! z`nj&qMf$9GxvB5U_^dvm%e9AFipwOt1hAerBiwcW@Q>T@s>ebH6^ z?IN87Nd00y%-e#Fdvy%CW*=vEtg6w<+(((5Hm4JGBXqdg~gk~qJt#h4Pn_{Mv;=IPy~wt Nh1x5M-Jr8-F<{I8I-o3?rz|+Pvsm0Gd+jB?t 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 Pta~8a3%pR^e^cN;QOOs4 literal 0 HcmV?d00001 diff --git a/lib/MoMu-STK-1.0.0/rawwaves/mand5.raw b/lib/MoMu-STK-1.0.0/rawwaves/mand5.raw new file mode 100644 index 0000000000000000000000000000000000000000..9b308a860b4966a4bfa6148f01bdfa70fdc99495 GIT binary patch literal 2048 zcmeH``Bzm{6vy{I_ulv5f%s4asiXP`OQ&HN9)y>(#z(WkOzxv6K%7#F#GwIY{zs6mEKVe z>I-(m=;J-ZHznY?B`7f8T;ByP2ZP@W85=yWd%ITJ9&=W<~_^&&^MsNBClUNBzYZC zx~Pxr)$Sr9QKT*6o%jK_r7hXk%eh~@?!4RfXWIkUPHxmH)fHN>7*BC97!z?gJ1%cA zY&E7S9hEg6#iny!Zm+jI5)9$WXyt;ECm)k@DmXH3VYZ?tfPUd(O%q| zYm0Xdb+@=avpelMj%AL}wxn0i=6Y*>YoE55_7jfl?r7Cl9iuj@bG1&CrwsQ5k5Ww9SN=`EnM5Go>9}aHu1CIB1goKCv=CkFdjNW z8M~)+HTWtgp@gF#o@yW#cQ7B=F7&++ipUpXJenV&M6f|E zM1mh37fx}S{>B1!oP~lD=D~UlWA93{q+02;++Qg)WGd&SMyaPHM7^ud(uVO#JW7+?SKKGnB(+X`tTAn_mZbTsC)8psLc7N& z3KRw6mRKRuX$gFb+t?6xN*X4GvnQ-kx+>Qw8ohDYKiW1#)obVH7v5NZAS#r}ON}U08*j&0)t_IjdpStVuFU5mKZyL^81gHX6%t9~RG9QxBO zohpPpb%xEt!f*3Kd>=o`Pw|6%6`#)I_%i+x@1eD6cJ8C+2h=;uhBzxKMYAC4NP*Oi2G9grK+9mLLUBmsiG$*Xa8Pd=M{{TmWzl}xOU2Xx78nN$V5d&= z0Lr0M->g!ofNI@OEm*;c2JDO$^hZzqHX5M}3LzI#V5xp5Nw5j_!(RR6b-gz5KN$EA DK%KG2 literal 0 HcmV?d00001 diff --git a/lib/MoMu-STK-1.0.0/rawwaves/mand6.raw b/lib/MoMu-STK-1.0.0/rawwaves/mand6.raw new file mode 100644 index 0000000000000000000000000000000000000000..05f083d8912b7622d17e058ced75e9c06d65f25d GIT binary patch literal 2048 zcmeHG`%_g_82!F|&OLB17mO>$wa{qtL8j&tA3YFi%v2P`C+ZNHWh(eWv!c;LkwnLV zP|-3;F>8!;G##HMY7fh_2P%wd778e+TsW6|&pmtZul+~#qqAoJvS;>Q>sxDm0I(tW z?%f~j`M-neUTPZRG#i^uFI}&&J$9#qHFaaksCxEU#aFJ?47C?PcbGfDstnQrZw*cdMb!cb4Z_ zFZxQ_t{BgF@;dB@A=ZHgV}DfGU>>SUf=!Q-=A719( z#RiGRatF-kZS9Bd*WA0=KA0bca?OxcZLc)0t6y_>vTwxwtb3DvlLD_=qg#hI^=b}l zIpV+JZ}DyQ75j68cPyuU(48KRFV7p z@a-&#mcYj>7J69Krq|bO9toyeaaMj10+)l|23|6=S}WUoTIqI}=mRfky;!DtiW`w`)x)rg+IojCe*yz};Wzi}A zuC+Ii?XNT2%qo9E`&)r6?Y3W->)U#?o@(W7d(4IAY;&Z)EU+)6+lkx|{iq}S2q$r> zHq)`hm}L}(EpWPBc@g{F+afcgDmxsHYIPU8E=Bwtnc@D_wLE-h*g<2sHXp{yw?&S< z)zSiATFLfA`;*nWroK zHeM^7yox_zPYe}>%Iq)1bTS|u_FxP?iL0;zccaM$uzanvc2w`Hr|W5Yv*9&P8)FCv=7yp(9L#3aEz5@F#k3HQH4d_58X*^n3h_9vQTb%@QG6!P;~()8yj{eL-oh(7 zi&0{esF!`@GFe3qdX`oy_8hp6$(WAMVLW!mZkULfSdOsks%{4e3yTETy z02weD-h@?93ZK9_m<9bImO}Ikt*2Qug%;3z>d$plLdCS27E=zrO@*{Y&ACb8W7?%u zo}{1YGTop%WPuyHLlTUGm*Hs$r#d=Id)3AhYjK@A`O3`?a4Am3q4*fO;2!(|-#{_s z!fcoT10e=bsc)p8sDkn+Rc%O({7R*ir#R;-<}{UEmRu|gWraK@f0h48zw#}Xdee)P zN%?e;>Y)P+fHat=JSkF2N}(L~!7;Vd)o=yQ!wJ=~L+~~1P;TYIRCpfxDI_ZH9uN&q S#cxrAO7P4BJaFLuao|5Krp?L# literal 0 HcmV?d00001 diff --git a/lib/MoMu-STK-1.0.0/rawwaves/mand7.raw b/lib/MoMu-STK-1.0.0/rawwaves/mand7.raw new file mode 100644 index 0000000000000000000000000000000000000000..64941e9f98421aa1b2b353abbfa5a25cd9942295 GIT binary patch literal 2048 zcmeH``E!m}6vxlG&-+>;jiiJS6U3S-(ay9|RHLnF2vW4QG}hQ=q)|$0i#=#8iO|Fn zV(FwxFoM=rOJf@ojZqB}OU)Evm@u?S-uJoZ+w(v4S99jvXSvV4_j^9y^AO>Y?6DDU zg>`F5c#bSL@> zd`o?mz6#%JUk5irqTE_vbj_{WyY2$9SS#)9I}&VfN(e^sY0m)fQg2shzZ37ttkcxH z-8-x9?)vfdCe?eh&JpLH)6m>BPt0A-i=2wh2$H>0BvsPc7P~LpZvJSW_3!pi@ZI-^ zxu4oJyV@P@Hgm7p`fi-R%En5u%(G+dN!dy9CeFF)`NI=nGEJa~<#am3lbn{G8qY%~ znKSVcE#)@G;C&e@lO^1iN*7yd6Kr>RK*Mka5i&d=5T(S6DbP`5@V;jcicw)9=;l1x#kVu zO26?Ra#P%eZnk~hCfZ8z*yqw*#>qW|V?D*Nm%rp-`in|OaNAV}zkn$-K>*aAKB00Y9E17rpSB_|O0yFaifqf*lwvw`8d- zl47vDl%29nE+P)ch^Y&GPPz1$J8~2o0{7%Ke3;j968GcDe1fY@ePg&<jT6o6k*sPQ9~V;p*;u2e{#d@RORY1Y^>yWeKn44Y#wNu*4dgF0U>mt~ja z%Vp)a7&oXH^`%iXfu>P9?V&pyzzyhMxBq%0rdE^gxq)uC`| z1s~2~502m(E-0^Mn2Q-0jsA$m2k3`kn23>h4mv9h>7J7P;R<=UxT#G#H*MFdz8tFb^6r>e-DS#SN z6ve8l>8fj`p0-YX&Q*0=C{M>+^)5r{Eu;mSX_QPus26qC9U4&+YO8(m21QZ}^`?ow z3Ds)^wb2MurB9VzCH_VQO7RUOq{={hr;zE$5R z&cRmQ-D)7+N71r5h#D zMp8);npoPXE`({Qs=c;hR2ze7g_6lV=RAGoZ|INiJLjJ7J@?%AJkRHS&joma!ETg2 zXj5HpUc@bl^(a))s?dw@s`U)**IKPbu`1Hlbv~=pMW6RFR0zvls<~m3O@TROd)QUB zSsL+FZ-7GuK9}fQT^cc zleW6Q7pfA~I2DUduFAEurFNVRHRa}rv9_)qWK-;TyWO6%o9$fp1P7uSlF$_kR8Lju z#i@I0pW3CqQCF4ox_Z+*zc<87kdt1O+=<=*m8JTq(L$gA#rRXjsUBFuGPZUlu8~c% zkC?3{-Hb9DY^beocA4P7AEuv4GpS~zDX@|DJzMI+T`n7Q0?UvBs)=f~y6L5OrQQy2 zp0~oQ(o^&by;|q%lfF~+?vdisu z7vcuFSU1$=xyy{@3Z6q_bihE OuR0QK$HzhzV#4`G?c4&m8r5-j>=b?)OO*w zUtN*D@YH>EQ+=-%sdU*9g3BmECWfOu?{T-}eVOC=BBNY|Tkc+SX>OXE>_)pd7wr;V zf{SrUZmKJCm*m7)rt+0qZ69zis}PFTh{r@MlURx@%!ePd@Q%!@kc(~j8I>wXHC9bj zePIlxRf?ea0-`j1!qx?9oUGK;&80=YHxJJW1_uU za-HRV7V;A=<2<1=jB$)%Pj+G}>9FQ(!${GS#4&uGe({#i67J(sR!YSip$#I@Numon zOU5X)MLU_}B!4&Qng~S8dbG@uayxpWNA0IB=!3yR;%VvK6nRe;J^hi0r_f6{b(4;2 zfhIz>6|0LU&*DyatRlSkC}Xf8A2|d zljJFr3&h>W!n%k%#qCL6<6R-xTq>A^QJ5foJyR+_2XD(f9W!LSDZ`HicvsdkWXEU> zmAds32T|gut>_5_gx_7>mKtA`9ylSlYCrdgny-Xsk&I1p;zo%a>56sCl^)q9-|mqr z9u?geqvA*aNS^`oREM`{dQ`sVDzBt?{Jj=`8FX L#zO-C1A+elz2fQ< literal 0 HcmV?d00001 diff --git a/lib/MoMu-STK-1.0.0/rawwaves/mand9.raw b/lib/MoMu-STK-1.0.0/rawwaves/mand9.raw new file mode 100644 index 0000000000000000000000000000000000000000..9e88a0c91317db8a3f2ba7969fe7aa0e0b2e029f GIT binary patch literal 2048 zcmeHF`%_g_7+w3EdoSSSDJY5g7{y0HC|V?z!eA;E8kJ+FH7a6^`AU0eXg*4-8D}(8 z(@e(@b(#t%9YIQL98yC=bbR0ogz$l>sDoFz+;h%eeeyr_oA;YN_w4=cy}oa)^#SPX z>}tIgNYzUi??2*8YprmHc`tiQLVO``?M9;UdQd}fi6_&hss7?O_)<5xT+{Xq;AS(MQd9Pxt)bicmdO zym>HaLeOS+llxN-f@8g%y)7X%K~)~Fdy8wQ*~5%9maDJT5Vct4bE$LD4p@T%hXXZM zcp%;XdCLlaxm~1BJ2mzy`=;*hT(b{Y8CIOL7F|>{k~l+ecPgB5R;ks=KEj{P1lJ`q zTaChTb=bIITsJ4W4|p!PGt61WEwjOO*fqpVGWWVRnN`?pSGR6xIqKgWsI*7e@z#6x z82y~C*DpI4^+s$kGL0-%t_I>7erGd3!ycp5+-8)jT&%@AC|2WDmC@cE(J0 zUF@un>2hY{MU|n>sT-#G3dMZh zW)T;$tDfS_w2SOsw%2~&u5(5^cl8PSuoK@R2Lmt`g(_6#r~xSBMMmhO`UVrI^lfJG z3?HzB3A#wvGY4T4Wxt`^S!xHSr z-zda9yhNM(IhF0TPdgkYH@@dq)?+xn!4A2Rj|}vLqQ)TXQr*>5HC837B=w4#tNP)8yi@Nu(=*Lh$1 zYe({5>G3QtOD-JU(F=XhA48EYIw#6khIlnuRw6CIt6&}dXeSCkk8zkTnKW@g^S+>5 z=UvJ4#(329wy0U6{y`%oPt;a24Y!ug&k7%X^E@;Xj<^lXb>;@2Zay``59XfOFliSV|%rs(zf L_gI1dL4p4OW?%Wt literal 0 HcmV?d00001 diff --git a/lib/MoMu-STK-1.0.0/rawwaves/mandpluk.raw b/lib/MoMu-STK-1.0.0/rawwaves/mandpluk.raw new file mode 100644 index 0000000000000000000000000000000000000000..162a0da9e1d448ee915c7b4ba441c8da46b6298a GIT binary patch literal 8900 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 PsADLOD`3`rMg6CLjECH- literal 0 HcmV?d00001 diff --git a/lib/MoMu-STK-1.0.0/rawwaves/ooo.raw b/lib/MoMu-STK-1.0.0/rawwaves/ooo.raw new file mode 100644 index 0000000000000000000000000000000000000000..1b8331e3d9a9ce5522961877759e898b3dc23fdb GIT binary patch literal 184 zcmV;p07w7-VFBF#F8pNu8~wBVo%_uDJNmWz%Kbb1Tlxt3FZ%!dTlx3))%R5P)9vWt zN!?52qv}HCJmo?9s}e*K3kz}?-7GgJO&IAHJstNU0T|y4{S3_)aS`VHi}Murm+pGo zqtVpSZ_{zrqt%7jF5<`SL+~E)f%aJO mEe0C@h4^&&ukdvB zXAXG~bv@x}I$N%JadGAL`hS(%i;Hv3)7cW9MqLki;Lq&o>b%0v(BhHte!bILT&lH- z8nV2S2BMRMO!;MbJUREVSF<)TUu7y~Ok$V|w434o&Hu^&=Kbydqy4MyN9#AI&)Yvd zetY^=-m?pjKHs}>tNH4;i>7BBkINlAzb9hb?hSueD=gKVFFoVeq?0|pZJrHGZJs^7 zlTOa~HD7wE=4yovf4A-46LIkTak(>&7fr8zyVZQ}#-q>AF1*Tnd-}uU&)dH_{b>DF T_ecA0_rH1nlmFjj7~uc_6d!%U literal 0 HcmV?d00001 diff --git a/lib/MoMu-STK-1.0.0/rawwaves/ppksblnk.raw b/lib/MoMu-STK-1.0.0/rawwaves/ppksblnk.raw new file mode 100644 index 0000000000000000000000000000000000000000..95a44464af8f4edbe304e7ed4a7fc70fd6d4b8d3 GIT binary patch literal 512 zcmZQzU{Gh6%b3Je%6yfziM^V0ACD)$tdObbBuN8VUPTSnS}iWU)5iNP9@!Z>ukdvB zXAXG~bv@x}I$N%JadGAL`hS(%i;Hv3)7cW9MqLki;Lq&o>b%0v(BhHte!bILT&lH- p8nV2S2BMRMO!;MbJUREVSF<)TUu7y~Ok$V|w0q#~2RdQo0sv6FP*(r| literal 0 HcmV?d00001 diff --git a/lib/MoMu-STK-1.0.0/rawwaves/ridecymb.raw b/lib/MoMu-STK-1.0.0/rawwaves/ridecymb.raw new file mode 100644 index 0000000000000000000000000000000000000000..722fa5a1477517a733d858d9a2d610051a22358f GIT binary patch literal 32394 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άsPNm-(DyaSbE?~RdQf2xOG(>;fG_8(zQWpz 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 literal 0 HcmV?d00001 diff --git a/lib/MoMu-STK-1.0.0/rawwaves/silence.raw b/lib/MoMu-STK-1.0.0/rawwaves/silence.raw new file mode 100644 index 0000000000000000000000000000000000000000..4b8a1b3e49c7b867bb4cb3d412403b88b765c9de GIT binary patch literal 448 NcmZQz7zIN)1ONfR00961 literal 0 HcmV?d00001 diff --git a/lib/MoMu-STK-1.0.0/rawwaves/sine.c b/lib/MoMu-STK-1.0.0/rawwaves/sine.c new file mode 100644 index 0000000..d10c103 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/rawwaves/sine.c @@ -0,0 +1,22 @@ +// Utility to make a rawwave sine table (assumes big-endian machine). + +#include +#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; iFB zGKY%hs+t;D6BV%?nD&Kk|Cnu_K!hvKaT4|7ju<)ocU`WSaDsxkCS zps|m=yNu&mn=rGT2EVoCRMq7rC4LAU=jmp1XJGib^K;Yme#N0S$B5x!5vTb86RGC()~Q^l}ER3K6w6| PCfhm3QL%Zqyz_bpy6-YGsc zzB7I`K`22t0h5rH(3}8x znt)~@2J`{?4DCZ~=m`1_oq%%$?)%{F1E|e{oQ%cEhMWz`-txE3yr6;g9G5jCjLa!tKJ?fSY0H3Sg)ZG7#b(d;qv=1kr*pfh@pU zF`z5J+<(zO(C-NRgQRbruO_w^YvMEM-{_x9cm$5uxfhcx>y_8xXLJ1yHXTh6<_cP8(k zY)Y&Ttle(+-q;CC0 zlzb_{l0f|!bgn^sMO^9!`?J|%V`3bldLrS%O+srzQi8T;G6aVC5BarD`}0*H<`E*i zraXA=POeW}N~c^n^Eqf7949*8gOBTumX6LInja9^-K=ev$~TX%#ru={JYNj8BB)K-G$3SsYc&T~t_vEbJ^aE1(yI7x3j%@^$j2^8)gCbE|U= zbCz@PIda(p*x|Vc0aW=6bF(%PGQI@z%d`+Yfqlq>| zbs~bWP8cFo6Nm(Ff+^u5K@?`e444MD!xT6Z#=-uuGi(W?VHB(e%fk||C@cUYU~c#n z%n1%RxC?+c2~bl5J!sJD3}$d(mI5?rK#N5X1-hm{p9uC05!Q(au-69crvM+jiL$^` z4DdFabQ<^!0e%;g#enxDkl~1=2l8~0SSk7--(V^NWGzZvPE!Th2hs%rhvxL-3~RvU zYo-NYbdYs7t2rA1xDDjU0fx)DhPl;wynyR;zD_=+fDf>y7n&7z79ooYi@Cu+FiTuY zrb=&?z94In8_N{SDj!KcDk>K%&#e%y$f*>m%%_M`$d6?o*Hm4oYOB_-91?wvsE;aN$v3augG`jIjV^xz*(`2(x^U1T)7Oj?v-~3v6TWi{k+8DpXRC(%P zyH^Kq$J0)$&fTt(=LXN$yEA*Vd+0Any&AoXFH`zZeT@FBfvW?XgXAHzA@*?NE7uXB zk-^c(G1al9*LgHk+VLOMKmErQ#up|ECM~CUruwIGZ?xZR|JD4~cLq7L`i}D6ZB}Y_ zVU9fSv>>@Kzerwkrc2Z5%ap${3?&A0rExWAO>=F3y=Mdek1>;vIq{+3U#CsE&5e&u z|Al|j+v3<7`<%UPzaz7=vHNT<>WjfX&;I1s;%^=-71lPp`+#_8esuO|>A3ED@QKd< DB?bC1 literal 0 HcmV?d00001 diff --git a/lib/MoMu-STK-1.0.0/rawwaves/snardrum.raw b/lib/MoMu-STK-1.0.0/rawwaves/snardrum.raw new file mode 100644 index 0000000000000000000000000000000000000000..93005ad04e1adee215a3a7cbcdd949311f2513bf GIT binary patch literal 16660 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 L0_bl}h7k?`T})ND literal 0 HcmV?d00001 diff --git a/lib/MoMu-STK-1.0.0/rawwaves/tambourn.raw b/lib/MoMu-STK-1.0.0/rawwaves/tambourn.raw new file mode 100644 index 0000000000000000000000000000000000000000..fa8125220f692abc78cd1554ab2fc4899219b646 GIT binary patch literal 9240 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 literal 0 HcmV?d00001 diff --git a/lib/MoMu-STK-1.0.0/rawwaves/tomhidrm.raw b/lib/MoMu-STK-1.0.0/rawwaves/tomhidrm.raw new file mode 100644 index 0000000000000000000000000000000000000000..0cf482b93778deb85fe70762346d3c4133a6a0e7 GIT binary patch literal 27642 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 B9JBxc literal 0 HcmV?d00001 diff --git a/lib/MoMu-STK-1.0.0/rawwaves/tomlowdr.raw b/lib/MoMu-STK-1.0.0/rawwaves/tomlowdr.raw new file mode 100644 index 0000000000000000000000000000000000000000..9813513dd9c05dc3b2aad5eef14ad08cc5e839c9 GIT binary patch literal 39200 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 N^G5$K9{%6E{XcWfP;dYM literal 0 HcmV?d00001 diff --git a/lib/MoMu-STK-1.0.0/rawwaves/tommiddr.raw b/lib/MoMu-STK-1.0.0/rawwaves/tommiddr.raw new file mode 100644 index 0000000000000000000000000000000000000000..4d042575a03819ac4ee527ee89b2d50f9f63c464 GIT binary patch literal 28292 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 literal 0 HcmV?d00001 diff --git a/lib/MoMu-STK-1.0.0/rawwaves/twopeaks.raw b/lib/MoMu-STK-1.0.0/rawwaves/twopeaks.raw new file mode 100644 index 0000000000000000000000000000000000000000..d383a24bda8d6364f31a4d99f0eba84db414bd05 GIT binary patch literal 512 zcmV+b0{{I0000R9CjeLgodEU$Vgcd;bpsp&)dZpif(CU5dkB*Wz6$#cNe!wG9T1=r zH51zvk{4MSFdG*g4IdLBC?iWHeJ8vs3M^zU%P~JQzcx!a;yZ*sF+k`;s77*0MNA-1 z15xf&;8)mM*InCS zCjbcm0RQ*@+5f2jWB&^Np8g*Fi~QvLEBjvhe))^|h4*dtLiGjnxAIo-jdX&%YSFSh=*x>Er^W^E~ z(CDY?ZtNxP%kNh53v6e*0ehEBxgBi~b(|p8pE}WB;iC+5h(j C?EQiO literal 0 HcmV?d00001 diff --git a/lib/MoMu-STK-1.0.0/src/ADSR.cpp b/lib/MoMu-STK-1.0.0/src/ADSR.cpp new file mode 100644 index 0000000..958ab13 --- /dev/null +++ b/lib/MoMu-STK-1.0.0/src/ADSR.cpp @@ -0,0 +1,155 @@ +/***************************************************/ +/*! \class ADSR + \brief STK ADSR envelope class. + + This class implements a traditional ADSR (Attack, Decay, Sustain, + Release) envelope. It responds to simple keyOn and keyOff + messages, keeping track of its state. The \e state = ADSR::DONE + after the envelope value reaches 0.0 in the ADSR::RELEASE state. + + by Perry R. Cook and Gary P. Scavone, 1995 - 2010. +*/ +/***************************************************/ + +#include "ADSR.h" + +namespace stk { + +ADSR :: ADSR( void ) +{ + target_ = 0.0; + value_ = 0.0; + attackRate_ = 0.001; + decayRate_ = 0.001; + releaseRate_ = 0.005; + sustainLevel_ = 0.5; + state_ = ATTACK; + Stk::addSampleRateAlert( this ); +} + +ADSR :: ~ADSR( void ) +{ +} + +void ADSR :: sampleRateChanged( StkFloat newRate, StkFloat oldRate ) +{ + if ( !ignoreSampleRateChange_ ) { + attackRate_ = oldRate * attackRate_ / newRate; + decayRate_ = oldRate * decayRate_ / newRate; + releaseRate_ = oldRate * releaseRate_ / newRate; + } +} + +void ADSR :: keyOn() +{ + target_ = 1.0; + state_ = ATTACK; +} + +void ADSR :: keyOff() +{ + target_ = 0.0; + state_ = RELEASE; +} + +void ADSR :: setAttackRate( StkFloat rate ) +{ + if ( rate < 0.0 ) { + errorString_ << "ADSR::setAttackRate: negative rates not allowed ... correcting!"; + handleError( StkError::WARNING ); + attackRate_ = -rate; + } + else attackRate_ = rate; +} + +void ADSR :: setDecayRate( StkFloat rate ) +{ + if ( rate < 0.0 ) { + errorString_ << "ADSR::setDecayRate: negative rates not allowed ... correcting!"; + handleError( StkError::WARNING ); + decayRate_ = -rate; + } + else decayRate_ = rate; +} + +void ADSR :: setSustainLevel( StkFloat level ) +{ + if ( level < 0.0 ) { + errorString_ << "ADSR::setSustainLevel: level out of range ... correcting!"; + handleError( StkError::WARNING ); + sustainLevel_ = 0.0; + } + else sustainLevel_ = level; +} + +void ADSR :: setReleaseRate( StkFloat rate ) +{ + if ( rate < 0.0 ) { + errorString_ << "ADSR::setReleaseRate: negative rates not allowed ... correcting!"; + handleError( StkError::WARNING ); + releaseRate_ = -rate; + } + else releaseRate_ = rate; +} + +void ADSR :: setAttackTime( StkFloat time ) +{ + if ( time < 0.0 ) { + errorString_ << "ADSR::setAttackTime: negative times not allowed ... correcting!"; + handleError( StkError::WARNING ); + attackRate_ = 1.0 / ( -time * Stk::sampleRate() ); + } + else attackRate_ = 1.0 / ( time * Stk::sampleRate() ); +} + +void ADSR :: setDecayTime( StkFloat time ) +{ + if ( time < 0.0 ) { + errorString_ << "ADSR::setDecayTime: negative times not allowed ... correcting!"; + handleError( StkError::WARNING ); + decayRate_ = 1.0 / ( -time * Stk::sampleRate() ); + } + else decayRate_ = 1.0 / ( time * Stk::sampleRate() ); +} + +void ADSR :: setReleaseTime( StkFloat time ) +{ + if ( time < 0.0 ) { + errorString_ << "ADSR::setReleaseTime: negative times not allowed ... correcting!"; + handleError( StkError::WARNING ); + releaseRate_ = sustainLevel_ / ( -time * Stk::sampleRate() ); + } + else releaseRate_ = sustainLevel_ / ( time * Stk::sampleRate() ); +} + +void ADSR :: setAllTimes( StkFloat aTime, StkFloat dTime, StkFloat sLevel, StkFloat rTime ) +{ + this->setAttackTime( aTime ); + this->setDecayTime( dTime ); + this->setSustainLevel( sLevel ); + this->setReleaseTime( rTime ); +} + +void ADSR :: setTarget( StkFloat target ) +{ + target_ = target; + if ( value_ < target_ ) { + state_ = ATTACK; + this->setSustainLevel( target_ ); + } + if ( value_ > target_ ) { + this->setSustainLevel( target_ ); + state_ = DECAY; + } +} + +void ADSR :: setValue( StkFloat value ) +{ + state_ = SUSTAIN; + target_ = value; + value_ = value; + this->setSustainLevel( value ); + lastFrame_[0] = value; +} + +} // stk namespace 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; }; -- 2.34.1