wsjtx-lib 1.0.1 → 1.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/README.md CHANGED
@@ -9,7 +9,7 @@ A high-performance Node.js C++ extension for digital amateur radio protocols, pr
9
9
  - 🔧 **TypeScript Support**: Full TypeScript definitions and modern ES modules
10
10
  - ⚡ **Async/Await**: Promise-based API for non-blocking operations
11
11
  - 🎵 **Audio Processing**: Support for both Float32Array and Int16Array audio formats
12
- - 🌍 **Cross-Platform**: Works on Windows, macOS, and Linux
12
+ - 🌍 **Cross-Platform**: Prebuilt binaries for Windows, macOS, and Linux
13
13
  - 📊 **WSPR Decoding**: Specialized support for WSPR IQ data processing
14
14
 
15
15
  ## Supported Modes
@@ -28,50 +28,86 @@ A high-performance Node.js C++ extension for digital amateur radio protocols, pr
28
28
 
29
29
  ## Installation
30
30
 
31
- ### Prerequisites
31
+ ### NPM Installation (Recommended)
32
+
33
+ The package includes prebuilt binaries for major platforms:
34
+
35
+ ```bash
36
+ npm install wsjtx-lib
37
+ ```
38
+
39
+ **Supported platforms with prebuilt binaries:**
40
+ - Linux x64
41
+ - macOS ARM64 (Apple Silicon)
42
+ - Windows x64
43
+
44
+ ### Building from Source
45
+
46
+ Only needed if prebuilt binaries are not available for your platform.
47
+
48
+ #### Prerequisites
32
49
 
33
50
  - Node.js 16+
34
51
  - CMake 3.15+
35
52
  - C++ compiler with C++17 support
36
- - FFTW3 library
53
+ - FFTW3 library (single precision)
37
54
  - Boost libraries
38
55
  - Fortran compiler (gfortran)
39
56
 
40
- ### macOS
57
+ #### macOS
41
58
 
42
59
  ```bash
43
60
  # Install dependencies using Homebrew
44
- brew install cmake fftw boost gcc
61
+ brew install cmake fftw boost gcc pkg-config
45
62
 
46
- # Clone and install
63
+ # Clone and build
47
64
  git clone --recursive https://github.com/boybook/wsjtx_lib_nodejs.git
48
- cd wsjtx-lib-nodejs
65
+ cd wsjtx_lib_nodejs
49
66
  npm install
67
+ npm run build
50
68
  ```
51
69
 
52
- ### Linux (Ubuntu/Debian)
70
+ #### Linux (Ubuntu/Debian)
53
71
 
54
72
  ```bash
55
73
  # Install dependencies
56
74
  sudo apt-get update
57
- sudo apt-get install cmake libfftw3-dev libboost-all-dev gfortran build-essential
58
-
59
- # Clone and install
75
+ sudo apt-get install -y \
76
+ cmake \
77
+ build-essential \
78
+ gfortran \
79
+ libfftw3-dev \
80
+ libboost-all-dev \
81
+ pkg-config
82
+
83
+ # Clone and build
60
84
  git clone --recursive https://github.com/boybook/wsjtx_lib_nodejs.git
61
- cd wsjtx-lib-nodejs
85
+ cd wsjtx_lib_nodejs
62
86
  npm install
87
+ npm run build
63
88
  ```
64
89
 
65
- ### Windows
90
+ #### Windows
66
91
 
67
- ```bash
68
- # Install dependencies using vcpkg or manually
69
- # Ensure CMake, FFTW3, Boost, and MinGW-w64 are available
92
+ Use MSYS2/MinGW-w64 for best compatibility:
70
93
 
71
- # Clone and install
94
+ ```bash
95
+ # Install MSYS2, then in MSYS2 MINGW64 terminal:
96
+ pacman -S --needed \
97
+ base-devel \
98
+ mingw-w64-x86_64-toolchain \
99
+ mingw-w64-x86_64-cmake \
100
+ mingw-w64-x86_64-pkg-config \
101
+ mingw-w64-x86_64-fftw \
102
+ mingw-w64-x86_64-boost \
103
+ mingw-w64-x86_64-gcc-fortran \
104
+ mingw-w64-x86_64-nodejs
105
+
106
+ # Clone and build
72
107
  git clone --recursive https://github.com/boybook/wsjtx_lib_nodejs.git
73
- cd wsjtx-lib-nodejs
108
+ cd wsjtx_lib_nodejs
74
109
  npm install
