Metadata-Version: 2.4
Name: wavcore
Version: 2.0.1
Summary: Ultra-fast lossless voice codec — real-time recording, VTXT text serialization, and bit-perfect reconstruction with a C engine.
License-Expression: MIT
Project-URL: Homepage, https://github.com/Zyro-Hub/wavecore
Project-URL: Source, https://github.com/Zyro-Hub/wavecore
Project-URL: Issues, https://github.com/Zyro-Hub/wavecore/issues
Keywords: audio,codec,voice,recording,lossless,real-time
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: C
Classifier: Topic :: Multimedia :: Sound/Audio
Classifier: Topic :: Multimedia :: Sound/Audio :: Capture/Recording
Classifier: Topic :: Multimedia :: Sound/Audio :: Conversion
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Requires-Dist: numpy>=1.21.0
Requires-Dist: sounddevice>=0.4.5
Requires-Dist: cffi>=1.15.0
Provides-Extra: dev
Requires-Dist: matplotlib>=3.5.0; extra == "dev"
Requires-Dist: scipy>=1.7.0; extra == "dev"

# WavCore

> **Ultra-fast, lossless real-time voice codec powered by a C engine**

**WavCore** is a Python package for recording, serializing, transmitting, and reconstructing voice audio with **bit-perfect precision**. It converts microphone audio into a human-readable text format called **VTXT** (`.vtxt`), making voice easy to store, inspect, sync, and send through any text-friendly system.

Created by **Prashant Pandey**
Repository: https://github.com/Zyro-Hub/wavecore
PyPI: https://pypi.org/project/wavcore/

---

## What's New in 2.0.0

- **Live Mode** (`wavcore.live_record`) — encodes and writes each frame to `.vtxt` in real-time while you speak. The file grows on disk live. Press ENTER to stop.
- **Normal Mode** (`wavcore.record`) — records full audio first, then encodes all at once (existing batch behaviour).
- **File Mode** (`file_to_vtxt`) — convert **any existing audio file** (WAV, FLAC, OGG, MP3…) to `.vtxt` **without a microphone**.
- **Direct Convert** (`convert_audio`) — convert any audio file straight to WAV in **one call** — no microphone, no manual vtxt step.
- `app.py` now shows a 3-option mode selection menu on startup.

---

## What WavCore Does

WavCore captures microphone audio, splits it into small 20ms frames, converts each frame into hexadecimal text with a CRC-32 checksum, and stores everything as a `.vtxt` file.

That means you can:

- Record voice locally and replay it perfectly
- Send voice over HTTP, WebSocket, Firebase, or any database
- Reconstruct the original audio anywhere, anytime
- Verify every frame for corruption with CRC-32

---

## Key Features

| Feature | Detail |
|---|---|
| **Lossless** | IEEE-754 hex encoding — zero float precision loss |
| **C engine** | `cffi`-compiled .pyd — 1326× faster than real-time |
| **Live mode** | Writes `.vtxt` frame-by-frame while speaking |
| **Normal mode** | Batch encode after full capture |
| **File mode** | Convert existing audio file → `.vtxt` — no mic needed |
| **Direct convert** | `convert_audio()` — audio file → WAV in one call |
| **CRC-32** | Per-frame integrity check |
| **Gap handling** | Missing frames → silence during decode |
| **Pure-Python fallback** | Works without native build |
| **Text transport** | Works with Firebase, SQLite, HTTP, WebSocket |

---

## Installation

```bash
pip install wavcore==2.0.0 .
```

Auto-installs: `numpy`, `sounddevice`, `cffi`
The C engine is compiled during install. No extra steps.

### Development (editable) Install

```bash
pip install -e .
```

### Verify

```python
import wavcore
print(wavcore.__version__)    # 2.0.0
print(wavcore.engine_info())  # C engine [cffi / MSVC 64-bit .pyd]  — ultra-fast
```

---

## Quick Start

