typically the output is a series of sample values that represent pressure over time. to save memory, samples are processed in blocks (arrays) rather than one by one. processing each sample individually adds significant overhead due to repeated parameter setup. block-based processing is more efficient.
multiple channels (for stereo or surround sound) can be stored either non interleaved (separate arrays per channel) or interleaved (channel samples alternating in one array). non interleaved storage is easier to process, while interleaved storage is more robust against playback interruptions since any input lag affects all channels equally. channel samples can be generated independently or generated once and then copied with modifications; independent generation allows more dynamic differences. sounds that are not centered often use different amplitudes, slight frequency shifts, or small delays per channel to simulate panning. common mixing controls attenuate one channel when panning left or right and leave both equal when centered.
to record generated samples, write them to audio files. without real-time playback this process is similar to rendering in 3d graphics. wav files with 32 bit float samples are the most widely supported high quality format. flac uses integer samples, which requires rounding when converting from float. au is a very simple format that supports multiple channels, sample rates, and formats, has minimal overhead, and is easy to implement, but it is less widely supported than wav.
amplitude and frequency transitions (envelopes) can be represented by paths. a path is defined by a few control points and an interpolation method. paths can also be stored as discrete values in arrays; array lookup is faster than interpolation but uses more memory. you can combine paths with pointwise operations such as addition, composition, reverse, stretch, scale, and randomization of interpolation segments.
noise describes sound with a random distribution of many frequencies, for example percussive bursts, hissing, or wind. it is typically generated by sampling a uniform random number generator and then filtering to shape the frequency content. summing many sine waves can produce noise but is computationally expensive and requires handling phase interference effects.
random numbers in software come from a pseudorandom generator that produces real or integer values in specified ranges. a uniform distribution assigns equal probability across the range and corresponds to white noise. other distributions are possible, including discrete distributions defined by custom arrays. see the distributions supported by the gnu scientific library for examples. generators use seed values so that the same sequence can be reproduced.
here is an example implementation of a random number generator for custom discrete probabilities in scheme:
cusum = (a, b...) -> # calculate cumulative sums from the given numbers. # (a b c ...) -> (a (+ a b) (+ a b c) ...) if b.length is 0 then [a] else [a].concat cusum(a + b[0], *b.slice(1)) random_discrete_f = (probabilities, state = random_state) -> ### (real ...) [random-state] -> procedure:{-> real} return a function that when called returns an index of a value in probabilities. each index will be returned with a probability given by the value at the index. each value is a fraction of the sum of probabilities. for example, if the values sum to 100, each entry in probabilities is a percentage. this allows for custom discrete random probability distributions. example usage: random_fn = random_discrete_f [10, 70, 20] samples = [random_fn(), random_fn()] ### cu_prob = cusum(probabilities[0], *probabilities.slice(1)) total = cu_prob[cu_prob.length - 1] -> deviate = if state? and typeof state.random is 'function' state.random() * total else Math.random() * total for idx in [0...cu_prob.length] if deviate < cu_prob[idx] return idx
two particularly useful digital filter types are:
samples can be analysed with statistical measures such as:
note the typical values for kurtosis and skewness are not limited to a range of 0 to 1
transform signals to match specific statistical properties using techniques such as:
for frequencies, sample offsets and related calculations, you can use different units