5 //------------------------------------------------------------------------
6 // An ASR envelope on a complex phasor,
7 // with asynchronous trigger for R stage.
8 // A/R use sine shaping.
9 //------------------------------------------------------------------------
12 SpotTone(SpotToneGen st) {
15 ComplexOSC(st->osc.gen);
17 for (i = 0; i < n; i++) {
19 // in an envelope stage?
21 if (st->stage == SpotTone_RISE) {
24 if (st->rise.have++ < st->rise.want) {
25 st->curr += st->rise.incr;
26 st->mul = st->scl * sin(st->curr * M_PI / 2.0);
28 // no, assert steady-state, force level
31 st->stage = SpotTone_STDY;
32 // won't come back into envelopes
33 // until FALL asserted from outside
36 } else if (st->stage == SpotTone_FALL) {
39 if (st->fall.have++ < st->fall.want) {
40 st->curr -= st->fall.incr;
41 st->mul = st->scl * sin(st->curr * M_PI / 2.0);
43 // no, assert trailing, force level
46 st->stage = SpotTone_HOLD;
47 // won't come back into envelopes hereafter
52 // (same base as osc.gen internal buf)
53 CXBdata(st->buf, i) = Cscl(CXBdata(st->buf, i), st->mul);
56 // indicate whether it's turned itself off
57 // sometime during this pass
59 return st->stage != SpotTone_HOLD;
62 //------------------------------------------------------------------------
63 // turn spotting on with current settings
66 SpotToneOn(SpotToneGen st) {
70 st->scl = pow(10.0, st->gain / 20.0);
71 st->curr = st->mul = 0.0;
73 // A/R times are in msec
75 st->rise.want = (int) (0.5 + st->sr * (st->rise.dur / 1e3));
77 if (st->rise.want <= 1)
80 st->rise.incr = 1.0 / (st->rise.want - 1);
82 st->fall.want = (int) (0.5 + st->sr * (st->fall.dur / 1e3));
84 if (st->fall.want <= 1)
87 st->fall.incr = 1.0 / (st->fall.want - 1);
91 OSCfreq(st->osc.gen) = 2.0 * M_PI * st->osc.freq / st->sr;
92 OSCphase(st->osc.gen) = 0.0;
94 st->stage = SpotTone_RISE;
97 //------------------------------------------------------------------------
101 SpotToneOff(SpotToneGen st) { st->stage = SpotTone_FALL; }
103 //------------------------------------------------------------------------
106 setSpotToneGenVals(SpotToneGen st,
118 newSpotToneGen(REAL gain, // dB
125 SpotToneGen st = (SpotToneGen) safealloc(1,
126 sizeof(SpotToneGenDesc),
129 setSpotToneGenVals(st, gain, freq, rise, fall);
133 st->osc.gen = newOSC(st->size,
140 // overload oscillator buf
141 st->buf = newCXB(st->size, OSCCbase(st->osc.gen), "SpotToneGen buf");
147 delSpotToneGen(SpotToneGen st) {
151 safefree((char *) st);