Crate culsynth

source ·
Expand description

This crate contains all of the DSP logic for the synthesizer. It is designed to be no_std friendly (though it has not yet been build/tested in this config) and all of the API and algorithms are designed to be implemented using both floating-point logic and fixed point logic. The fixed point logic additionally does not use division and minimizes the use of 32 bit widening multiplies (that is, with a 64 bit result) to the maximum extent possible for speed on embedded platforms without native hardware support for these primitives.

Most of the relevant code for users can be found in the devices module.

This crate uses the (somewhat regrettably hungarian-style) convention of having all fixed-point structs and traits be the same as their floating-point counterparts with the FxP suffix to denote fixed point operation. This is used instead of implementing it as generics implementations on u16 to preserve information about the location of the decimal place within the type system, but does require some duplication of code throughout the crate.

Modules§

  • This module provides objects to reason about the processing context. Currently, the only information wrapped is the current audio sample rate.
  • This module contains definitions of several different DSP primitives.
  • This module contains u8 constants for MIDI note numbers, using standard musical notation. For example, midi_const::Db4 is the note a semitone above middle C, and midi_const::A4 == 69u8 is A440.
  • Various utility functions and helpful constants
  • This module contains a struct composing various devices together as a single voice unit for a basic subtractive synthesizer.

Constants§

  • True if using libm for floating-point math, false if using internal approximation functions

Traits§

  • Helper trait to make constraint bounds less painful for floating point types
  • A trait encompassing the different sample data types (e.g. 16 bit fixed, 32 bit float, etc).
  • Type aliases defining the data types of various internal signals within the synthesizer. This is primariliy to be generic over fixed/floating point
  • A trait to simplify common operations on DSP Types. This is used to maximize the amount of code that can be agnostic to fixed and floating point
  • A trait encompassing 16 bit fixed point numbers along with a couple of convenience methods for the type.
  • Types must implement this trait to instantiate any of the generic devices in this module. Implementations are provided for f32 and f64.

Functions§

Type Aliases§

  • An envelope rise/fall time parameter, represented in seconds as an unsigned 16 bit fixed point number with 13 fractional bits and 3 integral bits. This yields a range of 0 to 8 seconds - though as implemented this timing is not precisely accurate (see [devices::EnvParamsFxP])
  • A unsigned 32 bit fixed point number representing a frequency in Hz. This uses 14 integral bits and 18 fractional bits
  • A signed value in the range [-1, 1) - used where we need a signed version of a ScalarFxP
  • A frequency parameter for a LFO, in Hertz
  • A unsigned 16 bit fixed point number representing a note/pitch, with 7 integral bits and 9 fractional. The integral bits correspond to the MIDI note numbers, i.e. a value of 69.0 represents A440 and tuning is 12 tone equal temprament.
  • A fixed point number representing a sample or otherwise generic piece of data within the synthesizer. These are 16 bit signed fixed point numbers with 12 fractional bits. Put another way, our reference (0dB) level is set at an amplitude of 2^12, and we have 3 bits (9dB) of headroom before clipping, since we lose a bit for the sign bit.
  • A unsigned 16 bit fixed point number in the interval [0, 1). Used primarily for “scaling” signals in amplitude, hence the (admittedly not great but useful) name assigned. Note that 0xFFFF is slightly less than 1.0, so we will lose a (very) small amount of signal when maxed out.
  • A signed variant of the above. This does not have the precision to represent the entire range of the MIDI note range, but is helpful for small adjustments (e.g. pitch bend)
  • A unsigned data type with the same number of fractional bits as a sample. Usually used for internal processing to steal an extra bit of precision when we know a value cannot be negative.