zynaddsubfx

ZynAddSubFX open source synthesizer
Log | Files | Refs | Submodules | LICENSE

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 &note, 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 }