```python
import wavcore
from recorder_converter import file_to_vtxt, convert_audio

# Normal mode — record 10s from mic, then encode
wavcore.record("audio.vtxt", "original.wav", duration=10)

# Live mode — write frames to .vtxt in real-time while speaking
wavcore.live_record("audio.vtxt", "original.wav", max_duration=60)

# File mode — convert an existing audio file to .vtxt (no mic)
file_to_vtxt("my_song.wav", "audio.vtxt")

# Direct convert — audio file → WAV in ONE call (no mic, no manual steps)
convert_audio("my_song.wav", "output.wav", play=True)

# Convert any .vtxt file → WAV (+ optional playback)
wavcore.decode("audio.vtxt", "reconstructed.wav", play=True)

# Check active engine
print(wavcore.engine_info())
```

---

## Running the Demo

```bash
python app.py
```

```
  ┌────────────────────────────────────────────────────────┐
  │  [1]  NORMAL MODE                                      │
  │       Record mic audio, encode all at once to .vtxt.   │
  │                                                        │
  │  [2]  LIVE MODE                                        │
  │       Each frame encoded + written to .vtxt live       │
  │       while you speak. Press ENTER to stop early.      │
  │                                                        │
  │  [3]  FILE MODE                                        │
  │       Convert an existing audio file (WAV/FLAC/OGG)    │
  │       to .vtxt — no microphone needed.                 │
  └────────────────────────────────────────────────────────┘

  Enter 1, 2 or 3:
```

All three modes produce a `.vtxt` file compatible with the same decode + playback step.

---

## Full Public API Reference

### Summary Table

| Function | Mode | Description |
|---|---|---|
| `wavcore.record()` | Normal | Record full audio from mic, encode to `.vtxt` |
| `wavcore.live_record()` | **Live** | Encode + write each frame live while speaking |
| `file_to_vtxt()` | **File** | Existing audio file → `.vtxt` (no mic needed) |
| `convert_audio()` | **Direct** | Audio file → WAV in one call (no mic, no manual vtxt) |
| `wavcore.decode()` | Decode | Any `.vtxt` → WAV + optional playback |
| `wavcore.engine_info()` | Info | Show active C engine tier |
| `wavcore.batch_encode()` | Low-level | `float32` array → list of hex strings |
| `wavcore.batch_decode()` | Low-level | List of hex strings → `float32` array |
| `wavcore.compute_frame_crc()` | Low-level | Compute CRC-32 for one frame |

---

### `wavcore.record()`

Record a fixed duration from the microphone. All encoding happens **after** capture in one fast batch call.

```python
stats = wavcore.record(
    vtxt_path   = "audio.vtxt",   # required — output .vtxt path
    orig_wav    = "original.wav", # optional — ground-truth WAV  (default "original.wav")
    duration    = 10,             # optional — seconds to record (default 10)
    sample_rate = 48_000,         # optional — Hz                (default 48000)
    frame_ms    = 20,             # optional — frame size in ms  (default 20)
)
```

**Pipeline:**
```
Mic → capture all audio → C batch_encode() → C CRC-32 per frame → write .vtxt
```

**Returns:**

```python
{
    "frames":        500,           # frames written
    "duration_ms":   10000.0,       # ms
    "sample_rate":   48000,
    "channels":      1,
    "peak":          0.518646,      # 0.0–1.0
    "rms":           0.055205,
    "vtxt_path":     "audio.vtxt",
    "orig_wav_path": "original.wav",
    "created_unix":  1745123456,
    "vtxt_size":     3942506,       # bytes
    "encode_ms":     35.2,          # total encode time
}
```

**Example:**

```python
import wavcore

stats = wavcore.record("voice.vtxt", "voice_orig.wav", duration=5)

print(f"Recorded : {stats['frames']} frames")
print(f"Duration : {stats['duration_ms'] / 1000:.1f} s")
print(f"Peak     : {stats['peak']:.4f}")
print(f"File     : {stats['vtxt_size']:,} bytes")
```

---

### `wavcore.live_record()`

**NEW in 2.0.0** — Records from the microphone and writes each 20ms frame to `.vtxt` **in real-time** as audio arrives. The file grows on disk while you speak. Press **ENTER** to stop early.

```python
stats = wavcore.live_record(
    vtxt_path    = "audio.vtxt",   # required — output .vtxt path
    orig_wav     = "original.wav", # optional — ground-truth WAV   (default "original.wav")
    max_duration = 60,             # optional — max seconds        (default 60)
    sample_rate  = 48_000,         # optional — Hz                 (default 48000)
    frame_ms     = 20,             # optional — frame size in ms   (default 20)
)
```

