text: #include "demo_common.h"
  
  static const uint8_t scale[]  = {36, 40, 43, 45, 60, 48, 52, 55};
  static const uint8_t scale2[] = {33, 31, 26, 31, 29, 33, 31, 29};
  static const float pitch[]    = {0.5f, 1.0f, 1.0f};
  
  static CT_Smush rnd;
  
  static void init_voice(CTSS_Synth *synth, CTSS_DSPStack *stack, float freq);
  static int render_synth(const void *in,
                          void *out,
                          unsigned long frames,
                          const PaStreamCallbackTimeInfo *timeInfo,
                          PaStreamCallbackFlags status,
                          void *data);
  
  int main(int argc, char *argv[]) {
    AppState app;
  
    ct_smush_init(&rnd, 0xdecafbad);
    ctss_init(&app.synth, 32);
  
    ctss_add_global_lfo(&app.synth,
                        ctss_osc("lfo1", ctss_process_osc_sin, 0.0f,
                                 HZ_TO_RAD(1.0f / 16.0f), 0.5f, 1.2f));
    ctss_add_global_lfo(&app.synth, ctss_osc("lfo2", ctss_process_osc_sin, 0.0f,
                                             HZ_TO_RAD(0.25f), 0.495f, 0.5f));
  
    for (uint8_t i = 0; i < app.synth.numStacks; i++) {
      init_voice(&app.synth, &app.synth.stacks[i], ctss_notes[scale[0]]);
    }
  
    app.pitch    = -10;
    app.callback = render_synth;
    app.handler  = demo_key_handler;
    app.channels = 2;
  
    return demo(&app);
  }
  
  static void init_voice(CTSS_Synth *synth, CTSS_DSPStack *stack, float freq) {
    ctss_init_stack(stack);
    CTSS_DSPNode *env = ctss_adsr("env", synth->lfo[0]);
    ctss_configure_adsr(env, 0.15f, 0.02f, 0.3f, 1.0f, 0.5f, false);
    CTSS_DSPNode *osc1 = ctss_osc_pluck("osc1", freq, 0.001f, 0.6f, 0.0f);
    CTSS_DSPNode *sum  = ctss_op2("sum", osc1, env, ctss_process_mult);
    CTSS_DSPNode *filter =
        ctss_filter_iir("filter", IIR_LP, sum, NULL, 18000.0f, 0.1f);
    CTSS_DSPNode *pan = ctss_panning("pan", filter, NULL, 0.5f);
    CTSS_DSPNode *delay =
        ctss_delay("delay", pan, (uint32_t)(SAMPLE_RATE * 0.25f * 1.5f), 0.3f, 2);
  
    CTSS_DSPNode *nodes[] = {env, osc1, sum, filter, pan, delay};
    ctss_build_stack(stack, nodes, 6);
  }
  
  static int render_synth(const void *in,
                          void *out,
                          unsigned long frames,
                          const PaStreamCallbackTimeInfo *timeInfo,
                          PaStreamCallbackFlags status,
                          void *data) {
    AppState *app = (AppState *)data;
    float time    = (float)timeInfo->currentTime;
    float ft      = fmodf(time, 0.25f);
    if (ft < 0.008) {
      float freq       = ctss_notes[scale[app->noteID % 8] + app->pitch];
      CTSS_DSPStack *s = &app->synth.stacks[app->voiceID];
      ctss_reset_adsr(NODE_ID(s, "env"));
      freq *= pitch[ct_smush(&rnd) % 3];
      ctss_reset_pluck(NODE_ID(s, "osc1"), freq,
                       ct_smush_minmax(&rnd, 0.001f, 0.05f),
                       ct_smush_minmax(&rnd, 0.05f, 0.95f));
      CTSS_PluckOsc *osc = NODE_ID_STATE(CTSS_PluckOsc, s, "osc1");
      osc->gain          = ct_smush_minmax(&rnd, 0.15f, 0.6f);
      osc->damping       = ct_smush_minmax(&rnd, 0.2f, 0.5f);
      osc->variation     = 0.5f;
      NODE_ID_STATE(CTSS_PanningState, s, "pan")
          ->pos = ct_smush_minmax(&rnd, 0.0f, 1.0f);
      ctss_activate_stack(s);
      app->noteID++;
      app->voiceID = (app->voiceID + 1) % app->synth.numStacks;
    }
    ft = fmodf(time, 0.5f);
    if (ft < 0.008) {
      float freq       = ctss_notes[scale[7 - app->noteID % 8] + app->pitch + 7];
      CTSS_DSPStack *s = &app->synth.stacks[app->voiceID];
      ctss_reset_adsr(NODE_ID(s, "env"));
      ctss_reset_pluck(NODE_ID(s, "osc1"), freq,
                       ct_smush_minmax(&rnd, 0.005f, 0.05f),
                       ct_smush_minmax(&rnd, 0.05f, 0.95f));
      CTSS_PluckOsc *osc = NODE_ID_STATE(CTSS_PluckOsc, s, "osc1");
      osc->gain          = ct_smush_minmax(&rnd, 0.05f, 0.4f) * 1.5f;
      osc->damping       = ct_smush_minmax(&rnd, 0.1f, 0.9f);
      osc->variation     = 0.5f;
      NODE_ID_STATE(CTSS_PanningState, s, "pan")
          ->pos = ct_smush_minmax(&rnd, 0.0f, 1.0f);
      ctss_activate_stack(s);
      app->noteID++;
      app->voiceID = (app->voiceID + 1) % app->synth.numStacks;
    }
  
    ctss_update_mix_stereo_f32(&app->synth, ctss_mixdown_f32, frames,
                               (float *)out);
    return 0;
  }
  