@jtarrio/webrtlsdr 3.0.1 → 3.0.2
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/dist/demod/demod-am.d.ts +54 -0
- package/dist/demod/demod-am.d.ts.map +1 -0
- package/dist/demod/demod-am.js +113 -0
- package/dist/demod/demod-am.js.map +1 -0
- package/dist/demod/demod-cw.d.ts +48 -0
- package/dist/demod/demod-cw.d.ts.map +1 -0
- package/dist/demod/demod-cw.js +101 -0
- package/dist/demod/demod-cw.js.map +1 -0
- package/dist/demod/demod-nbfm.d.ts +54 -0
- package/dist/demod/demod-nbfm.d.ts.map +1 -0
- package/dist/demod/demod-nbfm.js +114 -0
- package/dist/demod/demod-nbfm.js.map +1 -0
- package/dist/demod/demod-ssb.d.ts +55 -0
- package/dist/demod/demod-ssb.d.ts.map +1 -0
- package/dist/demod/demod-ssb.js +112 -0
- package/dist/demod/demod-ssb.js.map +1 -0
- package/dist/demod/demod-wbfm.d.ts +113 -0
- package/dist/demod/demod-wbfm.d.ts.map +1 -0
- package/dist/demod/demod-wbfm.js +212 -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 +82 -0
- package/dist/demod/empty-demodulator.d.ts.map +1 -0
- package/dist/demod/empty-demodulator.js +149 -0
- package/dist/demod/empty-demodulator.js.map +1 -0
- package/dist/demod/modes.d.ts +107 -0
- package/dist/demod/modes.d.ts.map +1 -0
- package/dist/demod/modes.js +101 -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 +78 -0
- package/dist/demod/spectrum.js.map +1 -0
- package/dist/dsp/buffers.d.ts +72 -0
- package/dist/dsp/buffers.d.ts.map +1 -0
- package/dist/dsp/buffers.js +122 -0
- package/dist/dsp/buffers.js.map +1 -0
- package/dist/dsp/coefficients.d.ts +22 -0
- package/dist/dsp/coefficients.d.ts.map +1 -0
- package/dist/dsp/coefficients.js +77 -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 +73 -0
- package/dist/dsp/demodulators.d.ts.map +1 -0
- package/dist/dsp/demodulators.js +244 -0
- package/dist/dsp/demodulators.js.map +1 -0
- package/dist/dsp/fft.d.ts +53 -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 +91 -0
- package/dist/dsp/filters.d.ts.map +1 -0
- package/dist/dsp/filters.js +250 -0
- package/dist/dsp/filters.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 +33 -0
- package/dist/dsp/resamplers.d.ts.map +1 -0
- package/dist/dsp/resamplers.js +91 -0
- package/dist/dsp/resamplers.js.map +1 -0
- package/dist/errors.d.ts +2 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +1 -0
- package/dist/errors.js.map +1 -1
- package/dist/players/audioplayer.d.ts +34 -0
- package/dist/players/audioplayer.d.ts.map +1 -0
- package/dist/players/audioplayer.js +71 -0
- package/dist/players/audioplayer.js.map +1 -0
- package/dist/radio/msgqueue.d.ts +23 -0
- package/dist/radio/msgqueue.d.ts.map +1 -0
- package/dist/radio/msgqueue.js +52 -0
- package/dist/radio/msgqueue.js.map +1 -0
- package/dist/radio/radio.d.ts +63 -22
- package/dist/radio/radio.d.ts.map +1 -1
- package/dist/radio/radio.js +255 -41
- package/dist/radio/radio.js.map +1 -1
- package/dist/radio/sample_receiver.d.ts +19 -0
- package/dist/radio/sample_receiver.d.ts.map +1 -0
- package/dist/radio/sample_receiver.js +54 -0
- package/dist/radio/sample_receiver.js.map +1 -0
- package/dist/radio.d.ts +1 -2
- package/dist/radio.d.ts.map +1 -1
- package/dist/radio.js +1 -1
- package/dist/radio.js.map +1 -1
- package/dist/rtlsdr/rtl2832u.d.ts +10 -1
- package/dist/rtlsdr/rtl2832u.d.ts.map +1 -1
- package/dist/rtlsdr/rtl2832u.js +6 -4
- package/dist/rtlsdr/rtl2832u.js.map +1 -1
- package/dist/rtlsdr/rtlcom.d.ts.map +1 -1
- package/dist/rtlsdr/rtlcom.js.map +1 -1
- package/package.json +2 -2
- package/dist/radio/source.d.ts +0 -25
- package/dist/radio/source.d.ts.map +0 -1
- package/dist/radio/source.js +0 -69
- package/dist/radio/source.js.map +0 -1
|
@@ -0,0 +1,250 @@
|
|
|
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
|
+
/** A class to apply a FIR filter to a sequence of samples. */
|
|
16
|
+
export class FIRFilter {
|
|
17
|
+
coefs;
|
|
18
|
+
/** @param coefs The coefficients of the filter to apply. */
|
|
19
|
+
constructor(coefs) {
|
|
20
|
+
this.coefs = coefs;
|
|
21
|
+
this.offset = this.coefs.length - 1;
|
|
22
|
+
this.center = Math.floor(this.coefs.length / 2);
|
|
23
|
+
this.curSamples = new Float32Array(this.offset);
|
|
24
|
+
}
|
|
25
|
+
offset;
|
|
26
|
+
center;
|
|
27
|
+
curSamples;
|
|
28
|
+
setCoefficients(coefs) {
|
|
29
|
+
const oldSamples = this.curSamples;
|
|
30
|
+
this.coefs = coefs;
|
|
31
|
+
this.offset = this.coefs.length - 1;
|
|
32
|
+
this.center = Math.floor(this.coefs.length / 2);
|
|
33
|
+
this.curSamples = new Float32Array(this.offset);
|
|
34
|
+
this.loadSamples(oldSamples);
|
|
35
|
+
}
|
|
36
|
+
clone() {
|
|
37
|
+
return new FIRFilter(this.coefs);
|
|
38
|
+
}
|
|
39
|
+
delay() {
|
|
40
|
+
return this.center;
|
|
41
|
+
}
|
|
42
|
+
inPlace(samples) {
|
|
43
|
+
this.loadSamples(samples);
|
|
44
|
+
for (let i = 0; i < samples.length; ++i) {
|
|
45
|
+
samples[i] = this.get(i);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Loads a new block of samples to filter.
|
|
50
|
+
* @param samples The samples to load.
|
|
51
|
+
*/
|
|
52
|
+
loadSamples(samples) {
|
|
53
|
+
const len = samples.length + this.offset;
|
|
54
|
+
if (this.curSamples.length != len) {
|
|
55
|
+
let newSamples = new Float32Array(len);
|
|
56
|
+
newSamples.set(this.curSamples.subarray(this.curSamples.length - this.offset));
|
|
57
|
+
this.curSamples = newSamples;
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
this.curSamples.copyWithin(0, samples.length);
|
|
61
|
+
}
|
|
62
|
+
this.curSamples.set(samples, this.offset);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Returns a filtered sample.
|
|
66
|
+
* Be very careful when you modify this function. About 85% of the total execution
|
|
67
|
+
* time is spent here, so performance is critical.
|
|
68
|
+
* @param index The index of the sample to return, corresponding
|
|
69
|
+
* to the same index in the latest sample block loaded via loadSamples().
|
|
70
|
+
*/
|
|
71
|
+
get(index) {
|
|
72
|
+
let i = 0;
|
|
73
|
+
let out = 0;
|
|
74
|
+
let len = this.coefs.length;
|
|
75
|
+
let len4 = 4 * Math.floor(len / 4);
|
|
76
|
+
while (i < len4) {
|
|
77
|
+
out +=
|
|
78
|
+
this.coefs[i++] * this.curSamples[index++] +
|
|
79
|
+
this.coefs[i++] * this.curSamples[index++] +
|
|
80
|
+
this.coefs[i++] * this.curSamples[index++] +
|
|
81
|
+
this.coefs[i++] * this.curSamples[index++];
|
|
82
|
+
}
|
|
83
|
+
let len2 = 2 * Math.floor(len / 2);
|
|
84
|
+
while (i < len2) {
|
|
85
|
+
out +=
|
|
86
|
+
this.coefs[i++] * this.curSamples[index++] +
|
|
87
|
+
this.coefs[i++] * this.curSamples[index++];
|
|
88
|
+
}
|
|
89
|
+
while (i < len) {
|
|
90
|
+
out += this.coefs[i++] * this.curSamples[index++];
|
|
91
|
+
}
|
|
92
|
+
return out;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Returns a delayed sample.
|
|
96
|
+
* @param index The index of the relative sample to return.
|
|
97
|
+
*/
|
|
98
|
+
getDelayed(index) {
|
|
99
|
+
return this.curSamples[index + this.center];
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/** Automatic gain control for audio signals. */
|
|
103
|
+
export class AGC {
|
|
104
|
+
sampleRate;
|
|
105
|
+
constructor(sampleRate, timeConstantSeconds, maxGain) {
|
|
106
|
+
this.sampleRate = sampleRate;
|
|
107
|
+
this.dcBlocker = new DcBlocker(sampleRate);
|
|
108
|
+
this.alpha = 1 - Math.exp(-1 / (sampleRate * timeConstantSeconds));
|
|
109
|
+
this.counter = 0;
|
|
110
|
+
this.maxPower = 0;
|
|
111
|
+
this.maxGain = maxGain || 100;
|
|
112
|
+
}
|
|
113
|
+
dcBlocker;
|
|
114
|
+
alpha;
|
|
115
|
+
counter;
|
|
116
|
+
maxPower;
|
|
117
|
+
maxGain;
|
|
118
|
+
clone() {
|
|
119
|
+
let copy = new AGC(this.sampleRate, 1, this.maxGain);
|
|
120
|
+
copy.alpha = this.alpha;
|
|
121
|
+
return copy;
|
|
122
|
+
}
|
|
123
|
+
delay() {
|
|
124
|
+
return 0;
|
|
125
|
+
}
|
|
126
|
+
inPlace(samples) {
|
|
127
|
+
const alpha = this.alpha;
|
|
128
|
+
let maxPower = this.maxPower;
|
|
129
|
+
let counter = this.counter;
|
|
130
|
+
let gain;
|
|
131
|
+
this.dcBlocker.inPlace(samples);
|
|
132
|
+
for (let i = 0; i < samples.length; ++i) {
|
|
133
|
+
const v = samples[i];
|
|
134
|
+
const power = v * v;
|
|
135
|
+
if (power > 0.9 * maxPower) {
|
|
136
|
+
counter = this.sampleRate;
|
|
137
|
+
if (power > maxPower) {
|
|
138
|
+
maxPower = power;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
else if (counter > 0) {
|
|
142
|
+
--counter;
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
maxPower -= alpha * maxPower;
|
|
146
|
+
}
|
|
147
|
+
gain = Math.min(this.maxGain, 1 / Math.sqrt(maxPower));
|
|
148
|
+
samples[i] *= gain;
|
|
149
|
+
}
|
|
150
|
+
this.maxPower = maxPower;
|
|
151
|
+
this.counter = counter;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/** A filter that blocks DC signals. */
|
|
155
|
+
export class DcBlocker {
|
|
156
|
+
restricted;
|
|
157
|
+
constructor(sampleRate, restricted) {
|
|
158
|
+
this.restricted = restricted;
|
|
159
|
+
this.alpha = 1 - Math.exp(-1 / (sampleRate / 2));
|
|
160
|
+
this.dc = 0;
|
|
161
|
+
this.restricted = this.restricted || false;
|
|
162
|
+
}
|
|
163
|
+
alpha;
|
|
164
|
+
dc;
|
|
165
|
+
clone() {
|
|
166
|
+
let copy = new DcBlocker(1000);
|
|
167
|
+
copy.alpha = this.alpha;
|
|
168
|
+
copy.dc = this.dc;
|
|
169
|
+
return copy;
|
|
170
|
+
}
|
|
171
|
+
delay() {
|
|
172
|
+
return 0;
|
|
173
|
+
}
|
|
174
|
+
inPlace(samples) {
|
|
175
|
+
const alpha = this.alpha;
|
|
176
|
+
let dc = this.dc;
|
|
177
|
+
for (let i = 0; i < samples.length; ++i) {
|
|
178
|
+
dc += alpha * (samples[i] - dc);
|
|
179
|
+
if (!this.restricted || dc * dc < 6e-5)
|
|
180
|
+
samples[i] -= dc;
|
|
181
|
+
}
|
|
182
|
+
this.dc = dc;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/** A de-emphasis filter with the given time constant. */
|
|
186
|
+
export class Deemphasizer {
|
|
187
|
+
/**
|
|
188
|
+
* @param sampleRate The signal's sample rate.
|
|
189
|
+
* @param timeConstant_uS The filter's time constant in microseconds.
|
|
190
|
+
*/
|
|
191
|
+
constructor(sampleRate, timeConstant_uS) {
|
|
192
|
+
this.alpha = 1 - Math.exp(-1 / ((sampleRate * timeConstant_uS) / 1e6));
|
|
193
|
+
this.val = 0;
|
|
194
|
+
}
|
|
195
|
+
alpha;
|
|
196
|
+
val;
|
|
197
|
+
/** Returns a copy of this deemphasizer. */
|
|
198
|
+
clone() {
|
|
199
|
+
let copy = new Deemphasizer(1, 1);
|
|
200
|
+
copy.alpha = this.alpha;
|
|
201
|
+
copy.val = this.val;
|
|
202
|
+
return copy;
|
|
203
|
+
}
|
|
204
|
+
delay() {
|
|
205
|
+
return 0;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Deemphasizes the given samples in place.
|
|
209
|
+
* @param samples The samples to deemphasize.
|
|
210
|
+
*/
|
|
211
|
+
inPlace(samples) {
|
|
212
|
+
const alpha = this.alpha;
|
|
213
|
+
let val = this.val;
|
|
214
|
+
for (let i = 0; i < samples.length; ++i) {
|
|
215
|
+
val += alpha * (samples[i] - val);
|
|
216
|
+
samples[i] = val;
|
|
217
|
+
}
|
|
218
|
+
this.val = val;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Shifts IQ samples by a given frequency.
|
|
223
|
+
*/
|
|
224
|
+
export class FrequencyShifter {
|
|
225
|
+
sampleRate;
|
|
226
|
+
constructor(sampleRate) {
|
|
227
|
+
this.sampleRate = sampleRate;
|
|
228
|
+
this.cosine = 1;
|
|
229
|
+
this.sine = 0;
|
|
230
|
+
}
|
|
231
|
+
cosine;
|
|
232
|
+
sine;
|
|
233
|
+
inPlace(I, Q, freq) {
|
|
234
|
+
let cosine = this.cosine;
|
|
235
|
+
let sine = this.sine;
|
|
236
|
+
const deltaCos = Math.cos((2 * Math.PI * freq) / this.sampleRate);
|
|
237
|
+
const deltaSin = Math.sin((2 * Math.PI * freq) / this.sampleRate);
|
|
238
|
+
for (let i = 0; i < I.length; ++i) {
|
|
239
|
+
const newI = I[i] * cosine - Q[i] * sine;
|
|
240
|
+
Q[i] = I[i] * sine + Q[i] * cosine;
|
|
241
|
+
I[i] = newI;
|
|
242
|
+
const newSine = cosine * deltaSin + sine * deltaCos;
|
|
243
|
+
cosine = cosine * deltaCos - sine * deltaSin;
|
|
244
|
+
sine = newSine;
|
|
245
|
+
}
|
|
246
|
+
this.cosine = cosine;
|
|
247
|
+
this.sine = sine;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
//# sourceMappingURL=filters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filters.js","sourceRoot":"","sources":["../../src/dsp/filters.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"power.d.ts","sourceRoot":"","sources":["../../src/dsp/power.ts"],"names":[],"mappings":"AAcA,wBAAgB,QAAQ,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,YAAY,GAAG,MAAM,CAQjE"}
|
|
@@ -0,0 +1,23 @@
|
|
|
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 function getPower(I, Q) {
|
|
15
|
+
let power = 0;
|
|
16
|
+
for (let i = 0; i < I.length; ++i) {
|
|
17
|
+
const vI = I[i];
|
|
18
|
+
const vQ = Q[i];
|
|
19
|
+
power += vI * vI + vQ * vQ;
|
|
20
|
+
}
|
|
21
|
+
return power / I.length;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=power.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"power.js","sourceRoot":"","sources":["../../src/dsp/power.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;AAEjC,MAAM,UAAU,QAAQ,CAAC,CAAe,EAAE,CAAe;IACvD,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC;QAClC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAChB,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAChB,KAAK,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;IAC7B,CAAC;IACD,OAAO,KAAK,GAAG,CAAC,CAAC,MAAM,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/** A class to convert a real input to a lower sample rate. */
|
|
2
|
+
export declare class RealDownsampler {
|
|
3
|
+
/**
|
|
4
|
+
* @param inRate The input sample rate.
|
|
5
|
+
* @param outRate The output sample rate.
|
|
6
|
+
* @param filterLen The size of the low-pass filter.
|
|
7
|
+
*/
|
|
8
|
+
constructor(inRate: number, outRate: number, filterLen: number);
|
|
9
|
+
private downsampler;
|
|
10
|
+
/**
|
|
11
|
+
* @param input The signal in the original sample rate.
|
|
12
|
+
* @returns The resampled signal.
|
|
13
|
+
*/
|
|
14
|
+
downsample(input: Float32Array): Float32Array;
|
|
15
|
+
}
|
|
16
|
+
/** A class to convert a complex input to a lower sample rate. */
|
|
17
|
+
export declare class ComplexDownsampler {
|
|
18
|
+
/**
|
|
19
|
+
* @param inRate The input sample rate.
|
|
20
|
+
* @param outRate The output sample rate.
|
|
21
|
+
* @param filterLen The size of the low-pass filter.
|
|
22
|
+
*/
|
|
23
|
+
constructor(inRate: number, outRate: number, filterLen: number);
|
|
24
|
+
private downsamplerI;
|
|
25
|
+
private downsamplerQ;
|
|
26
|
+
/**
|
|
27
|
+
* @param I The signal's real component.
|
|
28
|
+
* @param Q The signal's imaginary component.
|
|
29
|
+
* @returns An array with the output's real and imaginary components.
|
|
30
|
+
*/
|
|
31
|
+
downsample(I: Float32Array, Q: Float32Array): [Float32Array, Float32Array];
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=resamplers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resamplers.d.ts","sourceRoot":"","sources":["../../src/dsp/resamplers.ts"],"names":[],"mappings":"AAqDA,8DAA8D;AAC9D,qBAAa,eAAe;IAC1B;;;;OAIG;gBACS,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAK9D,OAAO,CAAC,WAAW,CAAc;IAEjC;;;OAGG;IACH,UAAU,CAAC,KAAK,EAAE,YAAY,GAAG,YAAY;CAG9C;AAED,iEAAiE;AACjE,qBAAa,kBAAkB;IAC7B;;;;OAIG;gBACS,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAM9D,OAAO,CAAC,YAAY,CAAc;IAClC,OAAO,CAAC,YAAY,CAAc;IAElC;;;;OAIG;IACH,UAAU,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,YAAY,GAAG,CAAC,YAAY,EAAE,YAAY,CAAC;CAG3E"}
|
|
@@ -0,0 +1,91 @@
|
|
|
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 { Float32Buffer } from "./buffers.js";
|
|
16
|
+
import { makeLowPassKernel } from "./coefficients.js";
|
|
17
|
+
import { FIRFilter } from "./filters.js";
|
|
18
|
+
/** A class to convert the input to a lower sample rate. */
|
|
19
|
+
class Downsampler {
|
|
20
|
+
ratio;
|
|
21
|
+
/**
|
|
22
|
+
* @param ratio The ratio of input/output sample rates.
|
|
23
|
+
* @param kernel The coefficients for the low-pass filter.
|
|
24
|
+
*/
|
|
25
|
+
constructor(ratio, kernel) {
|
|
26
|
+
this.ratio = ratio;
|
|
27
|
+
this.filter = new FIRFilter(kernel);
|
|
28
|
+
this.buffer = new Float32Buffer(2);
|
|
29
|
+
}
|
|
30
|
+
filter;
|
|
31
|
+
buffer;
|
|
32
|
+
/**
|
|
33
|
+
* Returns a downsampled version of the given samples.
|
|
34
|
+
* @param samples The sample block to downsample.
|
|
35
|
+
* @returns The downsampled block.
|
|
36
|
+
*/
|
|
37
|
+
downsample(samples) {
|
|
38
|
+
const ratio = this.ratio;
|
|
39
|
+
const len = Math.floor(samples.length / ratio);
|
|
40
|
+
let output = this.buffer.get(len);
|
|
41
|
+
this.filter.loadSamples(samples);
|
|
42
|
+
for (let i = 0; i < len; ++i) {
|
|
43
|
+
output[i] = this.filter.get(Math.floor(i * ratio));
|
|
44
|
+
}
|
|
45
|
+
return output;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/** A class to convert a real input to a lower sample rate. */
|
|
49
|
+
export class RealDownsampler {
|
|
50
|
+
/**
|
|
51
|
+
* @param inRate The input sample rate.
|
|
52
|
+
* @param outRate The output sample rate.
|
|
53
|
+
* @param filterLen The size of the low-pass filter.
|
|
54
|
+
*/
|
|
55
|
+
constructor(inRate, outRate, filterLen) {
|
|
56
|
+
const kernel = makeLowPassKernel(inRate, outRate / 2, filterLen);
|
|
57
|
+
this.downsampler = new Downsampler(inRate / outRate, kernel);
|
|
58
|
+
}
|
|
59
|
+
downsampler;
|
|
60
|
+
/**
|
|
61
|
+
* @param input The signal in the original sample rate.
|
|
62
|
+
* @returns The resampled signal.
|
|
63
|
+
*/
|
|
64
|
+
downsample(input) {
|
|
65
|
+
return this.downsampler.downsample(input);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/** A class to convert a complex input to a lower sample rate. */
|
|
69
|
+
export class ComplexDownsampler {
|
|
70
|
+
/**
|
|
71
|
+
* @param inRate The input sample rate.
|
|
72
|
+
* @param outRate The output sample rate.
|
|
73
|
+
* @param filterLen The size of the low-pass filter.
|
|
74
|
+
*/
|
|
75
|
+
constructor(inRate, outRate, filterLen) {
|
|
76
|
+
const kernel = makeLowPassKernel(inRate, outRate / 2, filterLen);
|
|
77
|
+
this.downsamplerI = new Downsampler(inRate / outRate, kernel);
|
|
78
|
+
this.downsamplerQ = new Downsampler(inRate / outRate, kernel);
|
|
79
|
+
}
|
|
80
|
+
downsamplerI;
|
|
81
|
+
downsamplerQ;
|
|
82
|
+
/**
|
|
83
|
+
* @param I The signal's real component.
|
|
84
|
+
* @param Q The signal's imaginary component.
|
|
85
|
+
* @returns An array with the output's real and imaginary components.
|
|
86
|
+
*/
|
|
87
|
+
downsample(I, Q) {
|
|
88
|
+
return [this.downsamplerI.downsample(I), this.downsamplerQ.downsample(Q)];
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=resamplers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resamplers.js","sourceRoot":"","sources":["../../src/dsp/resamplers.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,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,2DAA2D;AAC3D,MAAM,WAAW;IAML;IALV;;;OAGG;IACH,YACU,KAAa,EACrB,MAAoB;QADZ,UAAK,GAAL,KAAK,CAAQ;QAGrB,IAAI,CAAC,MAAM,GAAG,IAAI,SAAS,CAAC,MAAM,CAAC,CAAC;QACpC,IAAI,CAAC,MAAM,GAAG,IAAI,aAAa,CAAC,CAAC,CAAC,CAAC;IACrC,CAAC;IAEO,MAAM,CAAY;IAClB,MAAM,CAAgB;IAE9B;;;;OAIG;IACH,UAAU,CAAC,OAAqB;QAC9B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACzB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC;QAC/C,IAAI,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QACjC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC;YAC7B,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC;QACrD,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;CACF;AAED,8DAA8D;AAC9D,MAAM,OAAO,eAAe;IAC1B;;;;OAIG;IACH,YAAY,MAAc,EAAE,OAAe,EAAE,SAAiB;QAC5D,MAAM,MAAM,GAAG,iBAAiB,CAAC,MAAM,EAAE,OAAO,GAAG,CAAC,EAAE,SAAS,CAAC,CAAC;QACjE,IAAI,CAAC,WAAW,GAAG,IAAI,WAAW,CAAC,MAAM,GAAG,OAAO,EAAE,MAAM,CAAC,CAAC;IAC/D,CAAC;IAEO,WAAW,CAAc;IAEjC;;;OAGG;IACH,UAAU,CAAC,KAAmB;QAC5B,OAAO,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IAC5C,CAAC;CACF;AAED,iEAAiE;AACjE,MAAM,OAAO,kBAAkB;IAC7B;;;;OAIG;IACH,YAAY,MAAc,EAAE,OAAe,EAAE,SAAiB;QAC5D,MAAM,MAAM,GAAG,iBAAiB,CAAC,MAAM,EAAE,OAAO,GAAG,CAAC,EAAE,SAAS,CAAC,CAAC;QACjE,IAAI,CAAC,YAAY,GAAG,IAAI,WAAW,CAAC,MAAM,GAAG,OAAO,EAAE,MAAM,CAAC,CAAC;QAC9D,IAAI,CAAC,YAAY,GAAG,IAAI,WAAW,CAAC,MAAM,GAAG,OAAO,EAAE,MAAM,CAAC,CAAC;IAChE,CAAC;IAEO,YAAY,CAAc;IAC1B,YAAY,CAAc;IAElC;;;;OAIG;IACH,UAAU,CAAC,CAAe,EAAE,CAAe;QACzC,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5E,CAAC;CACF"}
|
package/dist/errors.d.ts
CHANGED
package/dist/errors.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAcA,qBAAa,UAAW,SAAQ,KAAK;gBAEjC,OAAO,EAAE,MAAM,EACf,IAAI,CAAC,EAAE,cAAc,EACrB,OAAO,CAAC,EAAE,iBAAiB;gBAEjB,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,cAAc;gBACtC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB;IAoBxD,IAAI,CAAC,EAAE,cAAc,CAAC;CACvB;AAED,oBAAY,cAAc;IACxB,YAAY,IAAA;IACZ,gBAAgB,IAAA;IAChB,iBAAiB,IAAA;IACjB,gBAAgB,IAAA;IAChB,UAAU,IAAA;
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAcA,qBAAa,UAAW,SAAQ,KAAK;gBAEjC,OAAO,EAAE,MAAM,EACf,IAAI,CAAC,EAAE,cAAc,EACrB,OAAO,CAAC,EAAE,iBAAiB;gBAEjB,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,cAAc;gBACtC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB;IAoBxD,IAAI,CAAC,EAAE,cAAc,CAAC;CACvB;AAED,oBAAY,cAAc;IACxB,YAAY,IAAA;IACZ,gBAAgB,IAAA;IAChB,iBAAiB,IAAA;IACjB,gBAAgB,IAAA;IAChB,UAAU,IAAA;IACV,iBAAiB,IAAA;CAClB;AAED,KAAK,iBAAiB,GAAG;IACvB,KAAK,CAAC,EAAE,GAAG,CAAC;CACb,CAAC"}
|
package/dist/errors.js
CHANGED
|
@@ -32,5 +32,6 @@ export var RadioErrorType;
|
|
|
32
32
|
RadioErrorType[RadioErrorType["UnsupportedDevice"] = 2] = "UnsupportedDevice";
|
|
33
33
|
RadioErrorType[RadioErrorType["UsbTransferError"] = 3] = "UsbTransferError";
|
|
34
34
|
RadioErrorType[RadioErrorType["TunerError"] = 4] = "TunerError";
|
|
35
|
+
RadioErrorType[RadioErrorType["DemodulationError"] = 5] = "DemodulationError";
|
|
35
36
|
})(RadioErrorType || (RadioErrorType = {}));
|
|
36
37
|
//# sourceMappingURL=errors.js.map
|
package/dist/errors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.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;AAEjC,MAAM,OAAO,UAAW,SAAQ,KAAK;IAQnC,YACE,OAAe,EACf,aAAkD,EAClD,OAA2B;QAE3B,KAAK,CACH,OAAO,EACP,OAAO,KAAK,SAAS;YACnB,CAAC,CAAC,OAAO;YACT,CAAC,CAAC,OAAO,aAAa,KAAK,QAAQ;
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.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;AAEjC,MAAM,OAAO,UAAW,SAAQ,KAAK;IAQnC,YACE,OAAe,EACf,aAAkD,EAClD,OAA2B;QAE3B,KAAK,CACH,OAAO,EACP,OAAO,KAAK,SAAS;YACnB,CAAC,CAAC,OAAO;YACT,CAAC,CAAC,OAAO,aAAa,KAAK,QAAQ;gBACjC,CAAC,CAAC,aAAa;gBACf,CAAC,CAAC,SAAS,CAChB,CAAC;QACF,IAAI,OAAO,aAAa,KAAK,QAAQ,EAAE,CAAC;YACtC,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;YAC1B,IAAI,CAAC,IAAI,GAAG,cAAc,cAAc,CAAC,aAAa,CAAC,EAAE,CAAC;QAC5D,CAAC;IACH,CAAC;IAED,IAAI,CAAkB;CACvB;AAED,MAAM,CAAN,IAAY,cAOX;AAPD,WAAY,cAAc;IACxB,mEAAY,CAAA;IACZ,2EAAgB,CAAA;IAChB,6EAAiB,CAAA;IACjB,2EAAgB,CAAA;IAChB,+DAAU,CAAA;IACV,6EAAiB,CAAA;AACnB,CAAC,EAPW,cAAc,KAAd,cAAc,QAOzB"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Player } from "../demod/player.js";
|
|
2
|
+
/** Options for the AudioPlayer constructor. */
|
|
3
|
+
export type PlayerOptions = {
|
|
4
|
+
/**
|
|
5
|
+
* A function that returns the AudioContext instance to use for the player.
|
|
6
|
+
* If not specified, the default AudioContext constructor is used.
|
|
7
|
+
*/
|
|
8
|
+
newAudioContext?: () => AudioContext;
|
|
9
|
+
};
|
|
10
|
+
/** A class to play a series of sample buffers at a constant rate using the Web Audio API. */
|
|
11
|
+
export declare class AudioPlayer implements Player {
|
|
12
|
+
private static OUT_RATE;
|
|
13
|
+
private static TIME_BUFFER;
|
|
14
|
+
constructor(options?: PlayerOptions);
|
|
15
|
+
private newAudioContext;
|
|
16
|
+
private lastPlayedAt;
|
|
17
|
+
private ac;
|
|
18
|
+
private gainNode;
|
|
19
|
+
private gain;
|
|
20
|
+
/**
|
|
21
|
+
* Queues the given samples for playing at the appropriate time.
|
|
22
|
+
* @param leftSamples The samples for the left speaker.
|
|
23
|
+
* @param rightSamples The samples for the right speaker.
|
|
24
|
+
*/
|
|
25
|
+
play(leftSamples: Float32Array, rightSamples: Float32Array): void;
|
|
26
|
+
/**
|
|
27
|
+
* Sets the volume for playing samples.
|
|
28
|
+
* @param volume The volume to set, between 0 and 1.
|
|
29
|
+
*/
|
|
30
|
+
setVolume(volume: number): void;
|
|
31
|
+
getVolume(): number;
|
|
32
|
+
get sampleRate(): number;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=audioplayer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audioplayer.d.ts","sourceRoot":"","sources":["../../src/players/audioplayer.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,+CAA+C;AAC/C,MAAM,MAAM,aAAa,GAAG;IAC1B;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,YAAY,CAAC;CACtC,CAAC;AAEF,6FAA6F;AAC7F,qBAAa,WAAY,YAAW,MAAM;IACxC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAS;IAChC,OAAO,CAAC,MAAM,CAAC,WAAW,CAAQ;gBAEtB,OAAO,CAAC,EAAE,aAAa;IASnC,OAAO,CAAC,eAAe,CAAqB;IAC5C,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,EAAE,CAA2B;IACrC,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,IAAI,CAAS;IAErB;;;;OAIG;IACH,IAAI,CAAC,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY;IAwB1D;;;OAGG;IACH,SAAS,CAAC,MAAM,EAAE,MAAM;IAOxB,SAAS,IAAI,MAAM;IAInB,IAAI,UAAU,IAAI,MAAM,CAGvB;CACF"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// Copyright 2013 Google Inc. 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 class to play a series of sample buffers at a constant rate using the Web Audio API. */
|
|
15
|
+
export class AudioPlayer {
|
|
16
|
+
static OUT_RATE = 48000;
|
|
17
|
+
static TIME_BUFFER = 0.05;
|
|
18
|
+
constructor(options) {
|
|
19
|
+
this.newAudioContext =
|
|
20
|
+
options?.newAudioContext || (() => new AudioContext());
|
|
21
|
+
this.lastPlayedAt = -1;
|
|
22
|
+
this.ac = undefined;
|
|
23
|
+
this.gainNode = undefined;
|
|
24
|
+
this.gain = 0;
|
|
25
|
+
}
|
|
26
|
+
newAudioContext;
|
|
27
|
+
lastPlayedAt;
|
|
28
|
+
ac;
|
|
29
|
+
gainNode;
|
|
30
|
+
gain;
|
|
31
|
+
/**
|
|
32
|
+
* Queues the given samples for playing at the appropriate time.
|
|
33
|
+
* @param leftSamples The samples for the left speaker.
|
|
34
|
+
* @param rightSamples The samples for the right speaker.
|
|
35
|
+
*/
|
|
36
|
+
play(leftSamples, rightSamples) {
|
|
37
|
+
if (this.ac === undefined || this.gainNode === undefined) {
|
|
38
|
+
this.ac = this.newAudioContext();
|
|
39
|
+
this.gainNode = this.ac.createGain();
|
|
40
|
+
this.gainNode.gain.value = this.gain;
|
|
41
|
+
this.gainNode.connect(this.ac.destination);
|
|
42
|
+
}
|
|
43
|
+
const buffer = this.ac.createBuffer(2, leftSamples.length, AudioPlayer.OUT_RATE);
|
|
44
|
+
buffer.getChannelData(0).set(leftSamples);
|
|
45
|
+
buffer.getChannelData(1).set(rightSamples);
|
|
46
|
+
let source = this.ac.createBufferSource();
|
|
47
|
+
source.buffer = buffer;
|
|
48
|
+
source.connect(this.gainNode);
|
|
49
|
+
this.lastPlayedAt = Math.max(this.lastPlayedAt + leftSamples.length / AudioPlayer.OUT_RATE, this.ac.currentTime + AudioPlayer.TIME_BUFFER);
|
|
50
|
+
source.start(this.lastPlayedAt);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Sets the volume for playing samples.
|
|
54
|
+
* @param volume The volume to set, between 0 and 1.
|
|
55
|
+
*/
|
|
56
|
+
setVolume(volume) {
|
|
57
|
+
this.gain = volume;
|
|
58
|
+
if (this.gainNode !== undefined) {
|
|
59
|
+
this.gainNode.gain.value = volume;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
getVolume() {
|
|
63
|
+
return this.gain;
|
|
64
|
+
}
|
|
65
|
+
get sampleRate() {
|
|
66
|
+
if (this.ac)
|
|
67
|
+
return this.ac.sampleRate;
|
|
68
|
+
return 48000;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=audioplayer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audioplayer.js","sourceRoot":"","sources":["../../src/players/audioplayer.ts"],"names":[],"mappings":"AAAA,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;AAajC,6FAA6F;AAC7F,MAAM,OAAO,WAAW;IACd,MAAM,CAAC,QAAQ,GAAG,KAAK,CAAC;IACxB,MAAM,CAAC,WAAW,GAAG,IAAI,CAAC;IAElC,YAAY,OAAuB;QACjC,IAAI,CAAC,eAAe;YAClB,OAAO,EAAE,eAAe,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,YAAY,EAAE,CAAC,CAAC;QACzD,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC;QACvB,IAAI,CAAC,EAAE,GAAG,SAAS,CAAC;QACpB,IAAI,CAAC,QAAQ,GAAG,SAAS,CAAC;QAC1B,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC;IAChB,CAAC;IAEO,eAAe,CAAqB;IACpC,YAAY,CAAS;IACrB,EAAE,CAA2B;IAC7B,QAAQ,CAAuB;IAC/B,IAAI,CAAS;IAErB;;;;OAIG;IACH,IAAI,CAAC,WAAyB,EAAE,YAA0B;QACxD,IAAI,IAAI,CAAC,EAAE,KAAK,SAAS,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YACzD,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;YACjC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,EAAE,CAAC,UAAU,EAAE,CAAC;YACrC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC;YACrC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC;QAC7C,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,YAAY,CACjC,CAAC,EACD,WAAW,CAAC,MAAM,EAClB,WAAW,CAAC,QAAQ,CACrB,CAAC;QACF,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAC1C,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QAC3C,IAAI,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,kBAAkB,EAAE,CAAC;QAC1C,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;QACvB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC9B,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,CAC1B,IAAI,CAAC,YAAY,GAAG,WAAW,CAAC,MAAM,GAAG,WAAW,CAAC,QAAQ,EAC7D,IAAI,CAAC,EAAE,CAAC,WAAW,GAAG,WAAW,CAAC,WAAW,CAC9C,CAAC;QACF,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAClC,CAAC;IAED;;;OAGG;IACH,SAAS,CAAC,MAAc;QACtB,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC;QACnB,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YAChC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC;QACpC,CAAC;IACH,CAAC;IAED,SAAS;QACP,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED,IAAI,UAAU;QACZ,IAAI,IAAI,CAAC,EAAE;YAAE,OAAO,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC;QACvC,OAAO,KAAK,CAAC;IACf,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** A message channel, in which messages are sent and received asynchronously. */
|
|
2
|
+
export declare class Channel<Msg> {
|
|
3
|
+
constructor();
|
|
4
|
+
/** Messages waiting to be delivered. */
|
|
5
|
+
private msgQueue;
|
|
6
|
+
/** Clients waiting to receive messages. */
|
|
7
|
+
private notifyQueue;
|
|
8
|
+
/**
|
|
9
|
+
* Sends a message.
|
|
10
|
+
*
|
|
11
|
+
* If there is a client waiting to receive a message, it is delivered straight to it.
|
|
12
|
+
* Otherwise, the message is added to the queue.
|
|
13
|
+
*/
|
|
14
|
+
send(msg: Msg): void;
|
|
15
|
+
/**
|
|
16
|
+
* Receives a message, returning a promise.
|
|
17
|
+
*
|
|
18
|
+
* If there is a message in the queue, the promise resolves to that message.
|
|
19
|
+
* Otherwise, the promise will resolve when a message is received.
|
|
20
|
+
*/
|
|
21
|
+
receive(): Promise<Msg>;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=msgqueue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"msgqueue.d.ts","sourceRoot":"","sources":["../../src/radio/msgqueue.ts"],"names":[],"mappings":"AAcA,iFAAiF;AACjF,qBAAa,OAAO,CAAC,GAAG;;IAMtB,wCAAwC;IACxC,OAAO,CAAC,QAAQ,CAAQ;IACxB,2CAA2C;IAC3C,OAAO,CAAC,WAAW,CAAyB;IAE5C;;;;;OAKG;IACH,IAAI,CAAC,GAAG,EAAE,GAAG;IASb;;;;;OAKG;IACH,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC;CAKxB"}
|