**Pipeline (per frame, every 20ms):**
```
Mic callback → queue → C batch_encode() → C CRC-32 → write [FRAME] → f.flush()
```

**Key difference from `record()`:**

| | `record()` | `live_record()` |
|---|---|---|
| When is .vtxt written? | After full capture | Every 20ms frame |
| Can you stop early? | No | Yes — press ENTER |
| Duration | Fixed | Up to `max_duration` |
| File visible on disk | Only after done | Grows in real-time |

**Returns:** Same dict shape as `record()`.

**Example:**

```python
import wavcore

# Record up to 2 minutes, stop early by pressing ENTER
stats = wavcore.live_record(
    vtxt_path    = "live_voice.vtxt",
    orig_wav     = "live_orig.wav",
    max_duration = 120,
)

print(f"Recorded : {stats['frames']} frames  ({stats['duration_ms']/1000:.1f} s)")
print(f"File     : {stats['vtxt_size']:,} bytes")
```

**Live progress output while recording:**
```
  [LIVE] Frame     47  |  0.9s  |  45.2 KB
```
You can open `live_voice.vtxt` in a text editor while recording — frames appear in real-time.

---

### `file_to_vtxt()` — **NEW in 2.0.0**

Convert **any existing audio file** to `.vtxt` using the C engine — **no microphone required**.

This is the function to use when you already have an audio file and want to encode it into the VTXT format.

```python
from recorder_converter import file_to_vtxt

stats = file_to_vtxt(
    audio_path  = "song.wav",       # required — input audio file
    vtxt_path   = "song.vtxt",      # required — output .vtxt path
    sample_rate = 48_000,           # optional — target Hz    (default 48000)
    frame_ms    = 20,               # optional — frame size   (default 20ms)
)
```

**Supported input formats:**

| Format | Requirement |
|---|---|
| `.wav` | Built-in — no extra install |
| `.flac` `.ogg` `.aiff` | `pip install soundfile` |
| `.mp3` | `pip install soundfile` + libsndfile with MP3 support |

**Pipeline:**
```
audio file → read → mono mix → resample if needed
          → C batch_encode() → C CRC-32 per frame → write .vtxt
```

**Returns:**

```python
{
    "frames":       500,              # frames written
    "duration_ms":  10000.0,          # ms
    "sample_rate":  48000,
    "channels":     1,
    "peak":         0.724518,         # 0.0–1.0
    "rms":          0.182350,
    "vtxt_path":    "song.vtxt",
    "source_file":  "/path/to/song.wav",  # absolute path of input
    "created_unix": 1745123456,
    "vtxt_size":    3942506,          # bytes
    "encode_ms":    42.1,
}
```

**Examples:**

```python
from recorder_converter import file_to_vtxt
import wavcore

# ── WAV file → .vtxt → decode + play ──────────────────────
file_to_vtxt("recording.wav", "recording.vtxt")
wavcore.decode("recording.vtxt", "output.wav", play=True)

# ── FLAC file (needs: pip install soundfile) ───────────────
file_to_vtxt("vocals.flac", "vocals.vtxt", sample_rate=44_100)
wavcore.decode("vocals.vtxt", "vocals_recon.wav", play=False)

# ── Check stats ────────────────────────────────────────────
stats = file_to_vtxt("interview.wav", "interview.vtxt")
print(f"Encoded {stats['frames']} frames ({stats['duration_ms']/1000:.1f}s)")
print(f"File size: {stats['vtxt_size']:,} bytes")
print(f"Took: {stats['encode_ms']:.1f} ms")
```

**How it handles different sample rates:**

If the source file has a different sample rate than `sample_rate`, the audio is resampled automatically:
- Uses `scipy.signal.resample_poly` if scipy is installed (high quality)
- Falls back to numpy linear interpolation if not

```python
# Source WAV is 44100 Hz, target is 48000 Hz — resampled automatically
file_to_vtxt("cd_audio.wav", "cd_audio.vtxt", sample_rate=48_000)
```

