Metadata-Version: 2.4
Name: filejack
Version: 1.0.0
Summary: File encoding/decoding to audio signals.
Author: Staheos
License-Expression: MIT
Project-URL: Homepage, https://github.com/Staheos/FileJack
Project-URL: Source, https://github.com/Staheos/FileJack
Project-URL: Issues, https://github.com/Staheos/FileJack/issues
Keywords: file,audio,jack,encoder,decoder
Classifier: Development Status :: 3 - Alpha
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Operating System :: OS Independent
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.15.0
Requires-Dist: scipy>=1.0.0
Requires-Dist: reedsolo>=1.0.0
Provides-Extra: test
Requires-Dist: pytest>=8.0; extra == "test"
Requires-Dist: pytest-cov; extra == "test"
Requires-Dist: pytest-xdist[psutil]>=3.5; extra == "test"
Dynamic: license-file

# FileJack

File encoding/decoding to audio signals.

FileJack turns an arbitrary file into a WAV audio signal and back. The data is
carried on a 12 kHz carrier using differential 8-PSK modulation, protected with
Reed-Solomon error correction and a per-frame CRC. It is meant for sending files
over an audio link (for example a 3.5 mm jack cable or an acoustic channel).

## How it works

The encoder splits the input into frames. Each frame carries a header
(sequence number, total frame count, payload length), the payload and a CRC32,
then gets Reed-Solomon encoded into a 255-byte codeword (223 data bytes + 32
parity bytes, so up to 209 payload bytes per frame). Each codeword is mapped to
symbols and modulated onto the carrier, preceded by a preamble and a syncword so
the decoder can find frame boundaries.

The decoder demodulates the recording, locks onto the preamble/syncword,
recovers the symbols, runs Reed-Solomon correction and checks each frame's CRC.
Valid frames are collected by sequence number and reassembled into the original
file. Decoding runs across multiple threads over overlapping blocks, so partial
or noisy recordings still recover whatever frames are intact.

Signal parameters live in [filejack/values.py](filejack/values.py): 48 kHz
sample rate, 4000 baud, 12 kHz carrier, 8-PSK.

## Installation

```
pip install filejack
```

Or from source:

```
pip install .
```

Dependencies: numpy, scipy, reedsolo.

## Command line usage

Encoding writes a WAV file. By default it produces an anti-phase stereo signal
(the right channel is the inverted left channel), which lets the decoder cancel
common-mode noise by subtracting the channels.

```
filejack encode input.bin
filejack encode input.bin output.wav
filejack encode input.bin output.wav --mono
```

Decoding reads a WAV file and writes the reconstructed file. Stereo input is
folded down automatically.

```
filejack decode output.wav
filejack decode output.wav recovered.bin
```

Decode options:

- `--fjf PATH` also saves the decoded frames into a `.fjf` file. This lets you
  merge frames recovered from several recordings of the same transmission.
- `--threads N` sets the number of decoding threads (default 12).

The command is also available as `python -m filejack`.

## Library usage

```python
import zlib
from scipy.io import wavfile
import numpy as np

from filejack.encode_frames import encode_data
from filejack.decode_data import decode_data
from filejack.reconstruct_data import reconstruct_data
from filejack.values import SAMPLE_RATE

data = open("input.bin", "rb").read()

# Encode to samples and write a WAV
waveform = encode_data(data)
wavfile.write("output.wav", SAMPLE_RATE, waveform)

# Read a WAV and decode
fs, rx = wavfile.read("output.wav")
rx = rx.astype(np.float32)
if rx.ndim == 2:
	rx = (rx[:, 0] - rx[:, 1]) / 2

frames_payload, total_expected, stats = decode_data(rx)
recovered = reconstruct_data(frames_payload, total_expected)

assert zlib.crc32(recovered) == zlib.crc32(data)
```

More runnable scripts are in [filejack/examples](filejack/examples), including
`stereo_to_mono.py` for folding an anti-phase stereo recording down to mono.

## .fjf files

A `.fjf` (FileJack Frames) file stores decoded frames with their sequence
numbers. Because each frame is independent, you can decode the same
transmission several times, save each attempt to a `.fjf`, and merge them to
fill in frames that were missed in individual passes. See
[filejack/merge_frames.py](filejack/merge_frames.py) and the merge example.

## Development

```
pip install .[test]
pytest
```

## License

MIT. See [LICENSE](LICENSE).