110
+ npm run build
75
111
  ```
76
112
 
77
113
  ## Quick Start
@@ -86,27 +122,27 @@ async function example() {
86
122
  // Encode an FT8 message
87
123
  const encodeResult = await lib.encode(
88
124
  WSJTXMode.FT8,
89
- 'CQ TEST K1ABC FN20',
90
- 1000 // Audio base frequency in Hz (typically 500-3000 Hz)
125
+ 'CQ DX BH1ABC OM88',
126
+ 1000 // Audio frequency in Hz (typically 500-3000 Hz)
91
127
  );
92
128
 
93
129
  console.log(`Generated ${encodeResult.audioData.length} audio samples`);
94
- console.log(`Message: "${encodeResult.messageSent}"`);
130
+ console.log(`Message sent: "${encodeResult.messageSent}"`);
95
131
 
96
- // Decode audio data
132
+ // Decode audio data (example with proper resampling for FT8)
97
133
  const audioData = new Float32Array(48000 * 13); // 13 seconds at 48kHz
98
134
  // ... fill audioData with actual audio samples ...
99
135
 
100
136
  const decodeResult = await lib.decode(
101
137
  WSJTXMode.FT8,
102
138
  audioData,
103
- 1000 // Same audio base frequency used for encoding
139
+ 1000 // Same audio frequency used for encoding
104
140
  );
105
141
 
106
142
  // Get decoded messages
107
143
  const messages = lib.pullMessages();
108
144
  messages.forEach(msg => {
109
- console.log(`Decoded: "${msg.text}" (SNR: ${msg.snr} dB)`);
145
+ console.log(`Decoded: "${msg.text}" (SNR: ${msg.snr} dB, ΔT: ${msg.deltaTime}s)`);
110
146
  });
111
147
  }
112
148
  ```
@@ -137,11 +173,13 @@ Decode digital radio signals from audio data.
137
173
  **Parameters:**
138
174
  - `mode`: WSJTXMode enum value
139
175
  - `audioData`: Float32Array or Int16Array of audio samples
140
- - `frequency`: Audio base frequency in Hz (typically 500-3000 Hz for FT8)
176
+ - `frequency`: Audio frequency in Hz (typically 500-3000 Hz)
141
177
  - `threads`: Number of threads to use (optional, default: 4)
142
178
 
143
179
  **Returns:** Promise resolving to DecodeResult with success status
144
180
 
181
+ **Note:** For optimal FT8 decoding, audio may need resampling. See examples for details.
182
+
145
183
  ##### `encode(mode, message, frequency, threads?): Promise<EncodeResult>`
146
184
 
147
185
  Encode a message into audio waveform for transmission.
@@ -149,7 +187,7 @@ Encode a message into audio waveform for transmission.
149
187
  **Parameters:**
150
188
  - `mode`: WSJTXMode enum value
151
189
  - `message`: Message text to encode (1-22 characters)
152
- - `frequency`: Audio base frequency in Hz (typically 500-3000 Hz for FT8)
190
+ - `frequency`: Audio frequency in Hz (typically 500-3000 Hz)
153
191
  - `threads`: Number of threads to use (optional, default: 4)
154
192
 
155
193
  **Returns:** Promise resolving to EncodeResult with audio data and actual message sent
@@ -161,6 +199,13 @@ Decode WSPR signals from IQ data.
161
199
  **Parameters:**
162
200
  - `iqData`: Float32Array of interleaved I,Q samples
163
201
  - `options`: WSPRDecodeOptions (optional)
202
+ - `dialFrequency`: RF dial frequency in Hz (default: 14095600)
203
+ - `callsign`: Station callsign
204
+ - `locator`: Grid locator
205
+ - `quickMode`: Enable quick decode mode (default: false)
206
+ - `useHashTable`: Use hash table optimization (default: true)
207
+ - `passes`: Number of decode passes (default: 2)
208
+ - `subtraction`: Enable signal subtraction (default: true)
164
209
 
165
210
  **Returns:** Promise resolving to array of WSPR decode results
166
211
 
@@ -208,8 +253,6 @@ interface WSJTXMessage {
208
253
  snr: number; // Signal-to-noise ratio in dB
209
254
  deltaTime: number; // Time offset in seconds
210
255
  deltaFrequency: number; // Frequency offset in Hz
211
- timestamp: number; // Unix timestamp
212
- sync: number; // Sync quality metric
213
256
  }
214
257
  ```
215
258
 
@@ -217,7 +260,7 @@ interface WSJTXMessage {
217
260
 
218
261
  ```typescript
219
262
  interface EncodeResult {
220
- audioData: Float32Array; // Generated audio waveform
263
+ audioData: Float32Array; // Generated audio waveform (48kHz sample rate)
221
264
  messageSent: string; // Actual message encoded
222
265
  }