**Note:** The `.vtxt` produced by `file_to_vtxt()` is fully compatible with `wavcore.decode()`. The header will contain `SOURCE_FILE` and `RECORD_MODE=FILE` fields.

---

### `convert_audio()` — Direct Audio Conversion

The **simplest way** to convert any audio file to WAV using the WavCore pipeline. One function call — no microphone, no manual steps.

Internally it calls `file_to_vtxt()` then `vtxt_to_wav()` and optionally deletes the intermediate `.vtxt`.

```python
from recorder_converter import convert_audio

stats = convert_audio(
    audio_path  = "song.wav",        # required — input audio file
    output_wav  = "output.wav",      # required — output WAV path
    sample_rate = 48_000,            # optional — target Hz      (default 48000)
    frame_ms    = 20,                # optional — frame size ms  (default 20)
    play        = False,             # optional — play after done (default False)
    keep_vtxt   = False,             # optional — keep .vtxt?    (default False)
    vtxt_path   = None,              # optional — custom .vtxt path (auto if None)
)
```

**Pipeline:**
```
audio_path  →  file_to_vtxt()  →  temp_vtxt
            →  vtxt_to_wav()   →  output_wav
            →  (delete temp_vtxt if keep_vtxt=False)
```

**Returns:**

```python
{
    "encode":        { ...file_to_vtxt stats... },
    "decode":        { ...vtxt_to_wav stats... },
    "vtxt_path":     "output_temp.vtxt",   # intermediate vtxt (deleted if keep_vtxt=False)
    "output_wav":    "output.wav",
    "duration_s":    10.0,
    "integrity_pct": 100.0,
    "peak":          0.724518,
    "rms":           0.182350,
}
```

**Examples:**

```python
from recorder_converter import convert_audio

# ── Simplest use — WAV in, WAV out ────────────────────────────
convert_audio("recording.wav", "output.wav")

# ── Play the result immediately ───────────────────────────────
convert_audio("interview.wav", "interview_clean.wav", play=True)

# ── Keep the .vtxt too (for inspection or re-use) ─────────────
stats = convert_audio(
    audio_path = "song.flac",          # FLAC needs: pip install soundfile
    output_wav = "song_out.wav",
    keep_vtxt  = True,
    vtxt_path  = "song_encoded.vtxt",  # save .vtxt here
)
print(f"Duration : {stats['duration_s']:.1f}s")
print(f"Integrity: {stats['integrity_pct']:.2f}%")

# ── Check encode + decode stats separately ────────────────────
print(f"Frames encoded : {stats['encode']['frames']}")
print(f"Frames valid   : {stats['decode']['ok_frames']}")
print(f"Total encode   : {stats['encode']['encode_ms']:.1f} ms")
print(f"Total decode   : {stats['decode']['total_ms']:.1f} ms")
```

**Comparison — two ways to do the same thing:**

```python
# ❌ Manual (3 steps)
from recorder_converter import file_to_vtxt, vtxt_to_wav
file_to_vtxt("song.wav", "song.vtxt")
vtxt_to_wav("song.vtxt", "output.wav", play_audio=True)
import os; os.remove("song.vtxt")

# ✅ Direct (1 step)
from recorder_converter import convert_audio
convert_audio("song.wav", "output.wav", play=True)
```

---

### `wavcore.decode()`

Convert **any** `.vtxt` file into a WAV file, with optional playback. Works with files from both `record()` and `live_record()`.

```python
stats = wavcore.decode(
    vtxt_path  = "audio.vtxt",        # required — input .vtxt file
    output_wav = "reconstructed.wav", # optional — output WAV path (default "reconstructed.wav")
    play       = True,                # optional — play after decode (default True)
)
```

**Pipeline:**
```
.vtxt → parse [FRAME] blocks → C batch_decode() → C CRC-32 verify
      → gap detection (silence for missing frames) → save WAV → play
```

**Returns:**

```python
{
    "ok_frames":     500,             # frames with valid CRC
    "bad_frames":    0,               # corrupted or missing frames
    "integrity_pct": 100.0,           # 100.0 = perfect lossless
    "duration_s":    10.0,            # seconds
    "peak":          0.518646,
    "rms":           0.055205,
    "output_wav":    "reconstructed.wav",
    "sample_rate":   48000,
    "total_ms":      35.8,            # decode pipeline time in ms
}
```

