npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@eldrforge/audio-tools

v0.1.15

Published

Audio recording tools for voice-driven development workflows

Readme

@eldrforge/audio-tools

Professional Audio Recording & Transcription Toolkit for Node.js

License npm version TypeScript

Voice-driven development workflows made simple

FeaturesInstallationQuick StartExamplesAPI ReferenceDocumentation


🎯 Overview

@eldrforge/audio-tools is a comprehensive TypeScript library for recording, transcribing, and managing audio in Node.js applications. Built for developers who want to integrate voice-driven workflows, voice notes, audio documentation, or AI-powered transcription into their projects.

Key Highlights

  • 🎙️ High-Quality Recording - Capture audio from any input device with configurable settings
  • 🎬 Visual Countdown Timers - Professional recording countdowns with ANSI colors and beeps
  • 🔊 Device Management - List, select, and configure audio input devices
  • 🤖 AI Transcription - Powered by OpenAI's Whisper API for accurate transcription
  • 📦 Archive Management - Timestamped archiving of audio files and transcripts
  • 🔧 Fully Typed - Complete TypeScript definitions for excellent IDE support
  • 🪵 Flexible Logging - Optional Winston logger integration
  • 🚀 Zero Config - Sensible defaults, works out of the box

✨ Features

Audio Recording

  • ✅ Cross-platform support (macOS, Linux, Windows)
  • ✅ Device selection and configuration
  • ✅ Configurable sample rates and formats (WAV, MP3, FLAC)
  • ✅ Duration limits and manual stop controls
  • ✅ Custom output paths
  • ✅ Real-time recording status

Visual Countdown Timers

  • ✅ ANSI color-coded terminal display
  • ✅ In-place updating (no screen clutter)
  • ✅ Audio beeps at configurable intervals
  • ✅ Warning colors when time is low
  • ✅ Callback support for custom behaviors
  • ✅ Graceful cleanup and process handling

Transcription & Archiving

  • ✅ OpenAI Whisper API integration
  • ✅ Automatic file archiving with timestamps
  • ✅ Transcript preservation in Markdown format
  • ✅ Batch processing support
  • ✅ Error recovery and retry logic

📦 Installation

npm install @eldrforge/audio-tools

Peer Dependencies

The library has optional peer dependencies for enhanced functionality:

# For logging (recommended)
npm install winston

# For shared utilities (optional)
npm install @eldrforge/shared

System Requirements

  • Node.js: 18.x or later
  • Operating System: macOS, Linux, or Windows
  • Audio Input: Microphone or audio input device

🚀 Quick Start

Basic Recording

import { recordAudio } from '@eldrforge/audio-tools';

// Record up to 60 seconds of audio
const result = await recordAudio({
  duration: 60,
  countdownDelay: 3,
});

console.log('Audio recorded:', result.filePath);
console.log('Duration:', result.duration, 'seconds');
console.log('File size:', result.fileSize, 'bytes');

Record and Transcribe

import { recordAudio, transcribeAudio, archiveAudio } from '@eldrforge/audio-tools';

// Record audio
const recording = await recordAudio({ duration: 120 });

// Transcribe with OpenAI Whisper
const transcript = await transcribeAudio(recording.filePath);

// Archive both audio and transcript with timestamps
const archive = await archiveAudio(
  recording.filePath,
  transcript,
  'output/recordings'
);

console.log('Transcript:', transcript);
console.log('Archived to:', archive.audioPath);

Interactive Device Selection

import { selectDeviceInteractive, recordAudio } from '@eldrforge/audio-tools';

// Let user select audio device interactively
const device = await selectDeviceInteractive();

// Record with selected device
const result = await recordAudio({ duration: 60 });

Countdown Timer

import { CountdownTimer } from '@eldrforge/audio-tools';

const timer = new CountdownTimer({
  durationSeconds: 30,
  beepAt30Seconds: true,
  redAt30Seconds: true,
  onTick: (remaining) => {
    console.log(`${remaining} seconds remaining`);
  },
  onComplete: () => {
    console.log('Time\'s up!');
  }
});

await timer.start();

📖 Documentation

Comprehensive documentation is available:

📚 Examples

The examples/ directory contains comprehensive, runnable examples:

| Example | Description | File | |---------|-------------|------| | Basic Recording | Simple audio recording with default settings | basic-recording.ts | | Record & Transcribe | Complete workflow with transcription and archiving | record-and-transcribe.ts | | Countdown Demo | Visual countdown timer demonstrations | countdown-demo.ts | | Device Selection | List and select audio input devices | device-selection.ts | | Custom Output | Specify custom paths and filenames | custom-output-path.ts |

Running Examples

cd examples
npm install
npm run basic          # Basic recording
npm run transcribe     # Record and transcribe (requires OPENAI_API_KEY)
npm run countdown      # Countdown timer demos
npm run devices        # Device selection
npm run custom-path    # Custom output paths

📖 API Reference

Recording Functions

recordAudio(options?: RecordingOptions): Promise<RecordingResult>

Record audio from an input device.

Options:

interface RecordingOptions {
  device?: AudioDevice | string;     // Audio device (optional, uses default)
  duration?: number;                 // Max duration in seconds (optional)
  outputPath?: string;               // Output file path (optional, generates temp)
  countdownDelay?: number;          // Countdown delay (default: 3)
  sampleRate?: number;              // Sample rate in Hz (default: 44100)
  format?: 'wav' | 'mp3' | 'flac';  // Audio format (default: 'wav')
}

Returns:

interface RecordingResult {
  filePath: string;   // Path to recorded file
  duration: number;   // Recording duration in seconds
  fileSize: number;   // File size in bytes
}

Example:

const result = await recordAudio({
  duration: 60,
  sampleRate: 48000,
  format: 'wav',
  countdownDelay: 3
});

archiveAudio(audioPath: string, transcript: string, outputDir?: string)

Archive audio file with its transcription.

Parameters:

  • audioPath: Path to the original audio file
  • transcript: Transcribed text content
  • outputDir: Directory to save archived files (default: 'output')

Returns:

{
  audioPath: string;      // Path to archived audio file
  transcriptPath: string; // Path to archived transcript
}

Example:

const archive = await archiveAudio(
  'recording.wav',
  'This is the transcribed text...',
  'output/archives'
);

// Creates files like:
// - output/archives/250701-1430-review-audio.wav
// - output/archives/250701-1430-review-transcript.md

deleteAudio(audioPath: string): Promise<void>

Delete an audio file safely.

Example:

await deleteAudio('temp-recording.wav');

getAudioDuration(audioPath: string): Promise<number | null>

Get the duration of an audio file (currently returns null, planned feature).


Device Functions

listAudioDevices(): Promise<AudioDevice[]>

List all available audio input devices.

Returns:

interface AudioDevice {
  id: string;
  name: string;
  isDefault: boolean;
}

Example:

const devices = await listAudioDevices();
devices.forEach(device => {
  console.log(`${device.name} (${device.id})`);
  if (device.isDefault) {
    console.log('  ✓ Default device');
  }
});

getDefaultDevice(): Promise<AudioDevice | null>

Get the system's default audio input device.

Example:

const device = await getDefaultDevice();
if (device) {
  console.log('Default device:', device.name);
}

findDevice(idOrName: string): Promise<AudioDevice | null>

Find a device by its ID or name.

Example:

const device = await findDevice('MacBook Pro Microphone');
if (device) {
  console.log('Found device:', device.id);
}

selectDeviceInteractive(): Promise<string>

Present an interactive menu to select an audio device.

Example:

const deviceId = await selectDeviceInteractive();
console.log('Selected device:', deviceId);

Transcription Functions

transcribeAudio(audioPath: string): Promise<string>

Transcribe an audio file using OpenAI's Whisper API.

Requirements:

  • OPENAI_API_KEY environment variable must be set
  • Audio file must be in a supported format (WAV, MP3, FLAC, etc.)

Example:

const transcript = await transcribeAudio('recording.wav');
console.log('Transcription:', transcript);

Countdown Timer Classes

CountdownTimer

A visual countdown timer with customizable behavior.

Constructor Options:

interface CountdownOptions {
  durationSeconds: number;          // Duration in seconds
  beepAt30Seconds?: boolean;        // Beep at 30s (default: true)
  redAt30Seconds?: boolean;         // Red color at 30s (default: true)
  onTick?: (remaining: number) => void;   // Called every second
  onComplete?: () => void;          // Called when complete
  clearOnComplete?: boolean;        // Clear display when done (default: false)
}

Methods:

  • start(): Promise<void> - Start the countdown
  • stop(): void - Stop the countdown
  • getRemainingSeconds(): number - Get remaining time
  • destroy(): void - Clean up resources
  • isTimerDestroyed(): boolean - Check if destroyed

Example:

const timer = new CountdownTimer({
  durationSeconds: 60,
  beepAt30Seconds: true,
  redAt30Seconds: true,
  onTick: (remaining) => {
    if (remaining % 10 === 0) {
      console.log(`${remaining} seconds left`);
    }
  },
  onComplete: () => {
    console.log('Recording complete!');
  }
});

await timer.start();

startCountdown(options: CountdownOptions): Promise<void>

Convenience function to create and start a countdown timer.

Example:

await startCountdown({
  durationSeconds: 30,
  onComplete: () => console.log('Done!')
});

createAudioRecordingCountdown(seconds: number): CountdownTimer

Create a countdown timer with sensible defaults for audio recording.

Example:

const timer = createAudioRecordingCountdown(120);
await timer.start();

Utility Functions

getTimestampedArchivedAudioFilename(extension?: string): string

Generate a timestamped filename for archived audio.

Example:

const filename = getTimestampedArchivedAudioFilename('.mp3');
// Returns: "250701-1430-review-audio.mp3"

getTimestampedArchivedTranscriptFilename(): string

Generate a timestamped filename for archived transcripts.

Example:

const filename = getTimestampedArchivedTranscriptFilename();
// Returns: "250701-1430-review-transcript.md"

Logging

setLogger(logger: Logger): void

Set a custom Winston logger instance.

Example:

