AudioSig Examples

Basic Audio Processing

Creating Test Signals

import numpy as np

def create_sine_wave(frequency=440, duration=1.0, sample_rate=24000):
    """Create a sine wave for testing."""
    t = np.linspace(0, duration, int(sample_rate * duration), dtype=np.float32)
    return np.sin(2 * np.pi * frequency * t)

def create_chirp(f_start=220, f_end=880, duration=1.0, sample_rate=24000):
    """Create a frequency sweep for testing."""
    t = np.linspace(0, duration, int(sample_rate * duration), dtype=np.float32)
    frequency = f_start + (f_end - f_start) * t / duration
    phase = 2 * np.pi * (f_start * t + (f_end - f_start) * t**2 / (2 * duration))
    return np.sin(phase).astype(np.float32)

Silence and Channel Layouts

import numpy as np
from audiosig import downmix_to_mono, generate_silence

silence = generate_silence(0.5, 24_000)
assert silence.shape == (12_000,)

left = np.ones(8, dtype=np.float32)
right = np.zeros(8, dtype=np.float32)
frames_first = np.column_stack([left, right])
mono_frames = downmix_to_mono(frames_first)

channels_first = np.stack([left, right])
mono_channels = downmix_to_mono(channels_first, channel_axis=0)
np.testing.assert_array_equal(mono_frames, 0.5)
np.testing.assert_array_equal(mono_channels, 0.5)

Silence length uses int(duration * sample_rate) truncation. Silence accepts real floating NumPy dtypes; downmixing accepts finite real floating one- or two-dimensional audio, preserves the source dtype, returns independent contiguous storage, and does not clip or normalize. For a long file, produce bounded silence chunks in the application rather than requesting one unbounded array; AudioSig deliberately does not provide file I/O or streaming wrappers.

Time Stretching Examples

from audiosig import time_stretch

# Create a 1-second tone
audio = create_sine_wave(440, duration=1.0)

# Speed up by 50% (shorter duration)
faster = time_stretch(audio, rate=1.5)
print(f"Original: {len(audio)} samples")
print(f"Faster: {len(faster)} samples")  # ~16000 samples

# Slow down by 50% (longer duration)
slower = time_stretch(audio, rate=0.5)
print(f"Slower: {len(slower)} samples")  # ~48000 samples

# Music tempo adjustment
def adjust_tempo(audio, tempo_factor):
    """Adjust audio tempo by a factor."""
    return time_stretch(audio, rate=tempo_factor)

# Speech rate adjustment
def slow_speech(audio, factor=0.8):
    """Make speech slower and clearer."""
    return time_stretch(audio, rate=factor)

Pitch Shifting Examples

from audiosig import pitch_shift

audio = create_sine_wave(440, duration=1.0, sample_rate=24000)

# Raise pitch by 1 octave (12 semitones)
octave_up = pitch_shift(audio, sample_rate=24000, semitones=12.0)

# Lower pitch by 1 octave
octave_down = pitch_shift(audio, sample_rate=24000, semitones=-12.0)

# Musical transposition
def transpose(audio, semitones, sample_rate=24000):
    """Transpose audio by semitones."""
    return pitch_shift(audio, sample_rate=sample_rate, semitones=semitones)

# A4 (440 Hz) to C5 (523 Hz) - about 3 semitones
c5 = transpose(audio, semitones=3.0)

For a speech-only experimental direct pitch path, keep changes moderate and opt in explicitly:

from audiosig import apply_speech_effects

speech_up = apply_speech_effects(
    audio,
    sample_rate=24_000,
    semitones=4.0,
    method="td_psola",
)

TD-PSOLA does not guarantee formant preservation, does not pitch unvoiced regions, and is not intended for music or polyphonic material.

Resampling Examples

from audiosig import resample, resample_speed, resample_to_length

# Create audio at 48kHz
audio_48k = create_sine_wave(440, duration=1.0, sample_rate=48000)

# Downsample to 16kHz
audio_16k = resample(audio_48k, source_rate=48000, target_rate=16000)
print(f"48kHz: {len(audio_48k)} samples")
print(f"16kHz: {len(audio_16k)} samples")  # 1/3 of original

# Upsample to 96kHz
audio_96k = resample(audio_48k, source_rate=48000, target_rate=96000)
print(f"96kHz: {len(audio_96k)} samples")  # 2x original

# Exact sample-count and playback-speed operations
exact = resample_to_length(audio_48k, 12_000)
faster_playback = resample_speed(audio_48k, speed=1.25)

Silence Detection and VAD

Basic VAD Usage

from audiosig import normalized_energy_vad, energy_based_vad