**Example — just convert, no playback (server use):**

```python
import wavcore

stats = wavcore.decode(
    vtxt_path  = "voice_data.vtxt",
    output_wav = "output.wav",
    play       = False,              # don't play, just save
)

print(f"Integrity : {stats['integrity_pct']:.2f}%")
print(f"Duration  : {stats['duration_s']:.2f} s")
print(f"Bad frames: {stats['bad_frames']}")
```

**Example — decode and play immediately:**

```python
wavcore.decode("voice_data.vtxt", "output.wav", play=True)
```

---

### `wavcore.engine_info()`

Returns a string describing the active C engine tier.

```python
print(wavcore.engine_info())
```

Possible outputs:

```
C engine [cffi / MSVC 64-bit .pyd]  — ultra-fast    ← best (after pip install)
C engine [ctypes DLL]  — fast                       ← DLL fallback
Pure-Python fallback  [run build_codec.py for C engine]
```

Always check this first when debugging performance. You want `C engine`.

---

### `wavcore.batch_encode(audio, spf)`

Low-level: encode a `float32` numpy array into a list of hex strings (one per frame).

```python
import wavcore
import numpy as np

audio    = np.random.randn(5 * 960).astype(np.float32)  # 5 frames
spf      = 960                                           # samples per frame

hex_list = wavcore.batch_encode(audio, spf)

print(len(hex_list))       # 5
print(len(hex_list[0]))    # 7680  (960 samples × 8 hex chars each)
print(type(hex_list[0]))   # <class 'str'>
```

**Parameters:**

| Parameter | Type | Description |
|---|---|---|
| `audio` | `np.ndarray` float32, 1-D | Audio samples, length = `n_frames × spf` |
| `spf` | `int` | Samples per frame (e.g. 960 for 20ms @ 48kHz) |

**Returns:** `list[str]` — uppercase hex strings, one per frame.

---

### `wavcore.batch_decode(hex_list, spf)`

Low-level: decode a list of hex strings back to a contiguous `float32` array. Exact inverse of `batch_encode`.

```python
audio_back = wavcore.batch_decode(hex_list, spf=960)

print(audio_back.shape)  # (4800,)  = 5 frames × 960 samples
print(audio_back.dtype)  # float32
print(np.array_equal(audio, audio_back))  # True — bit-perfect
```

**Parameters:**

| Parameter | Type | Description |
|---|---|---|
| `hex_list` | `list[str]` | Hex strings from `batch_encode` |
| `spf` | `int` | Samples per frame |

**Returns:** `np.ndarray` float32, 1-D.

---

### `wavcore.compute_frame_crc()`

Low-level: compute the CRC-32 checksum for a single audio frame. Used to verify frame integrity.

```python
import wavcore
import numpy as np

samples  = np.random.randn(960).astype(np.float32)
payload  = samples.tobytes()

crc = wavcore.compute_frame_crc(
    version      = 1,
    frame_id     = 0,
    timestamp_ms = 1745123456789.0,
    sample_rate  = 48000,
    channels     = 1,
    bit_depth    = 32,
    payload      = payload,         # raw bytes of float32 samples
)

print(f"CRC-32: {crc:08X}")   # e.g.  BC5C582D
```

**Parameters:**

| Parameter | Type | Description |
|---|---|---|
| `version` | `int` | Frame version (always 1) |
| `frame_id` | `int` | Sequential frame index (0, 1, 2 ...) |
| `timestamp_ms` | `float` | Wall-clock timestamp in milliseconds |
| `sample_rate` | `int` | Hz (e.g. 48000) |
| `channels` | `int` | Number of channels (1 = mono) |
| `bit_depth` | `int` | Bits per sample (32 for float32) |
| `payload` | `bytes` | Raw bytes of the float32 sample array |

**Returns:** `int` — 32-bit unsigned CRC value.

> **Identical to:** `zlib.crc32(struct.pack(">BIdIBBI", ...) + payload) & 0xFFFFFFFF`

---

## Architecture