223
266
  ```
@@ -242,51 +285,90 @@ interface WSPRResult {
242
285
 
243
286
  ## Examples
244
287
 
245
- ### Basic FT8 Encoding and Decoding
288
+ ### Complete FT8 Encode-Decode Cycle
246
289
 
247
290
  ```typescript
248
291
  import { WSJTXLib, WSJTXMode } from 'wsjtx-lib';
292
+ import * as fs from 'fs';
293
+ import * as wav from 'wav';
249
294
 
250
- const lib = new WSJTXLib();
251
-
252
- // Encode a message
253
- const result = await lib.encode(WSJTXMode.FT8, 'CQ DX K1ABC FN20', 1500);
254
- console.log(`Audio samples: ${result.audioData.length}`);
255
-
256
- // Decode audio (replace with actual audio data)
257
- const audioData = new Float32Array(48000 * 13);
258
- const decodeResult = await lib.decode(WSJTXMode.FT8, audioData, 1500);
295
+ async function ft8Example() {
296
+ const lib = new WSJTXLib();
297
+ const message = 'CQ DX BH1ABC OM88';
298
+ const audioFrequency = 1000;
299
+
300
+ // 1. Encode message
301
+ const encodeResult = await lib.encode(WSJTXMode.FT8, message, audioFrequency);
302
+ console.log(`Encoded: "${encodeResult.messageSent}"`);
303
+
304
+ // 2. Save as WAV file
305
+ const audioInt16 = new Int16Array(encodeResult.audioData.length);
306
+ for (let i = 0; i < encodeResult.audioData.length; i++) {
307
+ audioInt16[i] = Math.round(encodeResult.audioData[i] * 32767);
308
+ }
309
+
310
+ const writer = new wav.FileWriter('ft8_test.wav', {
311
+ channels: 1,
312
+ sampleRate: lib.getSampleRate(WSJTXMode.FT8),
313
+ bitDepth: 16
314
+ });
315
+
316
+ const buffer = Buffer.from(audioInt16.buffer);
317
+ writer.write(buffer);
318
+ writer.end();
319
+
320
+ // 3. Read back and decode
321
+ // Note: For optimal decode, you may need resampling
322
+ const resampled = resampleTo12kHz(encodeResult.audioData);
323
+ const audioForDecode = new Int16Array(resampled.length);
324
+ for (let i = 0; i < resampled.length; i++) {
325
+ audioForDecode[i] = Math.round(resampled[i] * 32767);
326
+ }
327
+
328
+ lib.pullMessages(); // Clear queue
329
+ const decodeResult = await lib.decode(WSJTXMode.FT8, audioForDecode, audioFrequency);
330
+
331
+ const messages = lib.pullMessages();
332
+ console.log(`Decoded ${messages.length} messages`);
333
+ }
259
334
 
260
- // Get messages
261
- const messages = lib.pullMessages();
262
- console.log(`Found ${messages.length} messages`);
335
+ // Helper function for resampling (48kHz -> 12kHz)
336
+ function resampleTo12kHz(audioData48k: Float32Array): Float32Array {
337
+ const audioData12k = new Float32Array(Math.floor(audioData48k.length / 4));
338
+ for (let i = 0; i < audioData12k.length; i++) {
339
+ audioData12k[i] = audioData48k[i * 4];
340
+ }
341
+ return audioData12k;
342
+ }
263
343
  ```
264
344
 
265
- > **Important Note**: The `frequency` parameter is the **audio base frequency** (typically 500-3000 Hz), not the RF frequency. For example, if you're operating on 20m FT8 (14.074 MHz RF), you might use 1500 Hz as the audio frequency within your transceiver's passband.
266
-
267
345
  ### WSPR Decoding
268
346
 
269
347
  ```typescript
270
348
  import { WSJTXLib } from 'wsjtx-lib';
271
349
 
