249 lines · 4.9 KB · Text
RawDownload
#+TITLE: expmap* Overview=expmap= is an exponential signal mapper with variableslope. It takes in a normalized linear value, and appliesan exponential curve to it. Two version of =expmap= are provided: a naive implementationthat is easy to read and adapt, and a more optimized versionthat uses parameter caching to reduce division operationsand calls to =exp=.* EquationThis is all there is to it: @!(fig "expmap_eqn""{1 - e^{xs} \\over 1 - e^{s}}")!@ Where @!(smallfig "expmap_x" "x")!@ is the normalizedlinear input signal, and @!(smallfig "expmap_s" "s")!@ isthe slope. As @!(smallfig "expmap_s")!@ gets more negative, theexponential curve will be more convex, with more valuesstaying closer to 1. As @!(smallfig "expmap_s")!@ gets morepositive, the exponential curve will get more concave, withmore values staying closer to 0.* Tangled Files=expmap.c= and =expmap.h= are the tangled files. If=SK_EXPMAP_PRIV= is defined, it exposes the structs. #+NAME: expmap.c#+BEGIN_SRC c :tangle expmap.c#include <math.h>#define SK_EXPMAP_PRIV#include "expmap.h"<<static_funcdefs>><<funcs>>#+END_SRC #+NAME: expmap.h#+BEGIN_SRC c :tangle expmap.h#ifndef SK_EXPMAP_H#define SK_EXPMAP_H #ifndef SKFLT#define SKFLT float#endif <<typedefs>><<funcdefs>> #ifdef SK_EXPMAP_PRIV<<structs>>#endif #endif#+END_SRC* Naive Function (stateless).The function =sk_expmap_stateless= will computethis exponential function without any internal state.The code is quite clear and simple,but requires two calls =exp=, which is an expensiveoperation. #+NAME: funcdefs#+BEGIN_SRC cSKFLT sk_expmap_stateless(SKFLT in, SKFLT slope);#+END_SRC #+NAME: funcs#+BEGIN_SRC cSKFLT sk_expmap_stateless(SKFLT in, SKFLT slope){    return (1 - exp(in*slope)) / (1 - exp(slope));}#+END_SRC* StructCalled =sk_expmap=. #+NAME: typedefs#+BEGIN_SRC ctypedef struct sk_expmap sk_expmap;#+END_SRC #+NAME: structs#+BEGIN_SRC cstruct sk_expmap {    <<sk_expmap>>};#+END_SRC* Input/Ouput CachingTo avoid computation, some caching of the input/outputvariables are used. =pin= is the cached input value, will be used to avoidcomputation. At init, it is set to be an (invalid) negativevalue. #+NAME: sk_expmap#+BEGIN_SRC cSKFLT pin;#+END_SRC #+NAME: init#+BEGIN_SRC cem->pin = -1;#+END_SRC =pout= is the cached computed output value. It is used if nocomputation is needed. By default, it is set to be -1. It isassumed that this value shouldn't actually ever be returned. #+NAME: sk_expmap#+BEGIN_SRC cSKFLT pout;#+END_SRC #+NAME: init#+BEGIN_SRC cem->pout = -1;#+END_SRC* Scaling Constant=scale= is the constant =1/(1 - exp(slope)=. A scaler usedto shave off an expensive =exp= operation and =div=operation. #+NAME: sk_expmap#+BEGIN_SRC cSKFLT scale;#+END_SRC The scaling value can be computed with the static function=compute_scale=, given an input slope. #+NAME: static_funcdefs#+BEGIN_SRC cstatic SKFLT compute_scale(SKFLT slope);#+END_SRC #+NAME: funcs#+BEGIN_SRC cstatic SKFLT compute_scale(SKFLT slope){    return 1 / (1 - exp(slope));}#+END_SRC After the =slope= is initialized, the scale is initializedto be the slope. #+NAME: init_scale#+BEGIN_SRC cem->scale = compute_scale(em->slope);#+END_SRC* InitializationInitialization is done with =sk_expmap_init=. #+NAME: funcdefs#+BEGIN_SRC cvoid sk_expmap_init(sk_expmap *em);#+END_SRC #+NAME: funcs#+BEGIN_SRC cvoid sk_expmap_init(sk_expmap *em){    <<init>>}#+END_SRC* Changing SlopeThe slope of expmap can be changed with =sk_expmap_slope=. #+NAME: funcdefs#+BEGIN_SRC cvoid sk_expmap_slope(sk_expmap *em, SKFLT slope);#+END_SRC #+NAME: funcs#+BEGIN_SRC cvoid sk_expmap_slope(sk_expmap *em, SKFLT slope){    em->slope = slope;}#+END_SRC The slope parameter uses caching to avoid re-computation. #+NAME: sk_expmap#+BEGIN_SRC cSKFLT slope;SKFLT pslope;#+END_SRC The slope is set to be =1= to begin. #+NAME: init#+BEGIN_SRC csk_expmap_slope(em, 1);em->pslope = 1;<<init_scale>>#+END_SRC* ComputeA single sample of audio is computed with =sk_expmap_tick=. #+NAME: funcdefs#+BEGIN_SRC cSKFLT sk_expmap_tick(sk_expmap *em, SKFLT in);#+END_SRC #+NAME: funcs#+BEGIN_SRC cSKFLT sk_expmap_tick(sk_expmap *em, SKFLT in){    SKFLT out = 0;    <<update_scale_value>>    <<compute>>    return out;}#+END_SRC Before a sample is computed, the slope parameter is checkedfor updates. If it is updated, the scale needs to bere-computed. #+NAME: update_scale_value#+BEGIN_SRC cif (em->slope != em->pslope) {    em->pslope = em->slope;    em->scale = compute_scale(em->slope);}#+END_SRC Computation is done only if the input value =in= isdifferent from the cached input value =pin=. Ifit is, it updates the cached output value =pout=.  the output variable =out= is set to be the cached value=pout=. #+NAME: compute#+BEGIN_SRC cif (in != em->pin) {    em->pin = in;    em->pout = (1 - exp(in * em->slope)) * em->scale;}out = em->pout;#+END_SRC

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t