```text
                    ┌─────────────────────────────┐
                    │      NORMAL MODE             │
  Microphone ──────>│  sd.rec() (full capture)     │
                    │  C batch_encode()            │
                    │  C compute_frame_crc() ×N    │
                    │  write .vtxt (all at once)   │
                    └─────────────────────────────┘

                    ┌─────────────────────────────┐
                    │      LIVE MODE               │
  Microphone ──────>│  sd.InputStream (callback)   │
                    │    ↓ every 20ms              │
                    │  queue → C batch_encode()    │
                    │  C compute_frame_crc()       │
                    │  write [FRAME] + f.flush()   │
                    │  (file grows live on disk)   │
                    └─────────────────────────────┘

                    ┌─────────────────────────────┐
                    │      FILE MODE  ← NEW        │
  Audio File ──────>│  read (wave / soundfile)     │
  (WAV/FLAC/OGG)    │  mono mix + resample         │
                    │  C batch_encode()            │
                    │  C compute_frame_crc() ×N    │
                    │  write .vtxt (all at once)   │
                    └─────────────────────────────┘

                    ┌─────────────────────────────┐
                    │      DECODE (all modes)      │
  .vtxt ───────────>│  parse [FRAME] blocks        │
                    │  C batch_decode()            │
                    │  C CRC-32 verify             │
                    │  gap detection → silence     │
                    │  save WAV + play             │
                    └─────────────────────────────┘
```

---

## VTXT Format

```text
# ================================================================
# wavcore VTXT  v1.0
# Recorded : 2026-04-21 12:00:00 UTC
# ================================================================

[FILE_HEADER]
CODEC_VERSION=1
FILE_VERSION=1
TOTAL_FRAMES=500
SAMPLE_RATE=48000
CHANNELS=1
BIT_DEPTH=32
FRAME_MS=20
DURATION_MS=10000.000000
CREATED_UNIX=1745467200
CREATED_UTC=2026-04-21 12:00:00 UTC
[/FILE_HEADER]

[FRAME]
FRAME_ID=0
FRAME_VERSION=1
TIMESTAMP_MS=1745467200000.000000
SAMPLE_RATE=48000
CHANNELS=1
BIT_DEPTH=32
PAYLOAD_LEN=3840
SAMPLES_COUNT=960
ORIG_CRC32=BC5C582D
SAMPLES_HEX=3C8B43963D0A12F4...
[/FRAME]
```

Live mode files also include `RECORD_MODE=LIVE` in the header.
File mode files include `RECORD_MODE=FILE` and `SOURCE_FILE=<filename>` in the header.

---

## Performance

| Operation | Frames | Time |
|---|---:|---:|
| Encode (C cffi) | 500 | ~7.5 ms |
| Decode (C cffi) | 500 | ~4.6 ms |
| CRC verify (C) | 500 | ~7.4 ms |
| Full pipeline | 500 | ~35.8 ms |

Real-time budget per 20ms frame: **20,000 µs**
WavCore encodes in: **~15 µs/frame** (1326× faster than real-time)

---

## Integration Examples

### 1. Direct `.vtxt` → WAV (no recording needed)

```python
import wavcore

# You already have a .vtxt file — just convert it
stats = wavcore.decode(
    vtxt_path  = "existing_voice.vtxt",
    output_wav = "output.wav",
    play       = False,
)
print(f"Done — {stats['duration_s']:.1f}s  |  {stats['integrity_pct']:.1f}% intact")
```

### 2. Live Record Then Decode

```python
import wavcore

# Step 1 — record live (press ENTER to stop)
rec = wavcore.live_record("voice.vtxt", "orig.wav", max_duration=120)
print(f"Captured {rec['frames']} frames ({rec['duration_ms']/1000:.1f}s)")

# Step 2 — decode immediately
dec = wavcore.decode("voice.vtxt", "reconstructed.wav", play=True)
print(f"Integrity: {dec['integrity_pct']:.2f}%")
```

### 3. Voice Messaging (HTTP)