import { setLogger } from '@eldrforge/audio-tools';
import { createLogger, format, transports } from 'winston';

const logger = createLogger({
  level: 'debug',
  format: format.combine(
    format.timestamp(),
    format.colorize(),
    format.simple()
  ),
  transports: [
    new transports.Console(),
    new transports.File({ filename: 'audio-tools.log' })
  ]
});

setLogger(logger);

getLogger(): Logger

Get the current logger instance.

Example:

import { getLogger } from '@eldrforge/audio-tools';

const logger = getLogger();
logger.info('Starting recording...');

🎬 Complete Usage Example

Here's a complete example showing a typical workflow:

import {
  recordAudio,
  transcribeAudio,
  archiveAudio,
  deleteAudio,
  CountdownTimer,
  setLogger
} from '@eldrforge/audio-tools';
import { createLogger, format, transports } from 'winston';
import { config } from 'dotenv';

// Load environment variables
config();

// Configure logging
const logger = createLogger({
  level: 'info',
  format: format.combine(
    format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
    format.colorize(),
    format.printf(({ timestamp, level, message }) =>
      `${timestamp} [${level}]: ${message}`
    )
  ),
  transports: [
    new transports.Console(),
    new transports.File({ filename: 'audio-tools.log' })
  ]
});

setLogger(logger);

async function recordAndTranscribeVoiceNote() {
  let audioPath: string | null = null;

  try {
    console.log('🎙️  Voice Note Recorder');
    console.log('======================\n');

    // Step 1: Countdown
    console.log('Get ready to speak...\n');
    const countdown = new CountdownTimer({
      durationSeconds: 3,
      beepAt30Seconds: false,
      clearOnComplete: true
    });
    await countdown.start();

    // Step 2: Record
    console.log('🔴 Recording... (Press ENTER to stop)\n');
    const recording = await recordAudio({
      duration: 300, // 5 minutes max
      sampleRate: 48000,
      format: 'wav'
    });

    audioPath = recording.filePath;
    logger.info(`Recorded ${recording.duration.toFixed(2)}s of audio`);

    // Step 3: Transcribe
    console.log('\n📝 Transcribing...');
    const transcript = await transcribeAudio(audioPath);

    console.log('\n✅ Transcript:\n');
    console.log('─'.repeat(60));
    console.log(transcript);
    console.log('─'.repeat(60));

    // Step 4: Archive
    console.log('\n💾 Archiving...');
    const archive = await archiveAudio(
      audioPath,
      transcript,
      'output/voice-notes'
    );

    logger.info(`Archived to: ${archive.audioPath}`);
    logger.info(`Transcript saved: ${archive.transcriptPath}`);

    // Step 5: Cleanup
    await deleteAudio(audioPath);
    logger.info('Temporary file deleted');

    console.log('\n✅ Voice note saved successfully!');

  } catch (error) {
    logger.error('Failed to process voice note:', error);

    // Cleanup on error
    if (audioPath) {
      try {
        await deleteAudio(audioPath);
      } catch {
        // Ignore cleanup errors
      }
    }

    throw error;
  }
}

// Run the example
recordAndTranscribeVoiceNote().catch(error => {
  console.error('\n❌ Error:', error.message);
  process.exit(1);
});

🔧 Configuration

Environment Variables

  • OPENAI_API_KEY - Required for transcription functionality
  • NO_COLOR - Disable ANSI colors in terminal output
  • TERM - Terminal type detection for ANSI support

Audio Preferences

The library uses @theunwalked/unplayable which stores audio device preferences in:

~/.unplayable/audio-preferences.json

You can manually edit this file to set default devices.

🏗️ Architecture

Dependencies

Platform Support

| Platform | Status | Backend | |----------|--------|---------| | macOS | ✅ Supported | CoreAudio | | Linux | ✅ Supported | ALSA/PulseAudio | | Windows | ✅ Supported | WASAPI |

🧪 Testing

The library includes comprehensive test coverage:

# Run tests
npm test

# Run tests with coverage
npm run test

# Watch mode
npm run test -- --watch

🛠️ Development

Build from Source

# Clone the repository
git clone https://github.com/grunnverk/audio-tools.git
cd audio-tools

# Install dependencies
npm install

# Build
npm run build

# Run tests
npm test

# Lint
npm run lint

Project Structure

audio-tools/
├── src/
│   ├── countdown.ts      # Countdown timer utilities
│   ├── devices.ts        # Audio device management
│   ├── recording.ts      # Recording and archiving
│   ├── transcription.ts  # Transcription wrapper
│   ├── types.ts          # TypeScript definitions
│   └── index.ts          # Main exports
├── tests/                # Test files
├── examples/             # Usage examples
├── dist/                 # Compiled output
└── package.json

🤝 Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/my-feature
  3. Make your changes with tests
  4. Run tests: npm test
  5. Commit with clear messages
  6. Push and open a Pull Request

📝 License

Apache-2.0 License - see LICENSE file for details.

🔗 Related Projects

💬 Support

📊 Changelog

See RELEASE_NOTES.md for version history and changes.


Made with ❤️ by Tim O'Brien

⭐ Star this repo if you find it useful!