Tags

Tags give the ability to mark specific points in history as being important
  • v0.5.8b

    saugns v0.5.8b. ADSR envelope edge case fixes.
    
    Fix ADSR envelope behavior when earlier stages take up the
    whole note time and there's more than one stage left; now,
    ensure advancing past every stage when note time runs out.
    The exception is in loop mode (`el`), which disregards the
    note duration. Also, fix edge cases for declick mode `ed`.
  • v0.5.8

    saugns v0.5.8. Support ternary smooth violet noise, etc.
    
    Language changes:
     * Signal generator types. `R` mode `m` noise functions:
       - Modify ternary `t` so that changing the shaping level
         does not mix it with uniform random; instead, make it
         only impact every other value, keeping it a form of
         "zero-stuffed" violet noise (which is what makes it
         sound "smoother" especially when used as modulator).
       - Implement violet `v` version of `t`. Less bassy, and
         yet more smooth-sounding for intense use as modulation
         carrier or modulator. This is a zero-stuffed version of
         the binary violet noise.
       - Add `m.z` override for zero-stuffing amplitude used by
         `t` modes; can e.g. be set to -1 to ensure every other
         half-cycle hits the bottom amplitude (making it bottom
         heavy).
     * Noise types for `N`: add `tv` ternary violet noise, i.e.
       zero-stuffed version of `bv` (binary violet noise).
  • v0.5.7c

    saugns v0.5.7c. Ladder effect distortion panning and tweak.
    
    Language changes:
     * Channel mixing. Add new pan law `a` additive mix panning
       (`c.pa`), which is a complement to `f` full-volume mode.
       Only increases channel panned to (the other unaffected).
       Used as part of implementing more accurate ladder effect
       panning.
     * Ladder effect distortion:
       - Add `a.l[p]` pan ratio control; multiplier for channel
         mixing `c` parameter, used specifically for the ladder
         effect pulse. If 0, mixes the pulse in mono as before.
         The new behavior, for more accurate emulation uses `C`
         (-1/7) as the default. Behavior depends on pan law.
       - Deprecate `a.l.t` in favor of renamed `a.l[t]` option.
    
    Tweak ladder effect distortion `a.l` behavior; the behavior
    to limit DC offset on silence was bad especially for LFO as
    it could halve the pulse level for half the cycle. It could
    _somewhat_ reduce pulse amplitude in more cases too. Fixed.
    
    Previously, the pulse (always up for an input amplitude not
    below minus the `a.l[t]` threshold value) would if up decay
    to 0 if it remained up. Now it only decays when input isn't
    also above plus the `a.l[t]` threshold value. It's reset to
    full amplitude when not decaying.
    
    This does cause a new quirk, mainly noticeable for a larger
    `a.l[t]` value and/or larger `a.l` pulse amplitude. When up
    the pulse may distort, decay beginning, only to be followed
    by a jump up in level if the input amplitude rises. This is
    mainly visible in the waveform but not audible.
  • v0.5.7b

    saugns v0.5.7b. ';' timing fix. Add ADSR 's.t' min sustain.
    
    Language changes:
     * Parameter envelopes.
       - Add minimum sustain time `s.t` envelope parameter. Can
         be used to ensure the sustain stage runs for a time if
         the envelope continues. When time is insufficient, and
         sustain is normally missing, the release is displaced.
         In loop mode `el`, a sustain stage is added.
       - Rename envelope mode `c` (clip envelope shape) back to
         `t` (truncated envelope).
    
    Fix voice allocation for `;` syntax with no time `t` after;
    an old bug could make such a voice expire prematurely. This
    fix is needed for a new `examples/drums-and-eh.sau` script.
  • v0.5.7

    saugns v0.5.7. Added "ladder effect" distortion. And more.
    
    Language changes:
     * Amplitude handling. Add "ladder effect" distortion `a.l`
       (by default off). The constant `C` (7/512, as in `a.lC`)
       matches the YM2612 chip level for the pulse added by the
       distortion. This is Sega Mega Drive/Genesis model 1 type
       distortion, a.k.a. the hardware bug part of the "sound".
        - The mixing scales the original signal, plus the added
          pulse, so that 1.0 plus pulse is brought down to 1.0.
        - The pulse is added in mono regardless of panning. The
          actual chip only allowed switching channels (left and
          right) on and off and added the pulse in all 4 cases.
          For more accurate behavior, use full-level panning as
          in `c.pf`; only the mute + pulse behavior is missing.
        - A threshold control `a.l.t` generalizes the behavior.
          The pulse shape is controlled by the threshold; where
          the size of negative input amplitudes exceeds the set
          threshold, the pulse is down, otherwise up (including
          whenever the amplitude is positive). The default `C`,
          here 2^-13, makes it match the chip behavior. For any
          levels from zero to minus the threshold, a completely
          different distortion (not matching the chip) is added
          by silencing that portion of the waveform. If raising
          the threshold, this becomes audible; it combines with
          the added pulse such that when the pulse fades out, a
          half-wave rectified signal remains which is "colored"
          similarly to a milder version of the pulse.
     * Frequency filters. The generator `a.f` options now apply
       to the final result for a generator. Previously, the `c`
       (channel mixing) options were handled afterward; panning
       wasn't filtered, but rather after filtering, unlike now.
     * Fix, that is apply `S c.p`; didn't actually work before.
     * Parameter sweeps. For a frequency sweep from `f` to `r`,
       or `r` to `f`, no longer convert its `v` to match `g` --
       do not make the `v` value a ratio or non-ratio to match.
       Instead let the line type interpolate between behaviors.
     * Deprecate use of PD and self-PM subparameters after `p.`
       in favor of the `p[]` syntax. This also means e.g. `W[]`
       and `R[]` instead of `W.` and `R.` for shorthand syntax.
     * Deprecate use of filter options `a.f.l` and `a.f.h`; the
       `a.f[l h]` options are favored.
    
    From now on each subparameter option will be available only
    through one of, after a `.` or within `[]`, never both. New
    options may use this to have the same name, but a different
    meaning.
  • v0.5.6c

    saugns v0.5.6c. Ratio carrier selection for modulators. Fix.
    
    Language changes:
     * Frequency. Ratio carrier selection for modulators. Every
       modulator now has the `r.c` option; it allows overriding
       which carrier's frequency is multiplied by the `r` value
       (by default going up one level, `r.c-1`). Changing it to
       0 or a positive value will go inward, from the root/top.
       Values out of range are clamped to the range, from root,
       to the level just above the modulator being set.
    
    Fix v0.5.6 edge case bug for frequency parameter sweeps; if
    using ratio for goal but not for state or vice-versa (mixed
    rather than consistent selection), the newer handling could
    mess up the signal. Scripts like the below are now fixed.
    
    "W f[W f10 a440] t10 p[R f440 r[g1]]"
  • v0.5.6b

    saugns v0.5.6b. Add pan law switches. Remove time '|' quirk.
    
    Language changes:
     * Channel mixing. Add `c.p` pan law switch to each
       generator, and a `S c.p` default setting. The modes are:
       - `l` (linear, center -6 dB, default). The old behavior,
         allows a mono downmix to undo panning cleanly.
       - `f` (full, center -0 dB). Makes positions `L`, `R` and
         `C` behave like traditional channel switcher settings.
         `2*L` or `2*R` cause a phase-inverted "fake surround".
         Modulation produces stereo-spread distortion (mono mix
         simplifies the sound while it remains impure).
     * Timing. For `|` time separator, correct an inconsistency
       (and the documentation). Using `|` never decreases delay
       to add now. Previously, it did so only when no generator
       was active in scope (like before any is added or after a
       prior `|`).
  • v0.5.6

    saugns v0.5.6. Add 1-pole filter options. Redesign rendering.
    
    Language changes:
     * Frequency filters.
        - Add filter option `a.f` for all audio generators, and
          1-pole lowpass and highpass filters. Options `a.f.l`,
          `a.f.h` (alternatively `a.f[l h]`) will set a cut-off
          frequency to use if given a positive number; if given
          0, the filter is disabled. As shorthand, `a.f` can be
          given a number if only lowpass or highpass (not both)
          is to be used; a positive number is used for lowpass,
          while a negative number is negated, and then used for
          highpass; if 0 is set, both filters are disabled.
        - Add global mix filters under `S a.f`, the same syntax
          and use as those for individual audio generators. The
          use of these filters is recommended to filter a whole
          audio file.
     * Parameter sweeps. Change sweep time interpretation, from
       being dynamic (much like time for a modulator), to being
       static or parse-time (much like timing offset syntax). A
       sweep is no longer paused or delayed if the generator it
       belongs to is paused or unused.
    
    Change `-p` printouts to only include script/"program" info
    beyond statistics if verbose `-v` is also passed. Tweak the
    format as well both for statistics and for verbose display.
    
    Redesign audio generation code; the traversal of the linked
    generators and deciding what to run now happens in new code
    in parser/semantics.h. The generator.c code now only runs a
    set of instructions (sauRIns), provided/set once per event.
    The aim is to move complexity out from the audio rendering.
  • v0.5.5b

    saugns v0.5.5b. Another edge case fix for internal ID reuse.
    
    Fix remaining object ID allocation/reuse bug. A script like
    the following misbehaved (in this case making the `N` silent
    the last second): "W[R t2 ; a0] t1 /1 W[N t4] t2"
    
    Further ID reuse correctness changes, and final improvements
    for reuse (see `saugns -p` output) with this approach.
  • v0.5.5

    saugns v0.5.5. Make numerical variables lexically scoped.
    
    Language changes:
     * Numerical expressions. Fix parsing bug causing `num-[]`
       (where `-[]` is a later expression clearing and setting
       a modulator list) to fail to read number `num`.
     * Numerical variables. Make them lexically scoped,
       add an option for accessing globals.
       - Make `$var=` always assign to a variable at the
         current block/list level.
       - Make `$var` in a numerical expression return a value
         from the lexically closest variable with a value, if
         any. Thus `$var=$var` may create a new local variable
         given the value of a variable from an outer scope.
       - Add `$~var` which can be used to read and/or write
         to a global variable from any lexical scope. For any
         syntax that began with `$var`, `$~var` is available.
       - Restrict `$?var` to being used at the global scope.
         Non-overriding assignmnent `$var?=` can still be used
         at any scope; it checks for the existence of `$var` at
         any scope, does nothing if it exists, defines a local
         variable if it does not exist.
     * Time values. Rename constant `D` to `T`.
  • v0.5.4

    saugns v0.5.4. Envelope mode changes, add 'S e' option.
    
    Language changes:
     * Script options. Add envelope setting `S e` to allow
       setting values for several envelopes at once. The values
       accepted are the same as those for any `.e` envelope
       subparameter, except for a lack of sweep and modulator
       values within `S e[]`. To apply the setting to envelopes
       in some generator after in the same scope, "touch" an
       envelope setting by writing its name, for example `a.e`
       mentions the amplitude envelope and the setting is then
       applied to it.
     * Parameter envelopes. Adjust ADSR envelope modes,
       changing the default to the new declick mode `d`.
       - Rename modes `t` (truncate envelope trajectory)
         to `c` (clip envelope shape), and the old `c`
         (clamp stage times) to `s` (shrink stage times).
       - Add `d` (declicked envelope shape), which when time
         runs out before completion keeps the last value and
         starts the next attack from it. Otherwise like `c`.
    
    Fix v0.5.2 bug which caused `S a` behavior when an affected
    generator uses AM lists to go wrong (scaling was wrongly
    applied to `.r[]` too, and not to `.e[]` which it should be).
    
    Simplify parser semantics, merge generator and object IDs.
    The object ID reuse is slightly better than in v0.5.3e
    (which improved it compared to v0.5.3d), but less "perfect"
    than v0.5.3e generator ID reuse (in return re-simplifying
    the generator pass code).
  • v0.5.3e

    saugns v0.5.3e. Fix several parsing bugs.
    
    Fix v0.5.3 use-after-free when cloning into modulator lists,
    as triggered by scripts such as: `'a W[R] | N[A :a N :a :a]`
    
    Fix time placement of `@name` inside modulator list assigned
    for a `;` compound step. This never worked correctly before;
    it used to be placed before the `;` in time from v0.3.12, in
    older versions being placed an extra time after `;` instead.
    
    Also fix behavior of the undocumented `{}` grouping feature,
    specifically it mixed with the `;` compound step, `{; ...}`.
  • v0.5.3d

    saugns v0.5.3d. Fix elusive bug in semantics code.
    
    Fix v0.5.3 bug not caught by test scripts, which may prevent
    correct generator ID reuse in scripts which use more voices.
  • v0.5.3c

    saugns v0.5.3c. Fix crash on failed script file open.
    
    Fix v0.5.3 bug causing crash (occasionally hang) when saugns
    fails to open a file to parse (for example, bogus filename).
  • v0.5.3b

    saugns v0.5.3b. Fix edge case for cloned modulators.
    
    In v0.5.3 object IDs alongside generator IDs were made
    to be reused. Object ID reuse code missed an edge case
    (to treat cloned modulators as labeled/non-reusable if
    the main/carrier generator cloned is freshly labeled).
    A crash could happen for scripts triggering the error.
  • v0.5.3

    saugns v0.5.3. Generator cloning with ':name'.
    
    Language changes:
     * Time values. Replace non-number literal `d` for
       the main time `t` parameter with a constant `D`
       usable for every time length parameter.
     * Label syntax.
       - Add `:name` expression, for copying the object
         pointed to by "name". A generator copy will be
         inserted where the reference is placed, unlike
         with an `@name` reference which merely touches
         the original object. A copy has separate time.
         All modulators are also cloned, once per copy.
       - Remove the deprecated syntax for num. variable
         assignment, `'name=`.
    
    Simplify parsing code and semantics before audio generation.
    One less set of data structures, don't copy and "convert".
    The code formerly called "parseconv" is now parser/semantics.
    
    Write generator number allocation code in parser semantics to
    reuse generators when their durations expire in scripts. The
    printouts from `saugns -p` reflect the new scheduling, the
    audio output is (of course) identical.
  • v0.5.2

    saugns v0.5.2. Give 'A' and 'N' wrappers 'f' control.
    
    Language changes:
     * Signal generator types. Allow frequency `f` (and ratio `r`)
       for all generators, not only oscillators. This allows using
       `A0[...]` (or `N[...]`) as a wrapper generator and giving
       it timed pitch changes, to control nested oscillators
       inside (which can use `r`). Useful for FM and additive
       sound design, with several carriers per voice.
     * Line types. More exp/log types with steepness not 6.
        - Add `exp11`, `log11`, `xpe11`, `lge11`. Steepness 11.
     * Modulation with value ranges. Tweak semantics, and add
       envelope options `.e` to long-form, for completeness. Don't
       switch list behavior for the very first list when the `..`
       long-form syntax is written just after, instead do it when
       short-form `.r` or `.e` are written after. After `..`, the
       options `.r`, `.e`, and/or `.a` can be used -- concatenated
       in the order listed, with any left out. For example, just
       one of them, or `.r.e`.
     * Fix `S a` when placed in additive AM list. (A typo in the
       code prevented multiplication by outer level setting from
       working, muting sound for generators after in scope
       instead.)
     * Frequencies as notes. Slightly tweak JI quartertones used.
  • v0.5.1

    saugns v0.5.1. Add ADSR envelope to sweepable parameters.
    
    Language changes:
     * Parameter envelopes. Implement ADSR envelope, add to every
       sweepable parameter. This uses list heading subparameters,
       under the new `.e` (envelope) subparameter which has a new
       sweepable secondary value (like that for value range `.r`,
       but for an envelope as a stage applied after, similarly).
       The envelope secondary value also accepts modulators in
       the list as does the long-form value range secondary value.
       - Add `a`, `d`, `s`, `r` subparameters within `.e[...]` --
         these can be used alongside the sweep subparameters.
         Also add `e` for further envelope-specific settings.
       - Add line selection `.l` sub-subparameter for each timed
         subparameter (`a`, `d`, and `r`), as well as `e` for
         setting all of them (overridden by the others if used
         at the same time) as in `e.lcos`.
       - Add 4 modes which can be toggled under `e`, default `ec`:
         `0` (off), `c` (clamp stage times to fit note duration,
         shortening stage trajectories without cutting them off),
         `l` (loop envelope instead of triggering when time set),
         `t` (truncate envelope trajectory if times are too long).
     * Remove long-deprecated sweep subparameter `r` (now `l`).
     * Phase distortion synthesis. Make the secondary parameter
       values default to the do-nothing values if not zero. Makes
       PD envelopes and value range modulation simpler to use.
    
    Support an ADSR envelope for each of the parameters allowing
    value ranges and sweeps (most). It triggers and runs anew with
    each new time duration set to the main `t` parameter for the
    generator the parameter belongs to. Each `;` for the generator
    implicitly sets `t` and thus triggers the envelope.
    
    For modulators, if time is implicit/indefinite (default `ti`)
    then the envelopes for parameters trigger with the closest
    carrier having its time set. Thus a single `;` for a carrier
    can trigger envelopes for a nested structure of oscillators.
    
    Prune example scripts, tweak some old ones adding envelopes.
    
    Performance tweaks to phaseshaping code, replace floorf().
  • v0.5.0c

    saugns v0.5.0c. Fix for builds with the clang 19 compiler.
    
    This is for an issue known to have affected x86-64.
    
    No difference for gcc nor for clang 18 and older.
    With clang 19, to keep -ffast-math builds from having
    broken FM and PM, never use lrint()/lrintf(), always
    use llrint()/llrintf() even when C type `long` is 64-bit.
    (Otherwise the former turn into 32-bit result instructions
    that clip values in some places.)
  • v0.5.0b

    saugns v0.5.0b. Fixes for PD parameter handling.
    
    Fix sweeps for PD parameters. These were meant to
    work, but were broken by v0.5.0 refactoring; time
    flags lacked initialization.
    
    Correct polarity of PD `.p` phase offset for `R`,
    was flipped relative to `W`.
    
    Fix mis-scaling of the `.p` phase offset for `.c`
    and `.d`, when using `R mh`, and for `R` whenever
    the `.f` multiplier is used.
    
    Refactor, unify "phasor" (phase signal generator,
    including PD) for `W` & `R`.