```python
import wavcore, requests

# === SENDER ===
wavcore.record("message.vtxt", "send_orig.wav", duration=5)
with open("message.vtxt", "r") as f:
    payload = f.read()

requests.post(
    "https://api.myapp.com/voice/send",
    data=payload.encode("utf-8"),
    headers={"Content-Type": "text/plain; charset=utf-8"},
)

# === RECEIVER ===
response = requests.get("https://api.myapp.com/voice/recv/msg123")
with open("received.vtxt", "w", encoding="utf-8") as f:
    f.write(response.text)

result = wavcore.decode("received.vtxt", "playback.wav", play=True)
print(f"Played {result['duration_s']:.1f}s  |  {result['integrity_pct']:.1f}% intact")
```

### 4. Firebase Realtime Database

```python
import wavcore
from firebase_admin import db

# Record and encode
wavcore.record("voice.vtxt", "voice.wav", duration=5)
with open("voice.vtxt", "r") as f:
    vtxt_data = f.read()

# Push as text to Firebase
ref = db.reference("voice_messages")
ref.push({"sender": "Alice", "vtxt": vtxt_data})

# On receiver — read and decode
messages = ref.get()
for key, msg in messages.items():
    with open("recv.vtxt", "w") as f:
        f.write(msg["vtxt"])
    wavcore.decode("recv.vtxt", "playback.wav", play=True)
```

### 5. SQLite Storage

```python
import wavcore, sqlite3

conn = sqlite3.connect("voices.db")
conn.execute("""CREATE TABLE IF NOT EXISTS voice_messages
    (id INTEGER PRIMARY KEY, sender TEXT, vtxt_data TEXT, created_at REAL)""")

# Record and store
stats = wavcore.record("temp.vtxt", "temp_orig.wav", duration=5)
with open("temp.vtxt") as f:
    vtxt = f.read()
conn.execute(
    "INSERT INTO voice_messages (sender, vtxt_data, created_at) VALUES (?, ?, ?)",
    ("Alice", vtxt, stats["created_unix"])
)
conn.commit()

# Retrieve and decode
row = conn.execute(
    "SELECT vtxt_data FROM voice_messages ORDER BY id DESC LIMIT 1"
).fetchone()
with open("playback.vtxt", "w") as f:
    f.write(row[0])
wavcore.decode("playback.vtxt", "playback.wav", play=True)
```

### 6. Custom Frame-by-Frame Streaming

```python
import wavcore, numpy as np, sounddevice as sd

SAMPLE_RATE = 48_000
SPF         = 960           # 20ms @ 48kHz
frame_id    = 0
frames_sent = []

def audio_callback(indata, frames, time_info, status):
    global frame_id
    chunk   = np.ascontiguousarray(indata.flatten(), dtype=np.float32)
    hex_str = wavcore.batch_encode(chunk, SPF)[0]
    payload = chunk.tobytes()
    crc     = wavcore.compute_frame_crc(
        1, frame_id,
        time_info.inputBufferAdcTime * 1000,
        SAMPLE_RATE, 1, 32, payload
    )
    frames_sent.append((frame_id, hex_str, f"{crc:08X}"))
    frame_id += 1

with sd.InputStream(samplerate=SAMPLE_RATE, channels=1,
                    dtype="float32", blocksize=SPF,
                    callback=audio_callback):
    input("Streaming... press ENTER to stop\n")

print(f"Captured {len(frames_sent)} frames")
```

### 7. Checking Signal Quality

```python
import wavcore

rec  = wavcore.record("audio.vtxt", "orig.wav", duration=10)
dec  = wavcore.decode("audio.vtxt", "recon.wav", play=False)

# Recording quality
if rec["peak"] < 0.001:
    print("WARNING: Mic too quiet — check OS audio settings")
elif rec["peak"] > 0.95:
    print("WARNING: Clipping detected — move mic further away")
else:
    print(f"Good signal: peak={rec['peak']:.4f}  rms={rec['rms']:.4f}")

# Decode quality
if dec["integrity_pct"] == 100.0:
    print("Perfect reconstruction — bit-identical to original")
elif dec["integrity_pct"] >= 95.0:
    print(f"Good: {dec['integrity_pct']:.1f}% frames valid")
else:
    print(f"Degraded: {dec['bad_frames']} frames corrupted/missing")

# Speed
fps = rec["frames"] / (rec["encode_ms"] / 1000)
print(f"Encode: {rec['encode_ms']:.1f} ms  ({fps:.0f} frames/s)")
print(f"Decode: {dec['total_ms']:.1f} ms")
```

