Skip to main content

Ultra-fast lossless voice codec — real-time recording, VTXT text serialization, and bit-perfect reconstruction with a C engine.

Project description

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

pip install wavcore==2.0.0 .

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

Development (editable) Install

pip install -e .

Verify

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

Quick Start

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

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.

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:

{
    "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:

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.

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:

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.

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:

{
    "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:

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
# 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.

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:

{
    "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:

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:

# ❌ 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().

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:

{
    "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):

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:

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

wavcore.engine_info()

Returns a string describing the active C engine tier.

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).

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.

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.

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

                    ┌─────────────────────────────┐
                    │      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

# ================================================================
# 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)

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

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)

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

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

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

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

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

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

No audio recorded (peak < 0.001)

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

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

sounddevice not found

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

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:

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

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


License

MIT License

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

wavcore-2.0.1.tar.gz (70.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

wavcore-2.0.1-cp312-cp312-win_amd64.whl (44.4 kB view details)

Uploaded CPython 3.12Windows x86-64

File details

Details for the file wavcore-2.0.1.tar.gz.

File metadata

  • Download URL: wavcore-2.0.1.tar.gz
  • Upload date:
  • Size: 70.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for wavcore-2.0.1.tar.gz
Algorithm Hash digest
SHA256 d3c78d88da6ab3118f094790bbcd8c10ea8dc59d3654121dfa3baa095fe9e411
MD5 44dce0c82d6843b6ecbab517b398ddff
BLAKE2b-256 73f1a0f93777ae660f9366d0e480399073bdea1cf7e3e42dd7201021fcbbd10f

See more details on using hashes here.

File details

Details for the file wavcore-2.0.1-cp312-cp312-win_amd64.whl.

File metadata

  • Download URL: wavcore-2.0.1-cp312-cp312-win_amd64.whl
  • Upload date:
  • Size: 44.4 kB
  • Tags: CPython 3.12, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for wavcore-2.0.1-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 6e4e9777cdbec7c8f8515fd4972260a04f31e1fd92ba80a62a2e824d55672c95
MD5 05c0f71348ea20342ab97ea31b35d8a7
BLAKE2b-256 38f8e5ea971f99a600d36bb71aef010d1aeda4e804fd6cf33a3aca5815467af0

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page