import { isNumber } from "@thi.ng/checks/is-number" ; import { Add , add } from "./add.js" ; import { AGen } from "./agen.js" ; import type { IGen , StatelessOscillator } from "./api.js" ; import { Const } from "./const.js" ; import { sum } from "./sum.js" ; /**
 * Higher order oscillator gen, wrapping a  StatelessOscillator * function and supporting either constant or  IGen -based
 * frequency and amplitude, thus allowing for FM/AM modulation.
 * Furthermore, a constant `dc` offset (center value) can be specified
 * (default: 0).
 *
 *  remarks If `freq` is a number, it must be given as normalized frequency. If
 * `freq` is an `IGen`, it must be configured to produce normalized
 * frequency values (e.g. if using an `Osc` by setting its `amp` to a
 * normalized freq and its `dc` offset to `baseFreq * TAU`). Also see
 *  fmodOsc for syntax sugar.
 *
 * The oscillator initializes to zero and its
 *  {@link @thi.ng/api#IDeref.deref} value is only available / valid
 * after the first invocation of  IGen . next .
 *
 *  param osc param freq param amp param dc export const osc = ( osc , freq , amp ? , dc ? ) => new Osc ( osc , freq , amp , dc ) ; remarks example param osc param freq param fmod param amod export const modOsc = ( osc , freq , fmod , amod = 1 ) => new Osc ( osc , sum ( fmod , isNumber ( freq ) ? add ( freq ) : freq ) , amod ) ; export class Osc extends AGen < number > { protected _phase ! : IGen < number > ; protected _amp ! : IGen < number > ; constructor ( protected _osc , freq , amp = 1 , protected _dc = 0 ) { super ( 0 ) ; this . setFreq ( freq ) ; this . setAmp ( amp ) ; } next ( ) { return ( this . _val = this . _osc ( this . _phase . next ( ) , 1 , this . _amp . next ( ) , this . _dc ) ) ; } setFreq ( freq , phase = 0 ) { this . _phase = isNumber ( freq ) ? new Add ( freq , phase ) : freq ; } setAmp ( amp ) { this . _amp = isNumber ( amp ) ? new Const ( amp ) : amp ; } }