Tags

Tags give the ability to mark specific points in history as being important
  • 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`.
  • v0.5.0

    saugns v0.5.0. Add a set of PD synthesis & PS options.
    
    Language changes:
     * Signal generator types. Add `W` mode toggle. (See below.)
     * Accept phase `p` values directly after `W` and `R` (a
       phase number requires e.g. parentheses around to set it
       apart from a wave or line type). This is mostly a shortcut
       to using phase subparameters (`W.a1/2`) and/or PM (`W[W]`).
     * Accept amplitude `a` values directly after `N` (not only
       after `A` as before); an amplitude number requries e.g.
       parentheses around to set it apart from the noise type.
       This is more for consistency and as a shortcut for AM.
     * Implement phase distortion synthesis, and some forms of
       pulsar synthesis as well. Add a set of phase `p`
       subparameters for this; each is for a distortion function,
       with main and subvalues which can be set, swept, and
       modulated. Used with constant numbers, they derive new wave
       types, e.g. `W.c2` is a sine alternating between on and off
       every other cycle with preserved base frequency.
     * Accept phase `p` subparameters for PD and for self-PM as
       `p[]` list heading subparameters. The main `p` parameter
       doesn't support value sweeps etc., so there was nothing
       else being parsed in such a way. This combines with the
       new support for `p` values right after `R` or `W`.
    
    Implement `R` and `W` PD options, each such subparameter
    (including its 2 subparameters) having full value ranges
    support.
     * Each PD option under `p` subparameters has in turn:
       - Subfrequency `.f`.
       - Phase offset `.p`.
     * The new duty cycle parameter `p.d` defaults to 1; a
       zoom phase distortion which is the inverse of `p.c`
       and corresponds to "PulWM", implemented through PD.
       Full zoom-out at 0.
     * The new cycle length parameter `p.c` defaults to 1.
       Values closer to 0 "zoom in" -- sawtooth-like edges
       may form. Values larger than 1 "zoom out", with the
       new area filled with a "blank" (the cycle beginning
       and end amplitude).
     * The new hold phase distortion with parameter `p.h`,
       a way to overwrite a portion of a wave cycle. Using
       a positive value draws a horizontal line up to that
       phase position, e.g. 1/4 for the first 1/4; using a
       negative value the line is drawn backward (for -1/4
       over the last 1/4).
     * The new `p.x` and `p.y` parameters allow a PWM-like
       phase distortion, which changes the size proportion
       of the 1st and 2nd halves of a cycle. Use `p.x` for
       "PWM" generalized to any wave type. Meanwhile `p.y`
       is the inverse, a rate-of-change distortion for how
       much phase moves in each half, making one "slower",
       the other "faster".
     * Tweak the `W` oscillator's LFO behavior for ADAA to
       remove overshoots, also fix PD glitches. For 0 Hz a
       prior value was (re-)used instead of a new, causing
       some LF noise with the new zoom-out PD. Instead, in
       case of phase difference at most 1 LUT value large,
       produce a naive sample instead. More glitches fixed
       for extreme PD where one sample pops up or down but
       some issues remain.
    
    Allow use of `W` as a naive oscillator using a new mode `m`
    switch. (The `W m` option is similar to `R m`, but simpler,
    having only 2 letters for modes as yet.) The default is `a`
    (ADAA, antiderivative anti-aliasing) preserving the current
    behavior. Using `n` switches to the naive implementation in
    the codebase that gives results like pre-v0.3.9 saugns, but
    with the current wave types -- not rounded like v0.3.3 had.
    
    Fix default line type for `p.a[]` -- now `lin`, was `cos`.
    
    Major refactoring, mainly of the generator module.
  • v0.4.8c

    saugns v0.4.8c. Fix minor bug, refactoring.
    
    Fix v0.4.8b bug which gave junk results when a
    0 Hz oscillator has an `f` modulator with `r`
    frequency ratio. (Normally useless, but valid
    in scripts.) Was due to use of uninitialized
    data for that specific case only.
    
    This script made noise with the buggy v0.4.8b,
    is correctly silent now:
    
    `W f0[W r10 a1000] t10`
  • v0.4.8b

    saugns v0.4.8b. Value range modulation for more parameters.
    
    For consistency, allow "Modulation with value ranges" for
    every parameter which accepts value sweeps. That's all with
    modulators, except the main phase & PM parameter `p` and its
    frequency-scaled PM subparameter `p.f`, where range-mapping
    doesn't make sense. This means it's now supported for `c`
    (channel mixing) and for self-PM `p.a` as well.
  • v0.4.8

    saugns v0.4.8. Add long-form value range modulation syntax.
    
    Modulation with value range. Add a new variation on
    the syntax with greater flexibility, for both `a`
    (amplitude) and `f`/`r` (frequency) parameters.
    
    Below `X` and `Y` denote optionally included range
    endpoint values, while `A` and `B` are the newly
    introduced modulator lists whose outputs are added
    for the endpoints only. The `C` and `D` modulator
    lists work as before. The old syntaxes remain as
    short forms unchanged:
     - `X[A]..Y[B].r[C].a[D]`
     - `X[D].rY[C]`
     - `X[D]`
    
    The use of the '..' changes the meaning of the first
    modulator list prior if included, so that it plays
    the part of `A` rather than of `D`. (If no `C` list
    is used for the generator the results of `A` and `D`
    modulators are identical, but the lists are built
    and cleared separately.)
  • v0.4.7c

    saugns v0.4.7c. Bugfixes for "r" rel. freq handling.
    
    Fix bugs for `r...` relative frequency parameters in
    AM modulators when placed inside `A` or `N`. (Latter
    types don't have frequency parameters, so use of `r`
    inside can't apply to them as the carriers outside.)
    When possible, make `r1` be better than `f1`.
     * A script `N a0[W]` now has a default frequency of
       `f440` for the inner `W`, not `r1` (which is like
       `f1` here, as there's no carrier frequency). But,
       in `W a0.r1[N[W]]` it's `r1`, effectively `f440`.
     * A separate bug affected e.g. `W a0.r1[A0[W r1]]`,
       where the `r1` acted like `f1` instead of passing
       the nearest outer frequency from the other `W`. A
       pointer wasn't passed along, a typo made it NULL.
     * Don't allow `r` for a modulator with all carriers
       being of types lacking a frequency parameter. Now
       such modulators are more like 1st level carriers.
    
    Clarify `r` behavior fully in the `README.SAU` file.