# Create audio with silence and speech
sample_rate = 24000
silence = np.zeros(sample_rate // 2, dtype=np.float32)  # 0.5s silence
speech = create_sine_wave(440, duration=0.5, sample_rate=sample_rate)
audio = np.concatenate([silence, speech, silence])

# Detect voice activity
activity = normalized_energy_vad(
    audio,
    sample_rate=sample_rate,
    frame_duration_ms=10,
    energy_threshold=0.1,
)

print(f"Active frames: {np.sum(activity)}")
print(f"Total frames: {len(activity)}")

Tuning VAD Parameters

from audiosig import normalized_energy_vad

def detect_speech(audio, sample_rate, sensitivity='medium'):
    """Detect speech with different sensitivity levels."""
    thresholds = {
        'low': 0.05,      # More permissive
        'medium': 0.15,   # Balanced
        'high': 0.30,     # More strict
    }

    return normalized_energy_vad(
        audio,
        sample_rate=sample_rate,
        frame_duration_ms=10,
        energy_threshold=thresholds[sensitivity],
    )

# Usage
activity = detect_speech(audio, sample_rate=24000, sensitivity='medium')

Finding Speech Boundaries

from audiosig import find_speech_bounds, find_speech_start

# Create test audio
sample_rate = 24000
silence = np.zeros(sample_rate // 2, dtype=np.float32)
speech = create_sine_wave(440, duration=1.0, sample_rate=sample_rate)
audio = np.concatenate([silence, speech, silence])

# Find speech bounds
bounds = find_speech_bounds(audio, sample_rate=sample_rate)
print(f"Speech from {bounds[0]} to {bounds[1]}")

# Extract just the speech
if not np.array_equal(bounds, [0, 0]):
    start, end = bounds
    speech_only = audio[start:end]

# Find speech start
start_idx = find_speech_start(audio, sample_rate=sample_rate)
print(f"Speech starts at sample {start_idx}")

Silence Trimming

Basic Trimming

from audiosig import trim

# Create audio with leading/trailing silence
sample_rate = 24000
silence = np.zeros(sample_rate // 4, dtype=np.float32)  # 0.25s silence
speech = create_sine_wave(440, duration=0.5, sample_rate=sample_rate)
audio = np.concatenate([silence, speech, silence])

# Trim silence
trimmed, interval = trim(audio, top_db=40.0)

print(f"Original length: {len(audio)}")
print(f"Trimmed length: {len(trimmed)}")
print(f"Kept samples {interval[0]} to {interval[1]}")

Splitting Audio Segments

from audiosig import split

# Create audio with multiple speech segments
sample_rate = 24000
segment1 = create_sine_wave(440, duration=0.3, sample_rate=sample_rate)
segment2 = create_sine_wave(880, duration=0.3, sample_rate=sample_rate)
silence = np.zeros(sample_rate // 4, dtype=np.float32)

audio = np.concatenate([segment1, silence, segment2, silence, segment1])

# Split into non-silent segments
intervals = split(audio, top_db=40.0, frame_length=512, hop_length=128)

print(f"Found {len(intervals)} segments")
for i, (start, end) in enumerate(intervals):
    segment = audio[start:end]
    print(f"Segment {i}: samples {start}-{end} ({len(segment)} samples)")

Custom Trimming Parameters

from audiosig import trim

def aggressive_trim(audio, top_db=20.0):
    """More aggressive silence removal."""
    return trim(audio, top_db=top_db, frame_length=1024, hop_length=64)

def gentle_trim(audio, top_db=60.0):
    """More conservative silence removal."""
    return trim(audio, top_db=top_db, frame_length=4096, hop_length=256)

# Use different strategies
trimmed_aggressive, _ = aggressive_trim(audio)
trimmed_gentle, _ = gentle_trim(audio)

Amplitude Processing

Gain Control

from audiosig import apply_gain_db

audio = create_sine_wave(440, duration=1.0, sample_rate=24000)

# Boost by 6 dB
boosted = apply_gain_db(audio, db=6.0)

# Attenuate by 10 dB
attenuated = apply_gain_db(audio, db=-10.0)

# With clipping protection
loud_clipped = apply_gain_db(audio, db=20.0, clip=True)

# Fade in/out effect
def fade_in(audio, duration_samples):
    """Apply linear fade in."""
    fade = np.linspace(0, 1, duration_samples, dtype=audio.dtype)
    result = audio.copy()
    result[:duration_samples] *= fade
    return result

def fade_out(audio, duration_samples):
    """Apply linear fade out."""
    fade = np.linspace(1, 0, duration_samples, dtype=audio.dtype)
    result = audio.copy()
    result[-duration_samples:] *= fade
    return result

Normalization

from audiosig import peak_normalize

audio = create_sine_wave(440, duration=1.0, sample_rate=24000) * 0.5

# Normalize to peak 0.9
normalized = peak_normalize(audio, peak=0.9)
print(f"Peak before: {np.max(np.abs(audio)):.3f}")
print(f"Peak after: {np.max(np.abs(normalized)):.3f}")

# Normalize to different targets
def normalize_to_target(audio, target_peak=0.95):
    """Normalize to specific peak level."""
    return peak_normalize(audio, peak=target_peak)

Frame Analysis

Basic Framing

from audiosig import frame_signal, frame_rms

audio = create_sine_wave(440, duration=1.0, sample_rate=24000)

# Split into frames
frames = frame_signal(
    audio,
    frame_length=2048,
    hop_length=512,
)
print(f"Audio shape: {audio.shape}")
print(f"Frames shape: {frames.shape}")  # (n_frames, 2048)

# Compute RMS per frame
rms_values = frame_rms(
    audio,
    frame_length=2048,
    hop_length=512,
)
print(f"RMS shape: {rms_values.shape}")  # (n_frames,)

Feature Extraction

from audiosig import (
    short_time_energy,
    zero_crossing_rate,
    spectral_flux,
)

audio = create_sine_wave(440, duration=1.0, sample_rate=24000)

# Short-time energy
energy = short_time_energy(audio, frame_length=2048, hop_length=512)

# Zero-crossing rate
zcr = zero_crossing_rate(audio, frame_length=2048, hop_length=512)

# Spectral flux
flux = spectral_flux(audio, frame_length=2048, hop_length=512)

print(f"Energy shape: {energy.shape}")
print(f"ZCR shape: {zcr.shape}")
print(f"Flux shape: {flux.shape}")

Real-World Examples

Audio Preprocessing Pipeline

import numpy as np
from audiosig import (
    trim,
    peak_normalize,
    resample,
    normalized_energy_vad,
)

def preprocess_audio(audio, source_rate, target_rate=16000):
    """Complete audio preprocessing pipeline."""
    # 1. Trim silence
    trimmed, _ = trim(audio, top_db=40.0)

    # 2. Normalize amplitude
    normalized = peak_normalize(trimmed, peak=0.95)

    # 3. Resample if needed
    if source_rate != target_rate:
        resampled = resample(
            normalized,
            source_rate=source_rate,
            target_rate=target_rate,
        )
    else:
        resampled = normalized

    return resampled

# Usage
audio_48k = load_audio("speech.wav")  # Your audio loading function
processed = preprocess_audio(audio_48k, source_rate=48000, target_rate=16000)

Speech Segmentation

import numpy as np
from audiosig import split, trim, normalized_energy_vad

def segment_speech(audio, sample_rate, min_duration_ms=100):
    """Segment audio into speech portions."""
    # Split into non-silent intervals
    intervals = split(
        audio,
        top_db=35.0,
        frame_length=512,
        hop_length=128,
    )

    # Filter by minimum duration
    min_samples = int(sample_rate * min_duration_ms / 1000)
    segments = []

    for start, end in intervals:
        if (end - start) >= min_samples:
            segments.append(audio[start:end])

    return segments

# Usage
audio = load_audio("long_speech.wav")
segments = segment_speech(audio, sample_rate=24000)
print(f"Found {len(segments)} speech segments")

Batch Processing

import numpy as np
from audiosig import time_stretch, pitch_shift

def process_batch(audio_list, rate=1.0, semitones=0.0, sample_rate=24000):
    """Process a batch of audio files."""
    results = []

    for audio in audio_list:
        # Apply time stretch if needed
        if rate != 1.0:
            audio = time_stretch(audio, rate=rate)

        # Apply pitch shift if needed
        if semitones != 0.0:
            audio = pitch_shift(
                audio,
                sample_rate=sample_rate,
                semitones=semitones,
            )

        results.append(audio)

    return results

# Usage
audio_files = [load_audio(f) for f in file_list]
processed = process_batch(audio_files, rate=1.1, semitones=2.0)

Performance Tips

Memory Efficiency

import numpy as np

# Process in chunks for large files
def process_large_audio(audio, chunk_size=24000):
    """Process large audio in chunks."""
    results = []
    for i in range(0, len(audio), chunk_size):
        chunk = audio[i:i + chunk_size]
        processed = process_chunk(chunk)  # Your processing function
        results.append(processed)
    return np.concatenate(results)

Using Appropriate dtypes

# For storage efficiency
audio_int16 = (audio * 32767).astype(np.int16)

# For processing (always use float)
audio_float = audio_int16.astype(np.float32) / 32767.0

# AudioSig preserves dtype
from audiosig import time_stretch
result = time_stretch(audio_float, rate=1.1)  # Returns float32