SynthNote.cpp (7097B)
1 /* 2 ZynAddSubFX - a software synthesizer 3 4 SynthNote.cpp - Abstract Synthesizer Note Instance 5 Copyright (C) 2016 Mark McCurry 6 7 This program is free software; you can redistribute it and/or 8 modify it under the terms of the GNU General Public License 9 as published by the Free Software Foundation; either version 2 10 of the License, or (at your option) any later version. 11 */ 12 #include "SynthNote.h" 13 #include "../Params/Controller.h" 14 #include "../Misc/Util.h" 15 #include "../globals.h" 16 #include <cstring> 17 #include <new> 18 #include <iostream> 19 20 namespace zyn { 21 22 SynthNote::SynthNote(const SynthParams &pars) 23 :memory(pars.memory), 24 legato(pars.synth, pars.velocity, pars.portamento, 25 pars.note_log2_freq, pars.quiet, pars.seed), ctl(pars.ctl), synth(pars.synth), time(pars.time) 26 {} 27 28 SynthNote::Legato::Legato(const SYNTH_T &synth_, float vel, 29 Portamento *portamento, 30 float note_log2_freq, bool quiet, prng_t seed) 31 :synth(synth_) 32 { 33 // Initialise some legato-specific vars 34 msg = LM_Norm; 35 fade.length = (int)(synth.samplerate_f * 0.005f); // 0.005f seems ok. 36 if(fade.length < 1) 37 fade.length = 1; // (if something's fishy) 38 fade.step = (1.0f / fade.length); 39 decounter = -10; 40 param.vel = vel; 41 param.portamento = portamento; 42 param.note_log2_freq = note_log2_freq; 43 param.seed = seed; 44 lastfreq_log2 = note_log2_freq; 45 silent = quiet; 46 } 47 48 int SynthNote::Legato::update(const LegatoParams &pars) 49 { 50 if(pars.externcall) 51 msg = LM_Norm; 52 if(msg != LM_CatchUp) { 53 lastfreq_log2 = param.note_log2_freq; 54 param.vel = pars.velocity; 55 param.portamento = pars.portamento; 56 param.note_log2_freq = pars.note_log2_freq; 57 if(msg == LM_Norm) { 58 if(silent) { 59 fade.m = 0.0f; 60 msg = LM_FadeIn; 61 } 62 else { 63 fade.m = 1.0f; 64 msg = LM_FadeOut; 65 return 1; 66 } 67 } 68 if(msg == LM_ToNorm) 69 msg = LM_Norm; 70 } 71 return 0; 72 } 73 74 void SynthNote::Legato::apply(SynthNote ¬e, float *outl, float *outr) 75 { 76 if(silent) // Silencer 77 if(msg != LM_FadeIn) { 78 memset(outl, 0, synth.bufferbytes); 79 memset(outr, 0, synth.bufferbytes); 80 } 81 try { 82 switch (msg) { 83 case LM_CatchUp: // Continue the catch-up... 84 if (decounter == -10) 85 decounter = fade.length; 86 //Yea, could be done without the loop... 87 for (int i = 0; i < synth.buffersize; ++i) { 88 decounter--; 89 if (decounter < 1) { 90 // Catching-up done, we can finally set 91 // the note to the actual parameters. 92 decounter = -10; 93 msg = LM_ToNorm; 94 LegatoParams pars{param.vel, param.portamento, 95 param.note_log2_freq, false, param.seed}; 96 note.legatonote(pars); 97 break; 98 } 99 } 100 break; 101 case LM_FadeIn: // Fade-in 102 if (decounter == -10) 103 decounter = fade.length; 104 silent = false; 105 for (int i = 0; i < synth.buffersize; ++i) { 106 decounter--; 107 if (decounter < 1) { 108 decounter = -10; 109 msg = LM_Norm; 110 break; 111 } 112 fade.m += fade.step; 113 outl[i] *= fade.m; 114 outr[i] *= fade.m; 115 } 116 break; 117 case LM_FadeOut: // Fade-out, then set the catch-up 118 if (decounter == -10) 119 decounter = fade.length; 120 for (int i = 0; i < synth.buffersize; ++i) { 121 decounter--; 122 if (decounter < 1) { 123 for (int j = i; j < synth.buffersize; ++j) { 124 outl[j] = 0.0f; 125 outr[j] = 0.0f; 126 } 127 decounter = -10; 128 silent = true; 129 // Fading-out done, now set the catch-up : 130 decounter = fade.length; 131 msg = LM_CatchUp; 132 //This freq should make this now silent note to catch-up/resync 133 //with the heard note for the same length it stayed at the 134 //previous freq during the fadeout. 135 const float catchupfreq_log2 = 2.0f * param.note_log2_freq - lastfreq_log2; 136 LegatoParams pars{param.vel, param.portamento, 137 catchupfreq_log2, false, param.seed}; 138 note.legatonote(pars); 139 break; 140 } 141 fade.m -= fade.step; 142 outl[i] *= fade.m; 143 outr[i] *= fade.m; 144 } 145 break; 146 default: 147 break; 148 } 149 } catch (std::bad_alloc &ba) { 150 std::cerr << "failed to apply legato: " << ba.what() << std::endl; 151 } 152 } 153 154 void SynthNote::setVelocity(float velocity_) { 155 legato.setSilent(true); //Let legato.update(...) returns 0. 156 LegatoParams pars{velocity_, 157 legato.getPortamento(), legato.getNoteLog2Freq(), true, legato.getSeed()}; 158 try { 159 legatonote(pars); 160 } catch (std::bad_alloc &ba) { 161 std::cerr << "failed to set velocity to legato note: " << ba.what() << std::endl; 162 } 163 legato.setDecounter(0); //avoid chopping sound due fade-in 164 } 165 166 void SynthNote::setPitch(float log2_freq_) { 167 legato.setSilent(true); //Let legato.update(...) return 0. 168 LegatoParams pars{legato.getVelocity(), 169 legato.getPortamento(), log2_freq_, true, legato.getSeed()}; 170 try { 171 legatonote(pars); 172 } catch (std::bad_alloc &ba) { 173 std::cerr << "failed to set velocity to legato note: " << ba.what() << std::endl; 174 } 175 legato.setDecounter(0); //avoid chopping sound due fade-in 176 } 177 178 void SynthNote::setFilterCutoff(float value) 179 { 180 /* set current value, if first time */ 181 if (filtercutoff_relfreq.isSet() == false) 182 filtercutoff_relfreq = ctl.filtercutoff.relfreq; 183 /* update value */ 184 filtercutoff_relfreq = 185 (value - 64.0f) * ctl.filtercutoff.depth / 4096.0f * 3.321928f; 186 } 187 188 float SynthNote::getFilterCutoffRelFreq(void) 189 { 190 if (filtercutoff_relfreq.isSet() == false) 191 return (ctl.filtercutoff.relfreq); 192 else 193 return (filtercutoff_relfreq); 194 } 195 196 float SynthNote::getRandomFloat() { 197 return (getRandomUint() / (INT32_MAX_FLOAT * 1.0f)); 198 } 199 200 prng_t SynthNote::getRandomUint() { 201 current_prng_state = prng_r(current_prng_state); 202 return current_prng_state; 203 } 204 205 }