---

## Configuration Reference

| Parameter | Default | Range | Applies to |
|---|---|---|---|
| `duration` | `10` | 1–3600 s | `record()` only — fixed length |
| `max_duration` | `60` | 1–3600 s | `live_record()` only — press ENTER to stop early |
| `audio_path` | — | any path | `file_to_vtxt()` only — input audio file |
| `sample_rate` | `48000` | 8000–192000 | All modes — higher = better quality, larger file |
| `frame_ms` | `20` | 10–100 | All modes — smaller = lower latency |
| `play` | `True` | True/False | `decode()` only — set `False` on servers |

### Sample Rate vs File Size (10 seconds)

| Sample Rate | Samples/Frame (20ms) | File Size | Quality |
|---|---|---|---|
| 8,000 Hz | 160 → 1,280 chars | ~660 KB | Phone call |
| 16,000 Hz | 320 → 2,560 chars | ~1.3 MB | VoIP |
| 44,100 Hz | 882 → 7,056 chars | ~3.6 MB | CD quality |
| **48,000 Hz** | **960 → 7,680 chars** | **~3.9 MB** | **Default** |
| 96,000 Hz | 1,920 → 15,360 chars | ~7.8 MB | Professional |

---

## Output Files

| File | Created by | Contains |
|---|---|---|
| `voice_data.vtxt` | `record()` / `live_record()` / `file_to_vtxt()` | Text-encoded audio frames |
| `original_reference.wav` | `record()` / `live_record()` | Raw mic capture (ground truth) |
| `reconstructed.wav` | `decode()` | Rebuilt audio from `.vtxt` |

> **File Mode note:** `file_to_vtxt()` does not create an `original_reference.wav` — the source audio file itself is the reference. The `.vtxt` header records the original filename as `SOURCE_FILE`.

---

## Troubleshooting

### "Pure-Python fallback" instead of C engine

```bash
pip install -e .          # triggers C compilation
# or reinstall from PyPI
pip install --force-reinstall wavcore
```

### No audio recorded (`peak < 0.001`)

```python
import sounddevice
print(sounddevice.query_devices())   # check available devices
```

Also check OS microphone permissions (Settings → Privacy → Microphone).

### `sounddevice` not found

```bash
pip install sounddevice
# Linux also needs:
sudo apt install libportaudio2
```

### CRC failures after local record+decode

Indicates file corruption (partial overwrite). Re-record to get a clean file.
For network transmission, add retry logic and re-request specific frames.

### Live mode: ENTER key not stopping

This can happen in some terminal environments. Press `Ctrl+C` as an alternative stop signal.

### File mode: format not supported

```bash
pip install soundfile        # for FLAC, OGG, AIFF
```

For MP3, soundfile needs libsndfile compiled with MP3 support (platform-dependent).
Alternatively, convert your MP3 to WAV first using any audio tool, then use `file_to_vtxt`.

### File mode: quality sounds different after decode

If the source file's sample rate (e.g. 44100 Hz) differs from `sample_rate` (default 48000 Hz), the audio is resampled. For best quality, match the sample rate to the source:

```python
from recorder_converter import file_to_vtxt

# Match source rate (44100 Hz CD audio)
file_to_vtxt("song.wav", "song.vtxt", sample_rate=44_100)
```

---

## Documentation

Full technical docs are in the `docs/` folder:

| File | Contents |
|---|---|
| `docs/ARCHITECTURE.md` | C engine, build system, internal design |
| `docs/VTXT_FORMAT_SPEC.md` | Complete .vtxt format specification |
| `docs/PERFORMANCE_GUIDE.md` | Benchmarks, tuning, profiling |
| `docs/USER_MANUAL.md` | Detailed usage guide |
| `docs/PYPI_PUBLISHING_GUIDE.md` | How to publish to PyPI |

---

## Developer

**Prashant Pandey**

- technical121@gmail.com
- codex.admim@gmail.com

GitHub: https://github.com/Zyro-Hub/wavecore
PyPI: https://pypi.org/project/wavcore/

---

## License

MIT License