272
- const lib = new WSJTXLib();
273
-
274
- // IQ data (interleaved I,Q samples)
275
- const iqData = new Float32Array(2 * 12000 * 120); // 2 minutes
276
- // ... fill with actual IQ data ...
277
-
278
- const options = {
279
- dialFrequency: 14095600, // RF dial frequency for WSPR (this is different from audio frequency)
280
- callsign: 'K1ABC',
281
- locator: 'FN20',
282
- quickMode: false,
283
- passes: 2
284
- };
285
-
286
- const results = await lib.decodeWSPR(iqData, options);
287
- results.forEach(result => {
288
- console.log(`${result.callsign} ${result.locator} ${result.power}dBm`);
289
- });
350
+ async function wsprExample() {
351
+ const lib = new WSJTXLib();
352
+
353
+ // IQ data (interleaved I,Q samples)
354
+ const iqData = new Float32Array(2 * 12000 * 120); // 2 minutes of IQ data
355
+ // ... fill with actual IQ data from SDR ...
356
+
357
+ const options = {
358
+ dialFrequency: 14095600, // 20m WSPR frequency
359
+ callsign: 'BH1ABC',
360
+ locator: 'OM88',
361
+ quickMode: false,
362
+ passes: 2
363
+ };
364
+
365
+ const results = await lib.decodeWSPR(iqData, options);
366
+
367
+ console.log('WSPR Decode Results:');
368
+ results.forEach(result => {
369
+ console.log(`${result.callsign} ${result.locator} ${result.power}dBm (SNR: ${result.snr}dB)`);
370
+ });
371
+ }
290
372
  ```
291
373
 
292
374
  ### Audio Format Conversion
@@ -295,11 +377,37 @@ results.forEach(result => {
295
377
  import { WSJTXLib } from 'wsjtx-lib';
296
378
 
297
379
  // Convert Float32Array to Int16Array
298
- const floatData = new Float32Array([0.5, -0.5, 0.25]);
380
+ const floatData = new Float32Array([0.5, -0.5, 0.25, -0.25]);
299
381
  const intData = WSJTXLib.convertAudioFormat(floatData, 'int16');
382
+ console.log(intData); // Int16Array [16384, -16384, 8192, -8192]
300
383
 
301
384
  // Convert back to Float32Array
302
385
  const backToFloat = WSJTXLib.convertAudioFormat(intData, 'float32');
386
+ console.log(backToFloat); // Float32Array [0.5, -0.5, 0.25, -0.25] (approximately)
387
+ ```
388
+
389
+ ### Multiple Message Types
390
+
391
+ ```typescript
392
+ import { WSJTXLib, WSJTXMode } from 'wsjtx-lib';
393
+
394
+ async function multipleMessages() {
395
+ const lib = new WSJTXLib();
396
+ const audioFrequency = 1000;
397
+
398
+ const messages = [
399
+ 'CQ DX BH1ABC OM88', // CQ call
400
+ 'BH1ABC BH2DEF +05', // Signal report
401
+ 'BH2DEF BH1ABC R-12', // Report acknowledgment
402
+ 'BH1ABC BH2DEF RRR', // Received acknowledgment
403
+ 'BH2DEF BH1ABC 73' // End contact
404
+ ];
405
+
406
+ for (const message of messages) {
407
+ const result = await lib.encode(WSJTXMode.FT8, message, audioFrequency);
408
+ console.log(`"${message}" -> "${result.messageSent}" (${result.audioData.length} samples)`);
409
+ }
410
+ }
303
411
  ```
304
412
 
305
413
  ## Error Handling
@@ -310,22 +418,44 @@ The library throws `WSJTXError` for all operation failures:
310
418
  import { WSJTXError } from 'wsjtx-lib';
311
419
 
312
420
  try {
313
- await lib.decode(WSJTXMode.FT8, audioData, 1500);
421
+ await lib.decode(WSJTXMode.FT8, audioData, 1000);
314
422
  } catch (error) {
315
423
  if (error instanceof WSJTXError) {
316
424
  console.error(`WSJTX Error [${error.code}]: ${error.message}`);
425
+
426
+ // Common error codes:
427
+ // - INVALID_MODE: Invalid mode parameter
428
+ // - INVALID_FREQUENCY: Invalid frequency parameter
429
+ // - INVALID_AUDIO_DATA: Invalid audio data format/size
430
+ // - INVALID_MESSAGE: Invalid message text
431
+ // - DECODE_ERROR: Decoding operation failed
432
+ // - ENCODE_ERROR: Encoding operation failed
317
433
  } else {
318
434
  console.error('Unexpected error:', error);
319
435
  }
320
436
  }
321
437
  ```
322
438
 
323
- ## Building from Source
439
+ ## Important Notes
440
+
441
+ 1. **Audio Frequency**: The `frequency` parameter is the audio tone frequency within your audio passband (typically 500-3000 Hz), not the RF frequency.
442
+
443
+ 2. **Sample Rates**: Different modes require different sample rates. Use `lib.getSampleRate(mode)` to get the correct rate.
444
+
445
+ 3. **Audio Resampling**: For optimal FT8 decoding, audio may need to be resampled from 48kHz to 12kHz. See examples for implementation.
446
+
447
+ 4. **Thread Safety**: Each WSJTXLib instance should be used from a single thread. Create separate instances for concurrent operations.
448
+
449
+ 5. **Message Queue**: The `pullMessages()` method clears the internal message queue. Call it regularly to avoid memory buildup.
450
+
451
+ ## Building from Source (Advanced)
452
+
453
+ For detailed build instructions when prebuilt binaries are not available, see [BUILD.md](BUILD.md).
324
454
 
325
455
  ```bash
