@jtarrio/signals 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +203 -0
- package/README.md +54 -0
- package/dist/demod/demod-am.d.ts +55 -0
- package/dist/demod/demod-am.d.ts.map +1 -0
- package/dist/demod/demod-am.js +118 -0
- package/dist/demod/demod-am.js.map +1 -0
- package/dist/demod/demod-cw.d.ts +49 -0
- package/dist/demod/demod-cw.d.ts.map +1 -0
- package/dist/demod/demod-cw.js +106 -0
- package/dist/demod/demod-cw.js.map +1 -0
- package/dist/demod/demod-nbfm.d.ts +55 -0
- package/dist/demod/demod-nbfm.d.ts.map +1 -0
- package/dist/demod/demod-nbfm.js +119 -0
- package/dist/demod/demod-nbfm.js.map +1 -0
- package/dist/demod/demod-ssb.d.ts +56 -0
- package/dist/demod/demod-ssb.d.ts.map +1 -0
- package/dist/demod/demod-ssb.js +118 -0
- package/dist/demod/demod-ssb.js.map +1 -0
- package/dist/demod/demod-wbfm.d.ts +114 -0
- package/dist/demod/demod-wbfm.d.ts.map +1 -0
- package/dist/demod/demod-wbfm.js +226 -0
- package/dist/demod/demod-wbfm.js.map +1 -0
- package/dist/demod/demodulator.d.ts +3 -0
- package/dist/demod/demodulator.d.ts.map +1 -0
- package/dist/demod/demodulator.js +28 -0
- package/dist/demod/demodulator.js.map +1 -0
- package/dist/demod/empty-demodulator.d.ts +78 -0
- package/dist/demod/empty-demodulator.d.ts.map +1 -0
- package/dist/demod/empty-demodulator.js +148 -0
- package/dist/demod/empty-demodulator.js.map +1 -0
- package/dist/demod/modes.d.ts +113 -0
- package/dist/demod/modes.d.ts.map +1 -0
- package/dist/demod/modes.js +107 -0
- package/dist/demod/modes.js.map +1 -0
- package/dist/demod/player.d.ts +19 -0
- package/dist/demod/player.d.ts.map +1 -0
- package/dist/demod/player.js +15 -0
- package/dist/demod/player.js.map +1 -0
- package/dist/demod/sample-counter.d.ts +22 -0
- package/dist/demod/sample-counter.d.ts.map +1 -0
- package/dist/demod/sample-counter.js +57 -0
- package/dist/demod/sample-counter.js.map +1 -0
- package/dist/demod/spectrum.d.ts +23 -0
- package/dist/demod/spectrum.d.ts.map +1 -0
- package/dist/demod/spectrum.js +76 -0
- package/dist/demod/spectrum.js.map +1 -0
- package/dist/dsp/buffers.d.ts +127 -0
- package/dist/dsp/buffers.d.ts.map +1 -0
- package/dist/dsp/buffers.js +171 -0
- package/dist/dsp/buffers.js.map +1 -0
- package/dist/dsp/coefficients.d.ts +23 -0
- package/dist/dsp/coefficients.d.ts.map +1 -0
- package/dist/dsp/coefficients.js +81 -0
- package/dist/dsp/coefficients.js.map +1 -0
- package/dist/dsp/converters.d.ts +15 -0
- package/dist/dsp/converters.d.ts.map +1 -0
- package/dist/dsp/converters.js +43 -0
- package/dist/dsp/converters.js.map +1 -0
- package/dist/dsp/demodulators.d.ts +68 -0
- package/dist/dsp/demodulators.d.ts.map +1 -0
- package/dist/dsp/demodulators.js +149 -0
- package/dist/dsp/demodulators.js.map +1 -0
- package/dist/dsp/fft.d.ts +54 -0
- package/dist/dsp/fft.d.ts.map +1 -0
- package/dist/dsp/fft.js +175 -0
- package/dist/dsp/fft.js.map +1 -0
- package/dist/dsp/filters.d.ts +197 -0
- package/dist/dsp/filters.d.ts.map +1 -0
- package/dist/dsp/filters.js +486 -0
- package/dist/dsp/filters.js.map +1 -0
- package/dist/dsp/math.d.ts +10 -0
- package/dist/dsp/math.d.ts.map +1 -0
- package/dist/dsp/math.js +55 -0
- package/dist/dsp/math.js.map +1 -0
- package/dist/dsp/power.d.ts +2 -0
- package/dist/dsp/power.d.ts.map +1 -0
- package/dist/dsp/power.js +23 -0
- package/dist/dsp/power.js.map +1 -0
- package/dist/dsp/resamplers.d.ts +45 -0
- package/dist/dsp/resamplers.d.ts.map +1 -0
- package/dist/dsp/resamplers.js +85 -0
- package/dist/dsp/resamplers.js.map +1 -0
- package/dist/errors.d.ts +15 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +33 -0
- package/dist/errors.js.map +1 -0
- package/dist/players/audioplayer.d.ts +25 -0
- package/dist/players/audioplayer.d.ts.map +1 -0
- package/dist/players/audioplayer.js +68 -0
- package/dist/players/audioplayer.js.map +1 -0
- package/dist/radio/msgqueue.d.ts +32 -0
- package/dist/radio/msgqueue.d.ts.map +1 -0
- package/dist/radio/msgqueue.js +62 -0
- package/dist/radio/msgqueue.js.map +1 -0
- package/dist/radio/radio.d.ts +107 -0
- package/dist/radio/radio.d.ts.map +1 -0
- package/dist/radio/radio.js +279 -0
- package/dist/radio/radio.js.map +1 -0
- package/dist/radio/sample_receiver.d.ts +17 -0
- package/dist/radio/sample_receiver.d.ts.map +1 -0
- package/dist/radio/sample_receiver.js +52 -0
- package/dist/radio/sample_receiver.js.map +1 -0
- package/dist/radio/signal_source.d.ts +53 -0
- package/dist/radio/signal_source.d.ts.map +1 -0
- package/dist/radio/signal_source.js +15 -0
- package/dist/radio/signal_source.js.map +1 -0
- package/dist/radio.d.ts +4 -0
- package/dist/radio.d.ts.map +1 -0
- package/dist/radio.js +4 -0
- package/dist/radio.js.map +1 -0
- package/dist/sources/generators.d.ts +41 -0
- package/dist/sources/generators.d.ts.map +1 -0
- package/dist/sources/generators.js +238 -0
- package/dist/sources/generators.js.map +1 -0
- package/dist/sources/provider.d.ts +7 -0
- package/dist/sources/provider.d.ts.map +1 -0
- package/dist/sources/provider.js +23 -0
- package/dist/sources/provider.js.map +1 -0
- package/dist/sources/push.d.ts +30 -0
- package/dist/sources/push.d.ts.map +1 -0
- package/dist/sources/push.js +106 -0
- package/dist/sources/push.js.map +1 -0
- package/dist/sources/read_ring.d.ts +14 -0
- package/dist/sources/read_ring.d.ts.map +1 -0
- package/dist/sources/read_ring.js +59 -0
- package/dist/sources/read_ring.js.map +1 -0
- package/dist/sources/realtime.d.ts +44 -0
- package/dist/sources/realtime.d.ts.map +1 -0
- package/dist/sources/realtime.js +136 -0
- package/dist/sources/realtime.js.map +1 -0
- package/package.json +25 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// Copyright 2024 Jacobo Tarrio Barreiro. All rights reserved.
|
|
2
|
+
// Copyright 2013 Google Inc. All rights reserved.
|
|
3
|
+
//
|
|
4
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
// you may not use this file except in compliance with the License.
|
|
6
|
+
// You may obtain a copy of the License at
|
|
7
|
+
//
|
|
8
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
//
|
|
10
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
// See the License for the specific language governing permissions and
|
|
14
|
+
// limitations under the License.
|
|
15
|
+
import { IqPool } from "./buffers.js";
|
|
16
|
+
/**
|
|
17
|
+
* Converts the given buffer of unsigned 8-bit samples into a pair of
|
|
18
|
+
* 32-bit floating-point sample streams.
|
|
19
|
+
*/
|
|
20
|
+
export class U8ToFloat32 {
|
|
21
|
+
/** @param length The expected length of each sample block. */
|
|
22
|
+
constructor(length) {
|
|
23
|
+
this.pool = new IqPool(4, length);
|
|
24
|
+
}
|
|
25
|
+
pool;
|
|
26
|
+
/**
|
|
27
|
+
* @param input A buffer containing the unsigned 8-bit samples.
|
|
28
|
+
* @returns An array that contains first the I stream and then the Q stream.
|
|
29
|
+
*/
|
|
30
|
+
convert(input) {
|
|
31
|
+
let u8 = new Uint8Array(input);
|
|
32
|
+
const len = u8.length / 2;
|
|
33
|
+
let out = this.pool.get(len);
|
|
34
|
+
const outI = out[0];
|
|
35
|
+
const outQ = out[1];
|
|
36
|
+
for (let i = 0; i < len; ++i) {
|
|
37
|
+
outI[i] = u8[2 * i] / 128 - 0.995;
|
|
38
|
+
outQ[i] = u8[2 * i + 1] / 128 - 0.995;
|
|
39
|
+
}
|
|
40
|
+
return out;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=converters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"converters.js","sourceRoot":"","sources":["../../src/dsp/converters.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,kDAAkD;AAClD,EAAE;AACF,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,iDAAiD;AACjD,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAEjC,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC;;;GAGG;AACH,MAAM,OAAO,WAAW;IACtB,8DAA8D;IAC9D,YAAY,MAAe;QACzB,IAAI,CAAC,IAAI,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IACpC,CAAC;IAEO,IAAI,CAAS;IAErB;;;OAGG;IACH,OAAO,CAAC,KAAkB;QACxB,IAAI,EAAE,GAAG,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC;QAC/B,MAAM,GAAG,GAAG,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;QAC1B,IAAI,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC7B,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;QACpB,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;QACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC;YAC7B,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,GAAG,KAAK,CAAC;YAClC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,GAAG,KAAK,CAAC;QACxC,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;CACF"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/** The sideband to demodulate. */
|
|
2
|
+
export declare enum Sideband {
|
|
3
|
+
Upper = 0,
|
|
4
|
+
Lower = 1
|
|
5
|
+
}
|
|
6
|
+
/** A class to demodulate a USB or LSB signal. */
|
|
7
|
+
export declare class SSBDemodulator {
|
|
8
|
+
/**
|
|
9
|
+
* @param sideband The sideband to demodulate.
|
|
10
|
+
* @param kernelLen The length of the Hilbert filter kernel to use.
|
|
11
|
+
*/
|
|
12
|
+
constructor(sideband: Sideband, kernelLen: number);
|
|
13
|
+
private filterDelay;
|
|
14
|
+
private filterHilbert;
|
|
15
|
+
private hilbertMul;
|
|
16
|
+
/** Switches the demodulator's sideband on the fly. */
|
|
17
|
+
setSideband(sideband: Sideband): void;
|
|
18
|
+
/** Demodulates the given I/Q samples into the real output. */
|
|
19
|
+
demodulate(I: Float32Array, Q: Float32Array, out: Float32Array): void;
|
|
20
|
+
}
|
|
21
|
+
/** A class to demodulate an AM signal. */
|
|
22
|
+
export declare class AMDemodulator {
|
|
23
|
+
/**
|
|
24
|
+
* @param sampleRate The signal's sample rate.
|
|
25
|
+
*/
|
|
26
|
+
constructor(sampleRate: number);
|
|
27
|
+
private alpha;
|
|
28
|
+
private carrierAmplitude;
|
|
29
|
+
/** Demodulates the given I/Q samples into the real output. */
|
|
30
|
+
demodulate(I: Float32Array, Q: Float32Array, out: Float32Array): void;
|
|
31
|
+
}
|
|
32
|
+
/** A class to demodulate an FM signal. */
|
|
33
|
+
export declare class FMDemodulator {
|
|
34
|
+
/**
|
|
35
|
+
* @param maxDeviation The maximum deviation for the signal, as a fraction of the sample rate.
|
|
36
|
+
*/
|
|
37
|
+
constructor(maxDeviation: number);
|
|
38
|
+
private mul;
|
|
39
|
+
private lI;
|
|
40
|
+
private lQ;
|
|
41
|
+
/** Changes the maximum deviation. */
|
|
42
|
+
setMaxDeviation(maxDeviation: number): void;
|
|
43
|
+
/** Demodulates the given I/Q samples into the real output. */
|
|
44
|
+
demodulate(I: Float32Array, Q: Float32Array, out: Float32Array): void;
|
|
45
|
+
}
|
|
46
|
+
/** A class to demodulate the stereo signal in a demodulated FM signal. */
|
|
47
|
+
export declare class StereoSeparator {
|
|
48
|
+
/**
|
|
49
|
+
* @param sampleRate The sample rate for the input signal.
|
|
50
|
+
* @param pilotFreq The frequency of the pilot tone.
|
|
51
|
+
*/
|
|
52
|
+
constructor(sampleRate: number, pilotFreq: number);
|
|
53
|
+
private pool;
|
|
54
|
+
private pll;
|
|
55
|
+
/**
|
|
56
|
+
* Locks on to the pilot tone and uses it to demodulate the stereo audio.
|
|
57
|
+
* @param samples The original audio stream.
|
|
58
|
+
* @returns An object with a key 'found' that tells whether a
|
|
59
|
+
* consistent stereo pilot tone was detected and a key 'diff'
|
|
60
|
+
* that contains the original stream demodulated with the
|
|
61
|
+
* reconstructed stereo carrier.
|
|
62
|
+
*/
|
|
63
|
+
separate(samples: Float32Array): {
|
|
64
|
+
found: boolean;
|
|
65
|
+
diff: Float32Array;
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=demodulators.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"demodulators.d.ts","sourceRoot":"","sources":["../../src/dsp/demodulators.ts"],"names":[],"mappings":"AAoBA,kCAAkC;AAClC,oBAAY,QAAQ;IAClB,KAAK,IAAA;IACL,KAAK,IAAA;CACN;AAED,iDAAiD;AACjD,qBAAa,cAAc;IACzB;;;OAGG;gBACS,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM;IAOjD,OAAO,CAAC,WAAW,CAAY;IAC/B,OAAO,CAAC,aAAa,CAAY;IACjC,OAAO,CAAC,UAAU,CAAS;IAE3B,sDAAsD;IACtD,WAAW,CAAC,QAAQ,EAAE,QAAQ;IAI9B,8DAA8D;IAC9D,UAAU,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,YAAY,EAAE,GAAG,EAAE,YAAY;CAU/D;AAED,0CAA0C;AAC1C,qBAAa,aAAa;IACxB;;OAEG;gBACS,UAAU,EAAE,MAAM;IAK9B,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,gBAAgB,CAAS;IAEjC,8DAA8D;IAC9D,UAAU,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,YAAY,EAAE,GAAG,EAAE,YAAY;CAa/D;AAED,0CAA0C;AAC1C,qBAAa,aAAa;IACxB;;OAEG;gBACS,YAAY,EAAE,MAAM;IAMhC,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,EAAE,CAAS;IACnB,OAAO,CAAC,EAAE,CAAS;IAEnB,qCAAqC;IACrC,eAAe,CAAC,YAAY,EAAE,MAAM;IAIpC,8DAA8D;IAC9D,UAAU,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,YAAY,EAAE,GAAG,EAAE,YAAY;CAe/D;AAED,0EAA0E;AAC1E,qBAAa,eAAe;IAC1B;;;OAGG;gBACS,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAKjD,OAAO,CAAC,IAAI,CAAc;IAC1B,OAAO,CAAC,GAAG,CAAM;IAEjB;;;;;;;OAOG;IACH,QAAQ,CAAC,OAAO,EAAE,YAAY,GAAG;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,YAAY,CAAA;KAAE;CAaxE"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
// Copyright 2024 Jacobo Tarrio Barreiro. All rights reserved.
|
|
2
|
+
// Copyright 2013 Google Inc. All rights reserved.
|
|
3
|
+
//
|
|
4
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
// you may not use this file except in compliance with the License.
|
|
6
|
+
// You may obtain a copy of the License at
|
|
7
|
+
//
|
|
8
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
//
|
|
10
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
// See the License for the specific language governing permissions and
|
|
14
|
+
// limitations under the License.
|
|
15
|
+
import { makeHilbertKernel } from "./coefficients.js";
|
|
16
|
+
import { decay, FIRFilter, PLL } from "./filters.js";
|
|
17
|
+
import { Float32Pool } from "./buffers.js";
|
|
18
|
+
import { atan2 } from "./math.js";
|
|
19
|
+
/** The sideband to demodulate. */
|
|
20
|
+
export var Sideband;
|
|
21
|
+
(function (Sideband) {
|
|
22
|
+
Sideband[Sideband["Upper"] = 0] = "Upper";
|
|
23
|
+
Sideband[Sideband["Lower"] = 1] = "Lower";
|
|
24
|
+
})(Sideband || (Sideband = {}));
|
|
25
|
+
/** A class to demodulate a USB or LSB signal. */
|
|
26
|
+
export class SSBDemodulator {
|
|
27
|
+
/**
|
|
28
|
+
* @param sideband The sideband to demodulate.
|
|
29
|
+
* @param kernelLen The length of the Hilbert filter kernel to use.
|
|
30
|
+
*/
|
|
31
|
+
constructor(sideband, kernelLen) {
|
|
32
|
+
let hilbert = makeHilbertKernel(kernelLen);
|
|
33
|
+
this.filterDelay = new FIRFilter(hilbert);
|
|
34
|
+
this.filterHilbert = new FIRFilter(hilbert);
|
|
35
|
+
this.hilbertMul = sideband == Sideband.Upper ? -1 : 1;
|
|
36
|
+
}
|
|
37
|
+
filterDelay;
|
|
38
|
+
filterHilbert;
|
|
39
|
+
hilbertMul;
|
|
40
|
+
/** Switches the demodulator's sideband on the fly. */
|
|
41
|
+
setSideband(sideband) {
|
|
42
|
+
this.hilbertMul = sideband == Sideband.Upper ? -1 : 1;
|
|
43
|
+
}
|
|
44
|
+
/** Demodulates the given I/Q samples into the real output. */
|
|
45
|
+
demodulate(I, Q, out) {
|
|
46
|
+
this.filterDelay.loadSamples(I);
|
|
47
|
+
this.filterHilbert.loadSamples(Q);
|
|
48
|
+
for (let i = 0; i < out.length; ++i) {
|
|
49
|
+
out[i] =
|
|
50
|
+
(this.filterDelay.getDelayed(i) +
|
|
51
|
+
this.filterHilbert.get(i) * this.hilbertMul) /
|
|
52
|
+
2;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/** A class to demodulate an AM signal. */
|
|
57
|
+
export class AMDemodulator {
|
|
58
|
+
/**
|
|
59
|
+
* @param sampleRate The signal's sample rate.
|
|
60
|
+
*/
|
|
61
|
+
constructor(sampleRate) {
|
|
62
|
+
this.alpha = decay(sampleRate, 0.5);
|
|
63
|
+
this.carrierAmplitude = 0;
|
|
64
|
+
}
|
|
65
|
+
alpha;
|
|
66
|
+
carrierAmplitude;
|
|
67
|
+
/** Demodulates the given I/Q samples into the real output. */
|
|
68
|
+
demodulate(I, Q, out) {
|
|
69
|
+
const alpha = this.alpha;
|
|
70
|
+
let carrierAmplitude = this.carrierAmplitude;
|
|
71
|
+
for (let i = 0; i < out.length; ++i) {
|
|
72
|
+
const vI = I[i];
|
|
73
|
+
const vQ = Q[i];
|
|
74
|
+
const power = vI * vI + vQ * vQ;
|
|
75
|
+
const amplitude = Math.sqrt(power);
|
|
76
|
+
carrierAmplitude += alpha * (amplitude - carrierAmplitude);
|
|
77
|
+
out[i] = carrierAmplitude == 0 ? 0 : amplitude / carrierAmplitude - 1;
|
|
78
|
+
}
|
|
79
|
+
this.carrierAmplitude = carrierAmplitude;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/** A class to demodulate an FM signal. */
|
|
83
|
+
export class FMDemodulator {
|
|
84
|
+
/**
|
|
85
|
+
* @param maxDeviation The maximum deviation for the signal, as a fraction of the sample rate.
|
|
86
|
+
*/
|
|
87
|
+
constructor(maxDeviation) {
|
|
88
|
+
this.mul = 1 / (2 * Math.PI * maxDeviation);
|
|
89
|
+
this.lI = 0;
|
|
90
|
+
this.lQ = 0;
|
|
91
|
+
}
|
|
92
|
+
mul;
|
|
93
|
+
lI;
|
|
94
|
+
lQ;
|
|
95
|
+
/** Changes the maximum deviation. */
|
|
96
|
+
setMaxDeviation(maxDeviation) {
|
|
97
|
+
this.mul = 1 / (2 * Math.PI * maxDeviation);
|
|
98
|
+
}
|
|
99
|
+
/** Demodulates the given I/Q samples into the real output. */
|
|
100
|
+
demodulate(I, Q, out) {
|
|
101
|
+
const mul = this.mul;
|
|
102
|
+
let lI = this.lI;
|
|
103
|
+
let lQ = this.lQ;
|
|
104
|
+
for (let i = 0; i < I.length; ++i) {
|
|
105
|
+
// s = s * conj(l)
|
|
106
|
+
let real = lI * I[i] + lQ * Q[i];
|
|
107
|
+
let imag = lI * Q[i] - I[i] * lQ;
|
|
108
|
+
lI = I[i];
|
|
109
|
+
lQ = Q[i];
|
|
110
|
+
out[i] = atan2(imag, real) * mul;
|
|
111
|
+
}
|
|
112
|
+
this.lI = lI;
|
|
113
|
+
this.lQ = lQ;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/** A class to demodulate the stereo signal in a demodulated FM signal. */
|
|
117
|
+
export class StereoSeparator {
|
|
118
|
+
/**
|
|
119
|
+
* @param sampleRate The sample rate for the input signal.
|
|
120
|
+
* @param pilotFreq The frequency of the pilot tone.
|
|
121
|
+
*/
|
|
122
|
+
constructor(sampleRate, pilotFreq) {
|
|
123
|
+
this.pool = new Float32Pool(4);
|
|
124
|
+
this.pll = new PLL(sampleRate, pilotFreq, 10);
|
|
125
|
+
}
|
|
126
|
+
pool;
|
|
127
|
+
pll;
|
|
128
|
+
/**
|
|
129
|
+
* Locks on to the pilot tone and uses it to demodulate the stereo audio.
|
|
130
|
+
* @param samples The original audio stream.
|
|
131
|
+
* @returns An object with a key 'found' that tells whether a
|
|
132
|
+
* consistent stereo pilot tone was detected and a key 'diff'
|
|
133
|
+
* that contains the original stream demodulated with the
|
|
134
|
+
* reconstructed stereo carrier.
|
|
135
|
+
*/
|
|
136
|
+
separate(samples) {
|
|
137
|
+
let out = this.pool.get(samples.length);
|
|
138
|
+
for (let i = 0; i < samples.length; ++i) {
|
|
139
|
+
this.pll.add(samples[i]);
|
|
140
|
+
// Multiply by 4 instead of 2 so 'out' has the same level as the input samples.
|
|
141
|
+
out[i] = samples[i] * this.pll.sin * this.pll.cos * 4;
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
found: this.pll.locked,
|
|
145
|
+
diff: out,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=demodulators.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"demodulators.js","sourceRoot":"","sources":["../../src/dsp/demodulators.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Float32RingBuffer } from "./buffers.js";
|
|
2
|
+
/** Fast Fourier Transform implementation. */
|
|
3
|
+
/**
|
|
4
|
+
* Returns the length of the FFT for a given array length.
|
|
5
|
+
*
|
|
6
|
+
* This FFT implementation only works in power-of-2 lengths,
|
|
7
|
+
* so this function returns the next available length.
|
|
8
|
+
*/
|
|
9
|
+
export declare function actualLength(minimumLength: number): number;
|
|
10
|
+
/**
|
|
11
|
+
* The output of the transform functions.
|
|
12
|
+
*
|
|
13
|
+
* The first array contains the real parts, and the second array contains the imaginary parts.
|
|
14
|
+
*/
|
|
15
|
+
export type FFTOutput = [Float32Array, Float32Array];
|
|
16
|
+
/** Fast Fourier Transform and reverse transform with a given length. */
|
|
17
|
+
export declare class FFT {
|
|
18
|
+
length: number;
|
|
19
|
+
/**
|
|
20
|
+
* Returns an FFT instance that fits the given length.
|
|
21
|
+
*
|
|
22
|
+
* The actual length may be greater than the given length if it
|
|
23
|
+
* is not a power of 2.
|
|
24
|
+
*/
|
|
25
|
+
static ofLength(minimumLength: number): FFT;
|
|
26
|
+
private constructor();
|
|
27
|
+
private revIndex;
|
|
28
|
+
private fwd;
|
|
29
|
+
private bwd;
|
|
30
|
+
private copy;
|
|
31
|
+
private out;
|
|
32
|
+
private window;
|
|
33
|
+
/** Sets the window function for this FFT. */
|
|
34
|
+
setWindow(window: Float32Array): void;
|
|
35
|
+
/**
|
|
36
|
+
* Transforms the given time-domain input.
|
|
37
|
+
* @param real An array of real parts.
|
|
38
|
+
* @param imag An array of imaginary parts.
|
|
39
|
+
* @return The output of the transform.
|
|
40
|
+
*/
|
|
41
|
+
transform(real: Float32Array, imag: Float32Array): FFTOutput;
|
|
42
|
+
transform(real: number[], imag: number[]): FFTOutput;
|
|
43
|
+
transformCircularBuffers(real: Float32RingBuffer, imag: Float32RingBuffer): FFTOutput;
|
|
44
|
+
/**
|
|
45
|
+
* Does a reverse transform of the given frequency-domain input.
|
|
46
|
+
* The input and output arrays must be the same length as the FFT.
|
|
47
|
+
* @param real An array of real parts.
|
|
48
|
+
* @param imag An array of imaginary parts.
|
|
49
|
+
* @return The output of the reverse transform.
|
|
50
|
+
*/
|
|
51
|
+
reverse(real: Float32Array, imag: Float32Array): FFTOutput;
|
|
52
|
+
reverse(real: number[], imag: number[]): FFTOutput;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=fft.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fft.d.ts","sourceRoot":"","sources":["../../src/dsp/fft.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,iBAAiB,EAAU,MAAM,cAAc,CAAC;AAEzD,6CAA6C;AAE7C;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAM1D;AAED;;;;GAIG;AACH,MAAM,MAAM,SAAS,GAAG,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;AAErD,wEAAwE;AACxE,qBAAa,GAAG;IAWa,MAAM,EAAE,MAAM;IAVzC;;;;;OAKG;IACH,MAAM,CAAC,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,GAAG;IAI3C,OAAO;IAWP,OAAO,CAAC,QAAQ,CAAa;IAC7B,OAAO,CAAC,GAAG,CAAiB;IAC5B,OAAO,CAAC,GAAG,CAAiB;IAC5B,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,MAAM,CAAe;IAE7B,6CAA6C;IAC7C,SAAS,CAAC,MAAM,EAAE,YAAY;IAI9B;;;;;OAKG;IACH,SAAS,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,YAAY,GAAG,SAAS;IAC5D,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,SAAS;IAepD,wBAAwB,CACtB,IAAI,EAAE,iBAAiB,EACvB,IAAI,EAAE,iBAAiB,GACtB,SAAS;IAQZ;;;;;;OAMG;IACH,OAAO,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,YAAY,GAAG,SAAS;IAC1D,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,SAAS;CAcnD"}
|
package/dist/dsp/fft.js
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
// Copyright 2024 Jacobo Tarrio Barreiro. All rights reserved.
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
import { IqPool } from "./buffers.js";
|
|
15
|
+
/** Fast Fourier Transform implementation. */
|
|
16
|
+
/**
|
|
17
|
+
* Returns the length of the FFT for a given array length.
|
|
18
|
+
*
|
|
19
|
+
* This FFT implementation only works in power-of-2 lengths,
|
|
20
|
+
* so this function returns the next available length.
|
|
21
|
+
*/
|
|
22
|
+
export function actualLength(minimumLength) {
|
|
23
|
+
if (minimumLength < 2)
|
|
24
|
+
return 0;
|
|
25
|
+
if (((minimumLength - 1) & minimumLength) == 0)
|
|
26
|
+
return minimumLength;
|
|
27
|
+
let realLength = 1;
|
|
28
|
+
while (realLength < minimumLength)
|
|
29
|
+
realLength <<= 1;
|
|
30
|
+
return realLength;
|
|
31
|
+
}
|
|
32
|
+
/** Fast Fourier Transform and reverse transform with a given length. */
|
|
33
|
+
export class FFT {
|
|
34
|
+
length;
|
|
35
|
+
/**
|
|
36
|
+
* Returns an FFT instance that fits the given length.
|
|
37
|
+
*
|
|
38
|
+
* The actual length may be greater than the given length if it
|
|
39
|
+
* is not a power of 2.
|
|
40
|
+
*/
|
|
41
|
+
static ofLength(minimumLength) {
|
|
42
|
+
return new FFT(actualLength(minimumLength));
|
|
43
|
+
}
|
|
44
|
+
constructor(length) {
|
|
45
|
+
this.length = length;
|
|
46
|
+
this.revIndex = reversedBitIndices(length);
|
|
47
|
+
let [fwd, bwd] = makeFftCoefficients(length);
|
|
48
|
+
this.fwd = fwd;
|
|
49
|
+
this.bwd = bwd;
|
|
50
|
+
this.copy = new IqPool(2, length);
|
|
51
|
+
this.out = new IqPool(2, length);
|
|
52
|
+
this.window = new Float32Array(length);
|
|
53
|
+
this.window.fill(1);
|
|
54
|
+
}
|
|
55
|
+
revIndex;
|
|
56
|
+
fwd;
|
|
57
|
+
bwd;
|
|
58
|
+
copy;
|
|
59
|
+
out;
|
|
60
|
+
window;
|
|
61
|
+
/** Sets the window function for this FFT. */
|
|
62
|
+
setWindow(window) {
|
|
63
|
+
this.window.set(window);
|
|
64
|
+
}
|
|
65
|
+
transform(real, imag) {
|
|
66
|
+
const length = this.length;
|
|
67
|
+
let [outReal, outImag] = this.out.get(length);
|
|
68
|
+
outReal.fill(0);
|
|
69
|
+
outImag.fill(0);
|
|
70
|
+
for (let i = 0; i < length && i < real.length && i < imag.length; ++i) {
|
|
71
|
+
const ri = this.revIndex[i];
|
|
72
|
+
outReal[ri] = (this.window[i] * real[i]) / length;
|
|
73
|
+
outImag[ri] = (this.window[i] * imag[i]) / length;
|
|
74
|
+
}
|
|
75
|
+
doFastTransform(this.length, this.fwd, outReal, outImag);
|
|
76
|
+
return [outReal, outImag];
|
|
77
|
+
}
|
|
78
|
+
transformCircularBuffers(real, imag) {
|
|
79
|
+
const length = this.length;
|
|
80
|
+
let [copyReal, copyImag] = this.copy.get(length);
|
|
81
|
+
real.copyTo(copyReal);
|
|
82
|
+
imag.copyTo(copyImag);
|
|
83
|
+
return this.transform(copyReal, copyImag);
|
|
84
|
+
}
|
|
85
|
+
reverse(real, imag) {
|
|
86
|
+
const length = this.length;
|
|
87
|
+
let [outReal, outImag] = this.out.get(length);
|
|
88
|
+
outReal.fill(0);
|
|
89
|
+
outImag.fill(0);
|
|
90
|
+
for (let i = 0; i < length && i < real.length && i < imag.length; ++i) {
|
|
91
|
+
const ri = this.revIndex[i];
|
|
92
|
+
outReal[ri] = this.window[i] * real[i];
|
|
93
|
+
outImag[ri] = this.window[i] * imag[i];
|
|
94
|
+
}
|
|
95
|
+
doFastTransform(this.length, this.bwd, outReal, outImag);
|
|
96
|
+
return [outReal, outImag];
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/** Performs a fast direct or reverse transform in place. */
|
|
100
|
+
function doFastTransform(length, coefs, real, imag) {
|
|
101
|
+
for (let dftSize = 2, coeffBin = 0; dftSize <= length; dftSize *= 2, ++coeffBin) {
|
|
102
|
+
const binCoefficients = coefs[coeffBin];
|
|
103
|
+
const halfDftSize = dftSize / 2;
|
|
104
|
+
for (let dftStart = 0; dftStart < length; dftStart += dftSize) {
|
|
105
|
+
for (let i = 0; i < halfDftSize; ++i) {
|
|
106
|
+
const near = dftStart + i;
|
|
107
|
+
const far = near + halfDftSize;
|
|
108
|
+
const evenReal = real[near];
|
|
109
|
+
const evenImag = imag[near];
|
|
110
|
+
const cr = binCoefficients.real[i];
|
|
111
|
+
const ci = binCoefficients.imag[i];
|
|
112
|
+
const or = real[far];
|
|
113
|
+
const oi = imag[far];
|
|
114
|
+
const oddReal = cr * or - ci * oi;
|
|
115
|
+
const oddImag = cr * oi + ci * or;
|
|
116
|
+
real[near] = evenReal + oddReal;
|
|
117
|
+
imag[near] = evenImag + oddImag;
|
|
118
|
+
real[far] = evenReal - oddReal;
|
|
119
|
+
imag[far] = evenImag - oddImag;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/** Builds a triangle of direct and reverse FFT coefficients for the given length. */
|
|
125
|
+
function makeFftCoefficients(length) {
|
|
126
|
+
let numBits = getNumBits(length);
|
|
127
|
+
let fwd = [];
|
|
128
|
+
let bwd = [];
|
|
129
|
+
for (let bin = 0, halfSize = 1; bin < numBits; ++bin, halfSize *= 2) {
|
|
130
|
+
fwd.push({
|
|
131
|
+
real: new Float32Array(halfSize),
|
|
132
|
+
imag: new Float32Array(halfSize),
|
|
133
|
+
});
|
|
134
|
+
bwd.push({
|
|
135
|
+
real: new Float32Array(halfSize),
|
|
136
|
+
imag: new Float32Array(halfSize),
|
|
137
|
+
});
|
|
138
|
+
for (let i = 0; i < halfSize; ++i) {
|
|
139
|
+
const fwdAngle = (-1 * Math.PI * i) / halfSize;
|
|
140
|
+
fwd[bin].real[i] = Math.cos(fwdAngle);
|
|
141
|
+
fwd[bin].imag[i] = Math.sin(fwdAngle);
|
|
142
|
+
const bwdAngle = (Math.PI * i) / halfSize;
|
|
143
|
+
bwd[bin].real[i] = Math.cos(bwdAngle);
|
|
144
|
+
bwd[bin].imag[i] = Math.sin(bwdAngle);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return [fwd, bwd];
|
|
148
|
+
}
|
|
149
|
+
/** Builds an array of numbers with their bits reversed. */
|
|
150
|
+
function reversedBitIndices(length) {
|
|
151
|
+
const numBits = getNumBits(length);
|
|
152
|
+
let output = new Int32Array(length);
|
|
153
|
+
for (let i = 0; i < length; ++i) {
|
|
154
|
+
output[i] = reverseBits(i, numBits);
|
|
155
|
+
}
|
|
156
|
+
return output;
|
|
157
|
+
}
|
|
158
|
+
/** Returns how many bits we need to fit 'length' distinct values. */
|
|
159
|
+
function getNumBits(length) {
|
|
160
|
+
let numBits = 0;
|
|
161
|
+
for (let shifted = length - 1; shifted > 0; shifted >>= 1)
|
|
162
|
+
++numBits;
|
|
163
|
+
return numBits;
|
|
164
|
+
}
|
|
165
|
+
/** Reverses the bits in a number. */
|
|
166
|
+
function reverseBits(num, bits) {
|
|
167
|
+
let output = 0;
|
|
168
|
+
for (let b = 0; b < bits; ++b) {
|
|
169
|
+
output <<= 1;
|
|
170
|
+
output |= num & 1;
|
|
171
|
+
num >>= 1;
|
|
172
|
+
}
|
|
173
|
+
return output;
|
|
174
|
+
}
|
|
175
|
+
//# sourceMappingURL=fft.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fft.js","sourceRoot":"","sources":["../../src/dsp/fft.ts"],"names":[],"mappings":"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"}
|