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.vtxtin 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.vtxtwithout a microphone. - Direct Convert (
convert_audio) — convert any audio file straight to WAV in one call — no microphone, no manual vtxt step. app.pynow 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_polyif 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 anoriginal_reference.wav— the source audio file itself is the reference. The.vtxtheader records the original filename asSOURCE_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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d3c78d88da6ab3118f094790bbcd8c10ea8dc59d3654121dfa3baa095fe9e411
|
|
| MD5 |
44dce0c82d6843b6ecbab517b398ddff
|
|
| BLAKE2b-256 |
73f1a0f93777ae660f9366d0e480399073bdea1cf7e3e42dd7201021fcbbd10f
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6e4e9777cdbec7c8f8515fd4972260a04f31e1fd92ba80a62a2e824d55672c95
|
|
| MD5 |
05c0f71348ea20342ab97ea31b35d8a7
|
|
| BLAKE2b-256 |
38f8e5ea971f99a600d36bb71aef010d1aeda4e804fd6cf33a3aca5815467af0
|