326
456
  # Clone with submodules
327
- git clone --recursive https://github.com/your-repo/wsjtx-lib-nodejs.git
328
- cd wsjtx-lib-nodejs
457
+ git clone --recursive https://github.com/boybook/wsjtx_lib_nodejs.git
458
+ cd wsjtx_lib_nodejs
329
459
 
330
460
  # Install dependencies
331
461
  npm install
@@ -336,8 +466,11 @@ npm run build
336
466
  # Run tests
337
467
  npm test
338
468
 
339
- # Run example
340
- node examples/basic_usage.js
469
+ # Run comprehensive tests
470
+ npm run test:full
471
+
472
+ # Run examples
473
+ node examples/examples.js
341
474
  ```
342
475
 
343
476
  ## Development
@@ -345,13 +478,14 @@ node examples/basic_usage.js
345
478
  ### Project Structure
346
479
 
347
480
  ```
348
- wsjtx-lib-nodejs/
481
+ wsjtx_lib_nodejs/
349
482
  ├── src/ # TypeScript source files
350
483
  ├── native/ # C++ wrapper code
351
- ├── wsjtx_lib/ # Git submodule (wsjtx_lib C library)
484
+ ├── wsjtx_lib/ # Git submodule (wsjtx_lib library)
352
485
  ├── test/ # Test files
353
486
  ├── examples/ # Usage examples
354
487
  ├── dist/ # Compiled TypeScript output
488
+ ├── prebuilds/ # Prebuilt binaries for distribution
355
489
  └── build/ # CMake build directory
356
490
  ```
357
491
 
@@ -360,8 +494,10 @@ wsjtx-lib-nodejs/
360
494
  - `npm run build` - Build both native module and TypeScript
361
495
  - `npm run build:native` - Build only the native C++ module
362
496
  - `npm run build:ts` - Build only TypeScript
363
- - `npm test` - Run all tests
497
+ - `npm test` - Run basic tests (CI-friendly)
498
+ - `npm run test:full` - Run comprehensive tests
364
499
  - `npm run clean` - Clean build artifacts
500
+ - `npm run package` - Package prebuilt binaries for distribution
365
501
 
366
502
  ## Contributing
367
503
 
@@ -374,17 +510,10 @@ wsjtx-lib-nodejs/
374
510
 
375
511
  ## License
376
512
 
377
- This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
513
+ This project is licensed under the GPL-3.0 License - see the [LICENSE](LICENSE) file for details.
378
514
 
379
515
  ## Acknowledgments
380
516
 
381
- - Based on the excellent [wsjtx_lib](https://github.com/original-repo/wsjtx_lib) C library
382
- - WSJT-X development team for the original algorithms
383
- - Amateur radio community for protocol specifications
384
-
385
- ## Support
386
-
387
- - 📧 Email: support@example.com
388
- - 🐛 Issues: [GitHub Issues](https://github.com/your-repo/wsjtx-lib-nodejs/issues)
389
- - 📖 Documentation: [Wiki](https://github.com/your-repo/wsjtx-lib-nodejs/wiki)
390
- - 💬 Discussions: [GitHub Discussions](https://github.com/your-repo/wsjtx-lib-nodejs/discussions)
517
+ - Based on the excellent [wsjtx_lib](https://github.com/paulh002/wsjtx_lib) library by PA0PHH
518
+ - WSJT-X development team for the original algorithms by K1JT
519
+ - Amateur radio community for protocol specifications
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wsjtx-lib",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Node.js C++ extension for WSJTX digital radio protocol library",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",
@@ -29,7 +29,7 @@
29
29
  "scripts": {
30
30
  "prebuild": "prebuild-install",
31
31
  "build": "npm run build:native && npm run build:ts",
32
- "build:dev": "npm run build:native && npm run build:ts",
32
+ "build:win": "npm run build:native:win && npm run build:ts",
33
33
  "build:native": "cmake-js compile",
34
34
  "build:native:win": "cmake-js compile --generator=\"MinGW Makefiles\"",
35
35
  "build:ts": "tsc",
@@ -1,5 +1,5 @@
1
1
  {
2
- "timestamp": "2025-06-05T11:40:53.134Z",
2
+ "timestamp": "2025-06-06T01:33:39.094Z",
3
3
  "platforms": [
4
4
  {
5
5
  "platform": "linux",