@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,107 @@
|
|
|
1
|
+
import { SampleReceiver } from "./sample_receiver.js";
|
|
2
|
+
import { SampleBlock, SignalSourceProvider } from "./signal_source.js";
|
|
3
|
+
/** The information in a 'radio' event. */
|
|
4
|
+
export type RadioEventType = {
|
|
5
|
+
type: "started";
|
|
6
|
+
} | {
|
|
7
|
+
type: "stopped";
|
|
8
|
+
} | {
|
|
9
|
+
type: "error";
|
|
10
|
+
exception: any;
|
|
11
|
+
};
|
|
12
|
+
/** The type of 'radio' events. */
|
|
13
|
+
export declare class RadioEvent extends CustomEvent<RadioEventType> {
|
|
14
|
+
constructor(e: RadioEventType);
|
|
15
|
+
}
|
|
16
|
+
/** Options for the Radio class. */
|
|
17
|
+
export type RadioOptions = {
|
|
18
|
+
/**
|
|
19
|
+
* The number of buffers to process per second.
|
|
20
|
+
*
|
|
21
|
+
* This number controls your processing latency: more buffers per second
|
|
22
|
+
* implies smaller buffers, thus smaller latency. It also increases your
|
|
23
|
+
* CPU requirements, though.
|
|
24
|
+
*
|
|
25
|
+
* The actual number of buffers per second may be slightly different to
|
|
26
|
+
* account for hardware requirements.
|
|
27
|
+
*/
|
|
28
|
+
buffersPerSecond?: number;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Provides controls to play, stop, and tune the radio.
|
|
32
|
+
*
|
|
33
|
+
* The command functions (start, stop, setParameter, etc) return promises that resolve when the
|
|
34
|
+
* corresponding command has been processed. Commands are processed one at a time and in the same order
|
|
35
|
+
* in which they were sent.
|
|
36
|
+
*
|
|
37
|
+
* There is a ready() function that returns a promise that resolves when all the commands sent
|
|
38
|
+
* before the ready() function have been processed. It is useful when a subclass of Radio() sends commands
|
|
39
|
+
* in the constructor, because then the ready() function will only resolve when all those commands
|
|
40
|
+
* have been processed.
|
|
41
|
+
*/
|
|
42
|
+
export declare class Radio<ParameterKey extends string = string> extends EventTarget {
|
|
43
|
+
private sourceProvider;
|
|
44
|
+
private sampleReceiver;
|
|
45
|
+
private options?;
|
|
46
|
+
/** @param sampleReceiver the object that will receive the radio samples. */
|
|
47
|
+
constructor(sourceProvider: SignalSourceProvider, sampleReceiver: SampleReceiver, options?: RadioOptions | undefined);
|
|
48
|
+
/** Current sample rate. */
|
|
49
|
+
private sampleRate;
|
|
50
|
+
/** Current state. */
|
|
51
|
+
private state;
|
|
52
|
+
/** Currently tuned frequency. */
|
|
53
|
+
private frequency;
|
|
54
|
+
/** Channel to send messages to the state machine. */
|
|
55
|
+
private channel;
|
|
56
|
+
/** Current values of the properties. */
|
|
57
|
+
private parameterValues;
|
|
58
|
+
/**
|
|
59
|
+
* Starts playing the radio.
|
|
60
|
+
*
|
|
61
|
+
* @returns a promise that resolves after the command has been processed by the radio.
|
|
62
|
+
*/
|
|
63
|
+
start(): Promise<void>;
|
|
64
|
+
/**
|
|
65
|
+
* Stops playing the radio.
|
|
66
|
+
*
|
|
67
|
+
* @returns a promise that resolves after the command has been processed by the radio.
|
|
68
|
+
*/
|
|
69
|
+
stop(): Promise<void>;
|
|
70
|
+
/** Returns whether the radio is playing (or scanning). */
|
|
71
|
+
isPlaying(): boolean;
|
|
72
|
+
/**
|
|
73
|
+
* Tunes the radio to this frequency.
|
|
74
|
+
*
|
|
75
|
+
* @returns a promise that resolves after the command has been processed by the radio.
|
|
76
|
+
*/
|
|
77
|
+
setFrequency(freq: number): Promise<void>;
|
|
78
|
+
/** Returns the tuned frequency. */
|
|
79
|
+
getFrequency(): number;
|
|
80
|
+
/**
|
|
81
|
+
* Changes the sample rate. This change only takes effect when the radio is started.
|
|
82
|
+
*
|
|
83
|
+
* @returns a promise that resolves after the command has been processed by the radio.
|
|
84
|
+
*/
|
|
85
|
+
setSampleRate(sampleRate: number): Promise<number>;
|
|
86
|
+
/** Returns the current sample rate. */
|
|
87
|
+
getSampleRate(): number;
|
|
88
|
+
/**
|
|
89
|
+
* Sets the value of a parameter.
|
|
90
|
+
*
|
|
91
|
+
* @returns a promise that resolves after the command has been processed by the radio.
|
|
92
|
+
*/
|
|
93
|
+
setParameter<V>(parameter: ParameterKey, value: V): Promise<void>;
|
|
94
|
+
/** Returns the value of a parameter. */
|
|
95
|
+
getParameter(parameter: ParameterKey): any;
|
|
96
|
+
/**
|
|
97
|
+
* Returns a promise that resolves when the radio has processed all commands send to it up to this point.
|
|
98
|
+
*/
|
|
99
|
+
ready(): Promise<void>;
|
|
100
|
+
/** Override this function to do something when a sample block is received. */
|
|
101
|
+
onReceiveSamples(block: SampleBlock): void;
|
|
102
|
+
/** Runs the state machine. */
|
|
103
|
+
private runLoop;
|
|
104
|
+
addEventListener(type: "radio", callback: (e: RadioEvent) => void | null, options?: boolean | AddEventListenerOptions | undefined): void;
|
|
105
|
+
addEventListener(type: string, callback: EventListenerOrEventListenerObject | null, options?: boolean | AddEventListenerOptions | undefined): void;
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=radio.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"radio.d.ts","sourceRoot":"","sources":["../../src/radio/radio.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EACL,WAAW,EAEX,oBAAoB,EACrB,MAAM,oBAAoB,CAAC;AAU5B,0CAA0C;AAC1C,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,GAAG,CAAA;CAAE,CAAC;AAEtC,kCAAkC;AAClC,qBAAa,UAAW,SAAQ,WAAW,CAAC,cAAc,CAAC;gBAC7C,CAAC,EAAE,cAAc;CAG9B;AAQD,mCAAmC;AACnC,MAAM,MAAM,YAAY,GAAG;IACzB;;;;;;;;;OASG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,qBAAa,KAAK,CAAC,YAAY,SAAS,MAAM,GAAG,MAAM,CAAE,SAAQ,WAAW;IAGxE,OAAO,CAAC,cAAc;IACtB,OAAO,CAAC,cAAc;IACtB,OAAO,CAAC,OAAO,CAAC;IAJlB,4EAA4E;gBAElE,cAAc,EAAE,oBAAoB,EACpC,cAAc,EAAE,cAAc,EAC9B,OAAO,CAAC,EAAE,YAAY,YAAA;IAWhC,2BAA2B;IAC3B,OAAO,CAAC,UAAU,CAAS;IAC3B,qBAAqB;IACrB,OAAO,CAAC,KAAK,CAAQ;IACrB,iCAAiC;IACjC,OAAO,CAAC,SAAS,CAAS;IAC1B,qDAAqD;IACrD,OAAO,CAAC,OAAO,CAAiC;IAChD,wCAAwC;IACxC,OAAO,CAAC,eAAe,CAAyB;IAEhD;;;;OAIG;IACG,KAAK;IAIX;;;;OAIG;IACG,IAAI;IAIV,0DAA0D;IAC1D,SAAS;IAIT;;;;OAIG;IACG,YAAY,CAAC,IAAI,EAAE,MAAM;IAI/B,mCAAmC;IACnC,YAAY,IAAI,MAAM;IAItB;;;;OAIG;IACG,aAAa,CAAC,UAAU,EAAE,MAAM;IAItC,uCAAuC;IACvC,aAAa,IAAI,MAAM;IAIvB;;;;OAIG;IACG,YAAY,CAAC,CAAC,EAAE,SAAS,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;IAQvD,wCAAwC;IACxC,YAAY,CAAC,SAAS,EAAE,YAAY,GAAG,GAAG;IAI1C;;OAEG;IACG,KAAK;IAIX,8EAA8E;IAC9E,gBAAgB,CAAC,KAAK,EAAE,WAAW;IAEnC,8BAA8B;YAChB,OAAO;IAgErB,gBAAgB,CACd,IAAI,EAAE,OAAO,EACb,QAAQ,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,GAAG,IAAI,EACxC,OAAO,CAAC,EAAE,OAAO,GAAG,uBAAuB,GAAG,SAAS,GACtD,IAAI;IACP,gBAAgB,CACd,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,kCAAkC,GAAG,IAAI,EACnD,OAAO,CAAC,EAAE,OAAO,GAAG,uBAAuB,GAAG,SAAS,GACtD,IAAI;CAYR"}
|
|
@@ -0,0 +1,279 @@
|
|
|
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
|
+
/**
|
|
15
|
+
* State machine to orchestrate the sample source, the demodulation process,
|
|
16
|
+
* and the sample receiver, as a "radio" that can be started and stopped.
|
|
17
|
+
*/
|
|
18
|
+
import { RadioError, RadioErrorType } from "../errors.js";
|
|
19
|
+
import { Channel } from "./msgqueue.js";
|
|
20
|
+
/** The type of 'radio' events. */
|
|
21
|
+
export class RadioEvent extends CustomEvent {
|
|
22
|
+
constructor(e) {
|
|
23
|
+
super("radio", { detail: e });
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/** Current state. */
|
|
27
|
+
var State;
|
|
28
|
+
(function (State) {
|
|
29
|
+
State[State["OFF"] = 0] = "OFF";
|
|
30
|
+
State[State["PLAYING"] = 1] = "PLAYING";
|
|
31
|
+
})(State || (State = {}));
|
|
32
|
+
/**
|
|
33
|
+
* Provides controls to play, stop, and tune the radio.
|
|
34
|
+
*
|
|
35
|
+
* The command functions (start, stop, setParameter, etc) return promises that resolve when the
|
|
36
|
+
* corresponding command has been processed. Commands are processed one at a time and in the same order
|
|
37
|
+
* in which they were sent.
|
|
38
|
+
*
|
|
39
|
+
* There is a ready() function that returns a promise that resolves when all the commands sent
|
|
40
|
+
* before the ready() function have been processed. It is useful when a subclass of Radio() sends commands
|
|
41
|
+
* in the constructor, because then the ready() function will only resolve when all those commands
|
|
42
|
+
* have been processed.
|
|
43
|
+
*/
|
|
44
|
+
export class Radio extends EventTarget {
|
|
45
|
+
sourceProvider;
|
|
46
|
+
sampleReceiver;
|
|
47
|
+
options;
|
|
48
|
+
/** @param sampleReceiver the object that will receive the radio samples. */
|
|
49
|
+
constructor(sourceProvider, sampleReceiver, options) {
|
|
50
|
+
super();
|
|
51
|
+
this.sourceProvider = sourceProvider;
|
|
52
|
+
this.sampleReceiver = sampleReceiver;
|
|
53
|
+
this.options = options;
|
|
54
|
+
this.sampleRate = 1024000;
|
|
55
|
+
this.state = State.OFF;
|
|
56
|
+
this.frequency = 88500000;
|
|
57
|
+
this.channel = new Channel();
|
|
58
|
+
this.parameterValues = new Map();
|
|
59
|
+
this.runLoop();
|
|
60
|
+
}
|
|
61
|
+
/** Current sample rate. */
|
|
62
|
+
sampleRate;
|
|
63
|
+
/** Current state. */
|
|
64
|
+
state;
|
|
65
|
+
/** Currently tuned frequency. */
|
|
66
|
+
frequency;
|
|
67
|
+
/** Channel to send messages to the state machine. */
|
|
68
|
+
channel;
|
|
69
|
+
/** Current values of the properties. */
|
|
70
|
+
parameterValues;
|
|
71
|
+
/**
|
|
72
|
+
* Starts playing the radio.
|
|
73
|
+
*
|
|
74
|
+
* @returns a promise that resolves after the command has been processed by the radio.
|
|
75
|
+
*/
|
|
76
|
+
async start() {
|
|
77
|
+
return this.channel.send({ type: "start" });
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Stops playing the radio.
|
|
81
|
+
*
|
|
82
|
+
* @returns a promise that resolves after the command has been processed by the radio.
|
|
83
|
+
*/
|
|
84
|
+
async stop() {
|
|
85
|
+
return this.channel.send({ type: "stop" });
|
|
86
|
+
}
|
|
87
|
+
/** Returns whether the radio is playing (or scanning). */
|
|
88
|
+
isPlaying() {
|
|
89
|
+
return this.state != State.OFF;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Tunes the radio to this frequency.
|
|
93
|
+
*
|
|
94
|
+
* @returns a promise that resolves after the command has been processed by the radio.
|
|
95
|
+
*/
|
|
96
|
+
async setFrequency(freq) {
|
|
97
|
+
return this.channel.send({ type: "frequency", value: freq });
|
|
98
|
+
}
|
|
99
|
+
/** Returns the tuned frequency. */
|
|
100
|
+
getFrequency() {
|
|
101
|
+
return this.frequency;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Changes the sample rate. This change only takes effect when the radio is started.
|
|
105
|
+
*
|
|
106
|
+
* @returns a promise that resolves after the command has been processed by the radio.
|
|
107
|
+
*/
|
|
108
|
+
async setSampleRate(sampleRate) {
|
|
109
|
+
return (this.sampleRate = sampleRate);
|
|
110
|
+
}
|
|
111
|
+
/** Returns the current sample rate. */
|
|
112
|
+
getSampleRate() {
|
|
113
|
+
return this.sampleRate;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Sets the value of a parameter.
|
|
117
|
+
*
|
|
118
|
+
* @returns a promise that resolves after the command has been processed by the radio.
|
|
119
|
+
*/
|
|
120
|
+
async setParameter(parameter, value) {
|
|
121
|
+
return this.channel.send({
|
|
122
|
+
type: "parameter",
|
|
123
|
+
name: parameter,
|
|
124
|
+
value: value,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
/** Returns the value of a parameter. */
|
|
128
|
+
getParameter(parameter) {
|
|
129
|
+
return this.parameterValues.get(parameter);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Returns a promise that resolves when the radio has processed all commands send to it up to this point.
|
|
133
|
+
*/
|
|
134
|
+
async ready() {
|
|
135
|
+
return this.channel.send({ type: "ready" });
|
|
136
|
+
}
|
|
137
|
+
/** Override this function to do something when a sample block is received. */
|
|
138
|
+
onReceiveSamples(block) { }
|
|
139
|
+
/** Runs the state machine. */
|
|
140
|
+
async runLoop() {
|
|
141
|
+
let transfers;
|
|
142
|
+
let source;
|
|
143
|
+
while (true) {
|
|
144
|
+
let { msg, ack } = await this.channel.receive();
|
|
145
|
+
try {
|
|
146
|
+
switch (this.state) {
|
|
147
|
+
case State.OFF: {
|
|
148
|
+
if (msg.type == "frequency")
|
|
149
|
+
this.frequency = msg.value;
|
|
150
|
+
if (msg.type == "parameter")
|
|
151
|
+
this.parameterValues.set(msg.name, msg.value);
|
|
152
|
+
if (msg.type != "start")
|
|
153
|
+
continue;
|
|
154
|
+
source = await this.sourceProvider.get();
|
|
155
|
+
this.sampleRate = await source.setSampleRate(this.sampleRate);
|
|
156
|
+
this.frequency = await source.setCenterFrequency(this.frequency);
|
|
157
|
+
for (let [name, value] of this.parameterValues.entries()) {
|
|
158
|
+
await source.setParameter(name, value);
|
|
159
|
+
}
|
|
160
|
+
await source.startReceiving();
|
|
161
|
+
transfers = new Transfers(source, this.sampleReceiver, this, this.sampleRate, this.options);
|
|
162
|
+
transfers.startStream();
|
|
163
|
+
this.state = State.PLAYING;
|
|
164
|
+
this.dispatchEvent(new RadioEvent({ type: "started" }));
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
case State.PLAYING: {
|
|
168
|
+
switch (msg.type) {
|
|
169
|
+
case "frequency":
|
|
170
|
+
if (this.frequency != msg.value) {
|
|
171
|
+
this.frequency = await source.setCenterFrequency(msg.value);
|
|
172
|
+
}
|
|
173
|
+
break;
|
|
174
|
+
case "parameter":
|
|
175
|
+
this.parameterValues.set(msg.name, await source.setParameter(msg.name, msg.value));
|
|
176
|
+
break;
|
|
177
|
+
case "stop":
|
|
178
|
+
await transfers.stopStream();
|
|
179
|
+
await source.close();
|
|
180
|
+
this.state = State.OFF;
|
|
181
|
+
this.dispatchEvent(new RadioEvent({ type: "stopped" }));
|
|
182
|
+
break;
|
|
183
|
+
default:
|
|
184
|
+
// do nothing.
|
|
185
|
+
}
|
|
186
|
+
break;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
catch (e) {
|
|
191
|
+
this.dispatchEvent(new RadioEvent({ type: "error", exception: e }));
|
|
192
|
+
}
|
|
193
|
+
finally {
|
|
194
|
+
ack();
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
addEventListener(type, callback, options) {
|
|
199
|
+
super.addEventListener(type, callback, options);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Transfer controller.
|
|
204
|
+
*
|
|
205
|
+
* Maintains 2 active transfers. When a transfer ends, it calls
|
|
206
|
+
* the sample receiver's 'receiveSamples' function and starts a new
|
|
207
|
+
* transfer. In this way, there is always a stream of samples coming in.
|
|
208
|
+
*/
|
|
209
|
+
class Transfers {
|
|
210
|
+
source;
|
|
211
|
+
sampleReceiver;
|
|
212
|
+
radio;
|
|
213
|
+
sampleRate;
|
|
214
|
+
/** Receive this many buffers per second by default. */
|
|
215
|
+
static DEFAULT_BUFS_PER_SEC = 20;
|
|
216
|
+
constructor(source, sampleReceiver, radio, sampleRate, options) {
|
|
217
|
+
this.source = source;
|
|
218
|
+
this.sampleReceiver = sampleReceiver;
|
|
219
|
+
this.radio = radio;
|
|
220
|
+
this.sampleRate = sampleRate;
|
|
221
|
+
let buffersPerSecond = options?.buffersPerSecond;
|
|
222
|
+
if (buffersPerSecond === undefined || buffersPerSecond <= 0)
|
|
223
|
+
buffersPerSecond = Transfers.DEFAULT_BUFS_PER_SEC;
|
|
224
|
+
this.samplesPerBuf = 512 * Math.ceil(sampleRate / buffersPerSecond / 512);
|
|
225
|
+
this.buffersWanted = 0;
|
|
226
|
+
this.buffersRunning = 0;
|
|
227
|
+
this.stopCallback = Transfers.nilCallback;
|
|
228
|
+
}
|
|
229
|
+
samplesPerBuf;
|
|
230
|
+
buffersWanted;
|
|
231
|
+
buffersRunning;
|
|
232
|
+
stopCallback;
|
|
233
|
+
static PARALLEL_BUFFERS = 2;
|
|
234
|
+
/** Starts the transfers as a stream. */
|
|
235
|
+
async startStream() {
|
|
236
|
+
this.sampleReceiver.setSampleRate(this.sampleRate);
|
|
237
|
+
await this.source.startReceiving();
|
|
238
|
+
this.buffersWanted = Transfers.PARALLEL_BUFFERS;
|
|
239
|
+
while (this.buffersRunning < this.buffersWanted) {
|
|
240
|
+
++this.buffersRunning;
|
|
241
|
+
this.readStream();
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Stops the transfer stream.
|
|
246
|
+
* @returns a promise that resolves when the stream is stopped.
|
|
247
|
+
*/
|
|
248
|
+
async stopStream() {
|
|
249
|
+
if (this.buffersRunning == 0 && this.buffersWanted == 0)
|
|
250
|
+
return;
|
|
251
|
+
let promise = new Promise((r) => {
|
|
252
|
+
this.stopCallback = r;
|
|
253
|
+
});
|
|
254
|
+
this.buffersWanted = 0;
|
|
255
|
+
return promise;
|
|
256
|
+
}
|
|
257
|
+
/** Runs the transfer stream. */
|
|
258
|
+
async readStream() {
|
|
259
|
+
try {
|
|
260
|
+
while (this.buffersRunning <= this.buffersWanted) {
|
|
261
|
+
const b = await this.source.readSamples(this.samplesPerBuf);
|
|
262
|
+
this.radio.onReceiveSamples(b);
|
|
263
|
+
this.sampleReceiver.receiveSamples(b.I, b.Q, b.frequency, b.data);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
catch (e) {
|
|
267
|
+
let error = new RadioError("Sample transfer was interrupted. Did you unplug your device?", RadioErrorType.TransferError, { cause: e });
|
|
268
|
+
let event = new RadioEvent({ type: "error", exception: error });
|
|
269
|
+
this.radio.dispatchEvent(event);
|
|
270
|
+
}
|
|
271
|
+
--this.buffersRunning;
|
|
272
|
+
if (this.buffersRunning == 0) {
|
|
273
|
+
this.stopCallback();
|
|
274
|
+
this.stopCallback = Transfers.nilCallback;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
static nilCallback() { }
|
|
278
|
+
}
|
|
279
|
+
//# sourceMappingURL=radio.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"radio.js","sourceRoot":"","sources":["../../src/radio/radio.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** Interface for classes that get samples from a Radio class. */
|
|
2
|
+
export interface SampleReceiver {
|
|
3
|
+
/** Sets the sample rate. */
|
|
4
|
+
setSampleRate(sampleRate: number): void;
|
|
5
|
+
/** Receives samples that should be demodulated. */
|
|
6
|
+
receiveSamples(I: Float32Array, Q: Float32Array, frequency: number, data?: any): void;
|
|
7
|
+
}
|
|
8
|
+
/** A "composite" sample receiver that executes its component receivers in sequence. */
|
|
9
|
+
export declare class CompositeReceiver implements SampleReceiver {
|
|
10
|
+
receivers: SampleReceiver[];
|
|
11
|
+
/** Creates a CompositeReceiver out of the given SampleReceivers. */
|
|
12
|
+
static of(first: SampleReceiver, ...rest: SampleReceiver[]): SampleReceiver;
|
|
13
|
+
private constructor();
|
|
14
|
+
setSampleRate(sampleRate: number): void;
|
|
15
|
+
receiveSamples(I: Float32Array, Q: Float32Array, frequency: number): void;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=sample_receiver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sample_receiver.d.ts","sourceRoot":"","sources":["../../src/radio/sample_receiver.ts"],"names":[],"mappings":"AAcA,iEAAiE;AACjE,MAAM,WAAW,cAAc;IAC7B,4BAA4B;IAC5B,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAExC,mDAAmD;IACnD,cAAc,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,GAAG,IAAI,CAAC;CACvF;AAED,uFAAuF;AACvF,qBAAa,iBAAkB,YAAW,cAAc;IAoB3B,SAAS,EAAE,cAAc,EAAE;IAnBtD,oEAAoE;IACpE,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,IAAI,EAAE,cAAc,EAAE,GAAG,cAAc;IAkB3E,OAAO;IAEP,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAMvC,cAAc,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;CAK1E"}
|
|
@@ -0,0 +1,52 @@
|
|
|
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
|
+
/** A "composite" sample receiver that executes its component receivers in sequence. */
|
|
15
|
+
export class CompositeReceiver {
|
|
16
|
+
receivers;
|
|
17
|
+
/** Creates a CompositeReceiver out of the given SampleReceivers. */
|
|
18
|
+
static of(first, ...rest) {
|
|
19
|
+
let list = [];
|
|
20
|
+
if (first instanceof CompositeReceiver) {
|
|
21
|
+
list.push(...first.receivers);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
list.push(first);
|
|
25
|
+
}
|
|
26
|
+
for (let next of rest) {
|
|
27
|
+
if (next instanceof CompositeReceiver) {
|
|
28
|
+
list.push(...next.receivers);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
list.push(next);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (list.length == 1)
|
|
35
|
+
return list[0];
|
|
36
|
+
return new CompositeReceiver(list);
|
|
37
|
+
}
|
|
38
|
+
constructor(receivers) {
|
|
39
|
+
this.receivers = receivers;
|
|
40
|
+
}
|
|
41
|
+
setSampleRate(sampleRate) {
|
|
42
|
+
for (let receiver of this.receivers) {
|
|
43
|
+
receiver.setSampleRate(sampleRate);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
receiveSamples(I, Q, frequency) {
|
|
47
|
+
for (let receiver of this.receivers) {
|
|
48
|
+
receiver.receiveSamples(I, Q, frequency);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=sample_receiver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sample_receiver.js","sourceRoot":"","sources":["../../src/radio/sample_receiver.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,EAAE;AACF,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,iDAAiD;AACjD,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAWjC,uFAAuF;AACvF,MAAM,OAAO,iBAAiB;IAoBD;IAnB3B,oEAAoE;IACpE,MAAM,CAAC,EAAE,CAAC,KAAqB,EAAE,GAAG,IAAsB;QACxD,IAAI,IAAI,GAAqB,EAAE,CAAC;QAChC,IAAI,KAAK,YAAY,iBAAiB,EAAE,CAAC;YACvC,IAAI,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC;QAChC,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACnB,CAAC;QACD,KAAK,IAAI,IAAI,IAAI,IAAI,EAAE,CAAC;YACtB,IAAI,IAAI,YAAY,iBAAiB,EAAE,CAAC;gBACtC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC;YAC/B,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClB,CAAC;QACH,CAAC;QACD,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC;QACrC,OAAO,IAAI,iBAAiB,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC;IAED,YAA2B,SAA2B;QAA3B,cAAS,GAAT,SAAS,CAAkB;IAAG,CAAC;IAE1D,aAAa,CAAC,UAAkB;QAC9B,KAAK,IAAI,QAAQ,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACpC,QAAQ,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;QACrC,CAAC;IACH,CAAC;IAED,cAAc,CAAC,CAAe,EAAE,CAAe,EAAE,SAAiB;QAChE,KAAK,IAAI,QAAQ,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACpC,QAAQ,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/** A block of samples returned by SignalSource.readSamples() */
|
|
2
|
+
export type SampleBlock = {
|
|
3
|
+
/**
|
|
4
|
+
* The I components of the samples.
|
|
5
|
+
* Each element of I matches a corresponding element of Q, and I and Q have the same lengths.
|
|
6
|
+
*/
|
|
7
|
+
I: Float32Array;
|
|
8
|
+
/**
|
|
9
|
+
* The Q components of the samples.
|
|
10
|
+
* Each element of Q matches a corresponding element of I, and I and Q have the same lengths.
|
|
11
|
+
*/
|
|
12
|
+
Q: Float32Array;
|
|
13
|
+
/** The center frequency the source listened on when these samples were captured. */
|
|
14
|
+
frequency: number;
|
|
15
|
+
/** Extra data. */
|
|
16
|
+
data?: any;
|
|
17
|
+
};
|
|
18
|
+
/** Interface for a sample source. */
|
|
19
|
+
export interface SignalSource<ParameterKey extends string = string> {
|
|
20
|
+
/**
|
|
21
|
+
* Sets the wanted sample rate for the source.
|
|
22
|
+
* Returns the actual sample rate, which may differ.
|
|
23
|
+
* This function should be called before start.
|
|
24
|
+
*/
|
|
25
|
+
setSampleRate(sampleRate: number): Promise<number>;
|
|
26
|
+
/**
|
|
27
|
+
* Sets the center frequency the source listens on.
|
|
28
|
+
* Returns the actual center frequency, which may differ.
|
|
29
|
+
*/
|
|
30
|
+
setCenterFrequency(freq: number): Promise<number>;
|
|
31
|
+
/** Sets the value of a parameter. */
|
|
32
|
+
setParameter<V>(parameter: ParameterKey, value: V): Promise<V | void>;
|
|
33
|
+
/**
|
|
34
|
+
* Prepares the source to start streaming samples.
|
|
35
|
+
* You must call this function before you start reading samples.
|
|
36
|
+
*/
|
|
37
|
+
startReceiving(): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* Reads the given number of samples.
|
|
40
|
+
*
|
|
41
|
+
* You may have several readSamples calls in flight,
|
|
42
|
+
* and their promises will be resolved in the same order that they were issued.
|
|
43
|
+
*/
|
|
44
|
+
readSamples(length: number): Promise<SampleBlock>;
|
|
45
|
+
/** Shuts down the signal source. */
|
|
46
|
+
close(): Promise<void>;
|
|
47
|
+
}
|
|
48
|
+
/** Interface for classes that return SignalSource instances. */
|
|
49
|
+
export interface SignalSourceProvider {
|
|
50
|
+
/** Returns a signal source. */
|
|
51
|
+
get(): Promise<SignalSource>;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=signal_source.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signal_source.d.ts","sourceRoot":"","sources":["../../src/radio/signal_source.ts"],"names":[],"mappings":"AAcA,gEAAgE;AAChE,MAAM,MAAM,WAAW,GAAG;IACxB;;;OAGG;IACH,CAAC,EAAE,YAAY,CAAC;IAChB;;;OAGG;IACH,CAAC,EAAE,YAAY,CAAC;IAChB,oFAAoF;IACpF,SAAS,EAAE,MAAM,CAAC;IAClB,kBAAkB;IAClB,IAAI,CAAC,EAAE,GAAG,CAAC;CACZ,CAAC;AAEF,qCAAqC;AACrC,MAAM,WAAW,YAAY,CAAC,YAAY,SAAS,MAAM,GAAG,MAAM;IAChE;;;;OAIG;IACH,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACnD;;;OAGG;IACH,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAClD,qCAAqC;IACrC,YAAY,CAAC,CAAC,EAAE,SAAS,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACtE;;;OAGG;IACH,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC;;;;;OAKG;IACH,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAClD,oCAAoC;IACpC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,gEAAgE;AAChE,MAAM,WAAW,oBAAoB;IACnC,+BAA+B;IAC/B,GAAG,IAAI,OAAO,CAAC,YAAY,CAAC,CAAC;CAC9B"}
|
|
@@ -0,0 +1,15 @@
|
|
|
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
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=signal_source.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signal_source.js","sourceRoot":"","sources":["../../src/radio/signal_source.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,EAAE;AACF,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,iDAAiD;AACjD,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC"}
|
package/dist/radio.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"radio.d.ts","sourceRoot":"","sources":["../src/radio.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,0BAA0B,CAAC"}
|
package/dist/radio.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"radio.js","sourceRoot":"","sources":["../src/radio.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,0BAA0B,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { SampleGenerator } from "./realtime.js";
|
|
2
|
+
/** Returns a generator for a tone at the given frequency with the given amplitude. */
|
|
3
|
+
export declare function tone(freq: number, amplitude: number, phase?: number): SampleGenerator;
|
|
4
|
+
/** Returns a generator for noise with a given maximum amplitude. */
|
|
5
|
+
export declare function noise(amplitude: number, random?: () => number): SampleGenerator;
|
|
6
|
+
/** Returns a generator that adds the outputs of all the provided generators together. */
|
|
7
|
+
export declare function sum(...generators: SampleGenerator[]): SampleGenerator;
|
|
8
|
+
/**
|
|
9
|
+
* Returns a generator that multiplies the output of the carrier generator
|
|
10
|
+
* with the output of the signal generator.
|
|
11
|
+
* The signal generator always receives a center frequency of 0 Hz.
|
|
12
|
+
*/
|
|
13
|
+
export declare function product(carrier: SampleGenerator, signal: SampleGenerator): SampleGenerator;
|
|
14
|
+
/**
|
|
15
|
+
* Returns a generator that multiplies every sample by the given gain.
|
|
16
|
+
*/
|
|
17
|
+
export declare function amplify(gain: number, signal: SampleGenerator): SampleGenerator;
|
|
18
|
+
/** Returns the real part of another generator's output. */
|
|
19
|
+
export declare function real(signal: SampleGenerator): SampleGenerator;
|
|
20
|
+
/**
|
|
21
|
+
* Returns a generator that amplitude-modulates the output
|
|
22
|
+
* of the signal generator using a modulation factor of 2.
|
|
23
|
+
* Only the I component of the signal is used as the input.
|
|
24
|
+
* The signal generator always receives a center frequency of 0 Hz.
|
|
25
|
+
*/
|
|
26
|
+
export declare function modulateAM(carrierFreq: number, amplitude: number, signal: SampleGenerator): SampleGenerator;
|
|
27
|
+
/**
|
|
28
|
+
* Returns a generator that frequency-modulates the output
|
|
29
|
+
* of the signal generator using the given maximum frequency deviation.
|
|
30
|
+
* Only the I component of the signal is used as the input.
|
|
31
|
+
* The signal generator always receives a center frequency of 0 Hz.
|
|
32
|
+
*/
|
|
33
|
+
export declare function modulateFM(carrierFreq: number, maximumDeviation: number, amplitude: number, signal: SampleGenerator): SampleGenerator;
|
|
34
|
+
/**
|
|
35
|
+
* Returns a generator that produces a baseband signal for WBFM modulation
|
|
36
|
+
* for mono or left and right channels, with the given time constant in microseconds
|
|
37
|
+
* (50 by default.)
|
|
38
|
+
*/
|
|
39
|
+
export declare function wbfmSignal(mono: SampleGenerator, tcMicros?: number): SampleGenerator;
|
|
40
|
+
export declare function wbfmSignal(left: SampleGenerator, right: SampleGenerator, tcMicros?: number): SampleGenerator;
|
|
41
|
+
//# sourceMappingURL=generators.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generators.d.ts","sourceRoot":"","sources":["../../src/sources/generators.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD,sFAAsF;AACtF,wBAAgB,IAAI,CAClB,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,KAAK,CAAC,EAAE,MAAM,GACb,eAAe,CA8BjB;AAED,oEAAoE;AACpE,wBAAgB,KAAK,CACnB,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,MAAM,MAAM,GACpB,eAAe,CAgBjB;AAED,yFAAyF;AACzF,wBAAgB,GAAG,CAAC,GAAG,UAAU,EAAE,eAAe,EAAE,GAAG,eAAe,CAoBrE;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CACrB,OAAO,EAAE,eAAe,EACxB,MAAM,EAAE,eAAe,GACtB,eAAe,CAqBjB;AAED;;GAEG;AACH,wBAAgB,OAAO,CACrB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,eAAe,GACtB,eAAe,CAcjB;AAED,2DAA2D;AAC3D,wBAAgB,IAAI,CAAC,MAAM,EAAE,eAAe,GAAG,eAAe,CAW7D;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CACxB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,eAAe,GACtB,eAAe,CAyBjB;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CACxB,WAAW,EAAE,MAAM,EACnB,gBAAgB,EAAE,MAAM,EACxB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,eAAe,GACtB,eAAe,CAgCjB;AAqED;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,IAAI,EAAE,eAAe,EACrB,QAAQ,CAAC,EAAE,MAAM,GAChB,eAAe,CAAC;AACnB,wBAAgB,UAAU,CACxB,IAAI,EAAE,eAAe,EACrB,KAAK,EAAE,eAAe,EACtB,QAAQ,CAAC,EAAE,MAAM,GAChB,eAAe,CAAC"}
|