@eldrforge/audio-tools 0.1.6 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,73 +1,750 @@
1
1
  # @eldrforge/audio-tools
2
2
 
3
- Audio recording tools for voice-driven development workflows.
3
+ <div align="center">
4
4
 
5
- ## Overview
5
+ **Professional Audio Recording & Transcription Toolkit for Node.js**
6
6
 
7
- This package provides:
8
- - Audio device detection and selection
9
- - Audio recording with countdown
10
- - Integration with transcription services
11
- - Voice-driven workflow support
7
+ [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
8
+ [![npm version](https://img.shields.io/npm/v/@eldrforge/audio-tools.svg)](https://www.npmjs.com/package/@eldrforge/audio-tools)
9
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.9-blue)](https://www.typescriptlang.org/)
12
10
 
13
- ## Installation
11
+ *Voice-driven development workflows made simple*
12
+
13
+ [Features](#-features) • [Installation](#-installation) • [Quick Start](#-quick-start) • [Examples](#-examples) • [API Reference](#-api-reference) • [Documentation](#-documentation)
14
+
15
+ </div>
16
+
17
+ ---
18
+
19
+ ## 🎯 Overview
20
+
21
+ `@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.
22
+
23
+ ### Key Highlights
24
+
25
+ - 🎙️ **High-Quality Recording** - Capture audio from any input device with configurable settings
26
+ - 🎬 **Visual Countdown Timers** - Professional recording countdowns with ANSI colors and beeps
27
+ - 🔊 **Device Management** - List, select, and configure audio input devices
28
+ - 🤖 **AI Transcription** - Powered by OpenAI's Whisper API for accurate transcription
29
+ - 📦 **Archive Management** - Timestamped archiving of audio files and transcripts
30
+ - 🔧 **Fully Typed** - Complete TypeScript definitions for excellent IDE support
31
+ - 🪵 **Flexible Logging** - Optional Winston logger integration
32
+ - 🚀 **Zero Config** - Sensible defaults, works out of the box
33
+
34
+ ## ✨ Features
35
+
36
+ ### Audio Recording
37
+ - ✅ Cross-platform support (macOS, Linux, Windows)
38
+ - ✅ Device selection and configuration
39
+ - ✅ Configurable sample rates and formats (WAV, MP3, FLAC)
40
+ - ✅ Duration limits and manual stop controls
41
+ - ✅ Custom output paths
42
+ - ✅ Real-time recording status
43
+
44
+ ### Visual Countdown Timers
45
+ - ✅ ANSI color-coded terminal display
46
+ - ✅ In-place updating (no screen clutter)
47
+ - ✅ Audio beeps at configurable intervals
48
+ - ✅ Warning colors when time is low
49
+ - ✅ Callback support for custom behaviors
50
+ - ✅ Graceful cleanup and process handling
51
+
52
+ ### Transcription & Archiving
53
+ - ✅ OpenAI Whisper API integration
54
+ - ✅ Automatic file archiving with timestamps
55
+ - ✅ Transcript preservation in Markdown format
56
+ - ✅ Batch processing support
57
+ - ✅ Error recovery and retry logic
58
+
59
+ ## 📦 Installation
14
60
 
15
61
  ```bash
16
62
  npm install @eldrforge/audio-tools
17
63
  ```
18
64
 
19
- ## Dependencies
65
+ ### Peer Dependencies
20
66
 
21
- - `@theunwalked/unplayable` - Audio recording library
22
- - `@eldrforge/ai-service` - For transcription (Whisper API)
23
- - `@eldrforge/shared` - Optional utilities (peer dependency)
24
- - `winston` - Optional logging (peer dependency)
67
+ The library has optional peer dependencies for enhanced functionality:
68
+
69
+ ```bash
70
+ # For logging (recommended)
71
+ npm install winston
72
+
73
+ # For shared utilities (optional)
74
+ npm install @eldrforge/shared
75
+ ```
25
76
 
26
- ## Usage
77
+ ### System Requirements
78
+
79
+ - **Node.js**: 18.x or later
80
+ - **Operating System**: macOS, Linux, or Windows
81
+ - **Audio Input**: Microphone or audio input device
82
+
83
+ ## 🚀 Quick Start
84
+
85
+ ### Basic Recording
27
86
 
28
87
  ```typescript
29
- import { recordAudio, listAudioDevices } from '@eldrforge/audio-tools';
88
+ import { recordAudio } from '@eldrforge/audio-tools';
30
89
 
31
- // List available devices
32
- const devices = await listAudioDevices();
33
- console.log('Available devices:', devices);
90
+ // Record up to 60 seconds of audio
91
+ const result = await recordAudio({
92
+ duration: 60,
93
+ countdownDelay: 3,
94
+ });
95
+
96
+ console.log('Audio recorded:', result.filePath);
97
+ console.log('Duration:', result.duration, 'seconds');
98
+ console.log('File size:', result.fileSize, 'bytes');
99
+ ```
100
+
101
+ ### Record and Transcribe
102
+
103
+ ```typescript
104
+ import { recordAudio, transcribeAudio, archiveAudio } from '@eldrforge/audio-tools';
34
105
 
35
106
  // Record audio
107
+ const recording = await recordAudio({ duration: 120 });
108
+
109
+ // Transcribe with OpenAI Whisper
110
+ const transcript = await transcribeAudio(recording.filePath);
111
+
112
+ // Archive both audio and transcript with timestamps
113
+ const archive = await archiveAudio(
114
+ recording.filePath,
115
+ transcript,
116
+ 'output/recordings'
117
+ );
118
+
119
+ console.log('Transcript:', transcript);
120
+ console.log('Archived to:', archive.audioPath);
121
+ ```
122
+
123
+ ### Interactive Device Selection
124
+
125
+ ```typescript
126
+ import { selectDeviceInteractive, recordAudio } from '@eldrforge/audio-tools';
127
+
128
+ // Let user select audio device interactively
129
+ const device = await selectDeviceInteractive();
130
+
131
+ // Record with selected device
132
+ const result = await recordAudio({ duration: 60 });
133
+ ```
134
+
135
+ ### Countdown Timer
136
+
137
+ ```typescript
138
+ import { CountdownTimer } from '@eldrforge/audio-tools';
139
+
140
+ const timer = new CountdownTimer({
141
+ durationSeconds: 30,
142
+ beepAt30Seconds: true,
143
+ redAt30Seconds: true,
144
+ onTick: (remaining) => {
145
+ console.log(`${remaining} seconds remaining`);
146
+ },
147
+ onComplete: () => {
148
+ console.log('Time\'s up!');
149
+ }
150
+ });
151
+
152
+ await timer.start();
153
+ ```
154
+
155
+ ## 📖 Documentation
156
+
157
+ Comprehensive documentation is available:
158
+
159
+ - **[Getting Started Guide](docs/GETTING_STARTED.md)** - Step-by-step tutorial for beginners
160
+ - **[Quick Reference](docs/QUICK_REFERENCE.md)** - One-page cheat sheet
161
+ - **[CLI Examples](docs/CLI_EXAMPLES.md)** - Build command-line tools
162
+ - **[FAQ](docs/FAQ.md)** - Frequently asked questions
163
+ - **[Architecture](docs/ARCHITECTURE.md)** - Design and internals
164
+ - **[Contributing Guide](CONTRIBUTING.md)** - How to contribute
165
+ - **[Documentation Index](docs/INDEX.md)** - Complete documentation map
166
+
167
+ ## 📚 Examples
168
+
169
+ The `examples/` directory contains comprehensive, runnable examples:
170
+
171
+ | Example | Description | File |
172
+ |---------|-------------|------|
173
+ | **Basic Recording** | Simple audio recording with default settings | `basic-recording.ts` |
174
+ | **Record & Transcribe** | Complete workflow with transcription and archiving | `record-and-transcribe.ts` |
175
+ | **Countdown Demo** | Visual countdown timer demonstrations | `countdown-demo.ts` |
176
+ | **Device Selection** | List and select audio input devices | `device-selection.ts` |
177
+ | **Custom Output** | Specify custom paths and filenames | `custom-output-path.ts` |
178
+
179
+ ### Running Examples
180
+
181
+ ```bash
182
+ cd examples
183
+ npm install
184
+ npm run basic # Basic recording
185
+ npm run transcribe # Record and transcribe (requires OPENAI_API_KEY)
186
+ npm run countdown # Countdown timer demos
187
+ npm run devices # Device selection
188
+ npm run custom-path # Custom output paths
189
+ ```
190
+
191
+ ## 📖 API Reference
192
+
193
+ ### Recording Functions
194
+
195
+ #### `recordAudio(options?: RecordingOptions): Promise<RecordingResult>`
196
+
197
+ Record audio from an input device.
198
+
199
+ **Options:**
200
+ ```typescript
201
+ interface RecordingOptions {
202
+ device?: AudioDevice | string; // Audio device (optional, uses default)
203
+ duration?: number; // Max duration in seconds (optional)
204
+ outputPath?: string; // Output file path (optional, generates temp)
205
+ countdownDelay?: number; // Countdown delay (default: 3)
206
+ sampleRate?: number; // Sample rate in Hz (default: 44100)
207
+ format?: 'wav' | 'mp3' | 'flac'; // Audio format (default: 'wav')
208
+ }
209
+ ```
210
+
211
+ **Returns:**
212
+ ```typescript
213
+ interface RecordingResult {
214
+ filePath: string; // Path to recorded file
215
+ duration: number; // Recording duration in seconds
216
+ fileSize: number; // File size in bytes
217
+ }
218
+ ```
219
+
220
+ **Example:**
221
+ ```typescript
36
222
  const result = await recordAudio({
37
- duration: 30,
38
- countdownDelay: 3,
223
+ duration: 60,
224
+ sampleRate: 48000,
225
+ format: 'wav',
226
+ countdownDelay: 3
39
227
  });
228
+ ```
40
229
 
41
- console.log('Audio recorded to:', result.filePath);
230
+ ---
231
+
232
+ #### `archiveAudio(audioPath: string, transcript: string, outputDir?: string)`
233
+
234
+ Archive audio file with its transcription.
235
+
236
+ **Parameters:**
237
+ - `audioPath`: Path to the original audio file
238
+ - `transcript`: Transcribed text content
239
+ - `outputDir`: Directory to save archived files (default: 'output')
240
+
241
+ **Returns:**
242
+ ```typescript
243
+ {
244
+ audioPath: string; // Path to archived audio file
245
+ transcriptPath: string; // Path to archived transcript
246
+ }
42
247
  ```
43
248
 
44
- More documentation coming as functionality is extracted.
249
+ **Example:**
250
+ ```typescript
251
+ const archive = await archiveAudio(
252
+ 'recording.wav',
253
+ 'This is the transcribed text...',
254
+ 'output/archives'
255
+ );
256
+
257
+ // Creates files like:
258
+ // - output/archives/250701-1430-review-audio.wav
259
+ // - output/archives/250701-1430-review-transcript.md
260
+ ```
45
261
 
46
- ## Development
262
+ ---
263
+
264
+ #### `deleteAudio(audioPath: string): Promise<void>`
265
+
266
+ Delete an audio file safely.
267
+
268
+ **Example:**
269
+ ```typescript
270
+ await deleteAudio('temp-recording.wav');
271
+ ```
272
+
273
+ ---
274
+
275
+ #### `getAudioDuration(audioPath: string): Promise<number | null>`
276
+
277
+ Get the duration of an audio file (currently returns null, planned feature).
278
+
279
+ ---
280
+
281
+ ### Device Functions
282
+
283
+ #### `listAudioDevices(): Promise<AudioDevice[]>`
284
+
285
+ List all available audio input devices.
286
+
287
+ **Returns:**
288
+ ```typescript
289
+ interface AudioDevice {
290
+ id: string;
291
+ name: string;
292
+ isDefault: boolean;
293
+ }
294
+ ```
295
+
296
+ **Example:**
297
+ ```typescript
298
+ const devices = await listAudioDevices();
299
+ devices.forEach(device => {
300
+ console.log(`${device.name} (${device.id})`);
301
+ if (device.isDefault) {
302
+ console.log(' ✓ Default device');
303
+ }
304
+ });
305
+ ```
306
+
307
+ ---
308
+
309
+ #### `getDefaultDevice(): Promise<AudioDevice | null>`
310
+
311
+ Get the system's default audio input device.
312
+
313
+ **Example:**
314
+ ```typescript
315
+ const device = await getDefaultDevice();
316
+ if (device) {
317
+ console.log('Default device:', device.name);
318
+ }
319
+ ```
320
+
321
+ ---
322
+
323
+ #### `findDevice(idOrName: string): Promise<AudioDevice | null>`
324
+
325
+ Find a device by its ID or name.
326
+
327
+ **Example:**
328
+ ```typescript
329
+ const device = await findDevice('MacBook Pro Microphone');
330
+ if (device) {
331
+ console.log('Found device:', device.id);
332
+ }
333
+ ```
334
+
335
+ ---
336
+
337
+ #### `selectDeviceInteractive(): Promise<string>`
338
+
339
+ Present an interactive menu to select an audio device.
340
+
341
+ **Example:**
342
+ ```typescript
343
+ const deviceId = await selectDeviceInteractive();
344
+ console.log('Selected device:', deviceId);
345
+ ```
346
+
347
+ ---
348
+
349
+ ### Transcription Functions
350
+
351
+ #### `transcribeAudio(audioPath: string): Promise<string>`
352
+
353
+ Transcribe an audio file using OpenAI's Whisper API.
354
+
355
+ **Requirements:**
356
+ - `OPENAI_API_KEY` environment variable must be set
357
+ - Audio file must be in a supported format (WAV, MP3, FLAC, etc.)
358
+
359
+ **Example:**
360
+ ```typescript
361
+ const transcript = await transcribeAudio('recording.wav');
362
+ console.log('Transcription:', transcript);
363
+ ```
364
+
365
+ ---
366
+
367
+ ### Countdown Timer Classes
368
+
369
+ #### `CountdownTimer`
370
+
371
+ A visual countdown timer with customizable behavior.
372
+
373
+ **Constructor Options:**
374
+ ```typescript
375
+ interface CountdownOptions {
376
+ durationSeconds: number; // Duration in seconds
377
+ beepAt30Seconds?: boolean; // Beep at 30s (default: true)
378
+ redAt30Seconds?: boolean; // Red color at 30s (default: true)
379
+ onTick?: (remaining: number) => void; // Called every second
380
+ onComplete?: () => void; // Called when complete
381
+ clearOnComplete?: boolean; // Clear display when done (default: false)
382
+ }
383
+ ```
384
+
385
+ **Methods:**
386
+ - `start(): Promise<void>` - Start the countdown
387
+ - `stop(): void` - Stop the countdown
388
+ - `getRemainingSeconds(): number` - Get remaining time
389
+ - `destroy(): void` - Clean up resources
390
+ - `isTimerDestroyed(): boolean` - Check if destroyed
391
+
392
+ **Example:**
393
+ ```typescript
394
+ const timer = new CountdownTimer({
395
+ durationSeconds: 60,
396
+ beepAt30Seconds: true,
397
+ redAt30Seconds: true,
398
+ onTick: (remaining) => {
399
+ if (remaining % 10 === 0) {
400
+ console.log(`${remaining} seconds left`);
401
+ }
402
+ },
403
+ onComplete: () => {
404
+ console.log('Recording complete!');
405
+ }
406
+ });
407
+
408
+ await timer.start();
409
+ ```
410
+
411
+ ---
412
+
413
+ #### `startCountdown(options: CountdownOptions): Promise<void>`
414
+
415
+ Convenience function to create and start a countdown timer.
416
+
417
+ **Example:**
418
+ ```typescript
419
+ await startCountdown({
420
+ durationSeconds: 30,
421
+ onComplete: () => console.log('Done!')
422
+ });
423
+ ```
424
+
425
+ ---
426
+
427
+ #### `createAudioRecordingCountdown(seconds: number): CountdownTimer`
428
+
429
+ Create a countdown timer with sensible defaults for audio recording.
430
+
431
+ **Example:**
432
+ ```typescript
433
+ const timer = createAudioRecordingCountdown(120);
434
+ await timer.start();
435
+ ```
436
+
437
+ ---
438
+
439
+ ### Utility Functions
440
+
441
+ #### `getTimestampedArchivedAudioFilename(extension?: string): string`
442
+
443
+ Generate a timestamped filename for archived audio.
444
+
445
+ **Example:**
446
+ ```typescript
447
+ const filename = getTimestampedArchivedAudioFilename('.mp3');
448
+ // Returns: "250701-1430-review-audio.mp3"
449
+ ```
450
+
451
+ ---
452
+
453
+ #### `getTimestampedArchivedTranscriptFilename(): string`
454
+
455
+ Generate a timestamped filename for archived transcripts.
456
+
457
+ **Example:**
458
+ ```typescript
459
+ const filename = getTimestampedArchivedTranscriptFilename();
460
+ // Returns: "250701-1430-review-transcript.md"
461
+ ```
462
+
463
+ ---
464
+
465
+ ### Logging
466
+
467
+ #### `setLogger(logger: Logger): void`
468
+
469
+ Set a custom Winston logger instance.
470
+
471
+ **Example:**
472
+ ```typescript
473
+ import { setLogger } from '@eldrforge/audio-tools';
474
+ import { createLogger, format, transports } from 'winston';
475
+
476
+ const logger = createLogger({
477
+ level: 'debug',
478
+ format: format.combine(
479
+ format.timestamp(),
480
+ format.colorize(),
481
+ format.simple()
482
+ ),
483
+ transports: [
484
+ new transports.Console(),
485
+ new transports.File({ filename: 'audio-tools.log' })
486
+ ]
487
+ });
488
+
489
+ setLogger(logger);
490
+ ```
491
+
492
+ ---
493
+
494
+ #### `getLogger(): Logger`
495
+
496
+ Get the current logger instance.
497
+
498
+ **Example:**
499
+ ```typescript
500
+ import { getLogger } from '@eldrforge/audio-tools';
501
+
502
+ const logger = getLogger();
503
+ logger.info('Starting recording...');
504
+ ```
505
+
506
+ ---
507
+
508
+ ## 🎬 Complete Usage Example
509
+
510
+ Here's a complete example showing a typical workflow:
511
+
512
+ ```typescript
513
+ import {
514
+ recordAudio,
515
+ transcribeAudio,
516
+ archiveAudio,
517
+ deleteAudio,
518
+ CountdownTimer,
519
+ setLogger
520
+ } from '@eldrforge/audio-tools';
521
+ import { createLogger, format, transports } from 'winston';
522
+ import { config } from 'dotenv';
523
+
524
+ // Load environment variables
525
+ config();
526
+
527
+ // Configure logging
528
+ const logger = createLogger({
529
+ level: 'info',
530
+ format: format.combine(
531
+ format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
532
+ format.colorize(),
533
+ format.printf(({ timestamp, level, message }) =>
534
+ `${timestamp} [${level}]: ${message}`
535
+ )
536
+ ),
537
+ transports: [
538
+ new transports.Console(),
539
+ new transports.File({ filename: 'audio-tools.log' })
540
+ ]
541
+ });
542
+
543
+ setLogger(logger);
544
+
545
+ async function recordAndTranscribeVoiceNote() {
546
+ let audioPath: string | null = null;
547
+
548
+ try {
549
+ console.log('🎙️ Voice Note Recorder');
550
+ console.log('======================\n');
551
+
552
+ // Step 1: Countdown
553
+ console.log('Get ready to speak...\n');
554
+ const countdown = new CountdownTimer({
555
+ durationSeconds: 3,
556
+ beepAt30Seconds: false,
557
+ clearOnComplete: true
558
+ });
559
+ await countdown.start();
560
+
561
+ // Step 2: Record
562
+ console.log('🔴 Recording... (Press ENTER to stop)\n');
563
+ const recording = await recordAudio({
564
+ duration: 300, // 5 minutes max
565
+ sampleRate: 48000,
566
+ format: 'wav'
567
+ });
568
+
569
+ audioPath = recording.filePath;
570
+ logger.info(`Recorded ${recording.duration.toFixed(2)}s of audio`);
571
+
572
+ // Step 3: Transcribe
573
+ console.log('\n📝 Transcribing...');
574
+ const transcript = await transcribeAudio(audioPath);
575
+
576
+ console.log('\n✅ Transcript:\n');
577
+ console.log('─'.repeat(60));
578
+ console.log(transcript);
579
+ console.log('─'.repeat(60));
580
+
581
+ // Step 4: Archive
582
+ console.log('\n💾 Archiving...');
583
+ const archive = await archiveAudio(
584
+ audioPath,
585
+ transcript,
586
+ 'output/voice-notes'
587
+ );
588
+
589
+ logger.info(`Archived to: ${archive.audioPath}`);
590
+ logger.info(`Transcript saved: ${archive.transcriptPath}`);
591
+
592
+ // Step 5: Cleanup
593
+ await deleteAudio(audioPath);
594
+ logger.info('Temporary file deleted');
595
+
596
+ console.log('\n✅ Voice note saved successfully!');
597
+
598
+ } catch (error) {
599
+ logger.error('Failed to process voice note:', error);
600
+
601
+ // Cleanup on error
602
+ if (audioPath) {
603
+ try {
604
+ await deleteAudio(audioPath);
605
+ } catch {
606
+ // Ignore cleanup errors
607
+ }
608
+ }
609
+
610
+ throw error;
611
+ }
612
+ }
613
+
614
+ // Run the example
615
+ recordAndTranscribeVoiceNote().catch(error => {
616
+ console.error('\n❌ Error:', error.message);
617
+ process.exit(1);
618
+ });
619
+ ```
620
+
621
+ ## 🔧 Configuration
622
+
623
+ ### Environment Variables
624
+
625
+ - `OPENAI_API_KEY` - Required for transcription functionality
626
+ - `NO_COLOR` - Disable ANSI colors in terminal output
627
+ - `TERM` - Terminal type detection for ANSI support
628
+
629
+ ### Audio Preferences
630
+
631
+ The library uses `@theunwalked/unplayable` which stores audio device preferences in:
632
+ ```
633
+ ~/.unplayable/audio-preferences.json
634
+ ```
635
+
636
+ You can manually edit this file to set default devices.
637
+
638
+ ## 🏗️ Architecture
639
+
640
+ ### Dependencies
641
+
642
+ - **[@theunwalked/unplayable](https://github.com/theunwalked/unplayable)** - Cross-platform audio recording
643
+ - **[@eldrforge/ai-service](https://github.com/calenvarek/ai-service)** - OpenAI Whisper integration
644
+ - **[@eldrforge/shared](https://github.com/calenvarek/shared)** - Optional shared utilities
645
+ - **winston** - Optional structured logging
646
+
647
+ ### Platform Support
648
+
649
+ | Platform | Status | Backend |
650
+ |----------|--------|---------|
651
+ | macOS | ✅ Supported | CoreAudio |
652
+ | Linux | ✅ Supported | ALSA/PulseAudio |
653
+ | Windows | ✅ Supported | WASAPI |
654
+
655
+ ## 🧪 Testing
656
+
657
+ The library includes comprehensive test coverage:
47
658
 
48
659
  ```bash
660
+ # Run tests
661
+ npm test
662
+
663
+ # Run tests with coverage
664
+ npm run test
665
+
666
+ # Watch mode
667
+ npm run test -- --watch
668
+ ```
669
+
670
+ ## 🛠️ Development
671
+
672
+ ### Build from Source
673
+
674
+ ```bash
675
+ # Clone the repository
676
+ git clone https://github.com/calenvarek/audio-tools.git
677
+ cd audio-tools
678
+
49
679
  # Install dependencies
50
680
  npm install
51
681
 
52
682
  # Build
53
683
  npm run build
54
684
 
55
- # Test
56
- npm run test
685
+ # Run tests
686
+ npm test
57
687
 
58
688
  # Lint
59
689
  npm run lint
60
690
  ```
61
691
 
62
- ## Platform Support
692
+ ### Project Structure
693
+
694
+ ```
695
+ audio-tools/
696
+ ├── src/
697
+ │ ├── countdown.ts # Countdown timer utilities
698
+ │ ├── devices.ts # Audio device management
699
+ │ ├── recording.ts # Recording and archiving
700
+ │ ├── transcription.ts # Transcription wrapper
701
+ │ ├── types.ts # TypeScript definitions
702
+ │ └── index.ts # Main exports
703
+ ├── tests/ # Test files
704
+ ├── examples/ # Usage examples
705
+ ├── dist/ # Compiled output
706
+ └── package.json
707
+ ```
708
+
709
+ ## 🤝 Contributing
710
+
711
+ Contributions are welcome! Please:
712
+
713
+ 1. Fork the repository
714
+ 2. Create a feature branch: `git checkout -b feature/my-feature`
715
+ 3. Make your changes with tests
716
+ 4. Run tests: `npm test`
717
+ 5. Commit with clear messages
718
+ 6. Push and open a Pull Request
719
+
720
+ ## 📝 License
721
+
722
+ Apache-2.0 License - see [LICENSE](LICENSE) file for details.
723
+
724
+ ## 🔗 Related Projects
725
+
726
+ - **[@eldrforge/ai-service](https://github.com/calenvarek/ai-service)** - AI services including transcription
727
+ - **[@eldrforge/shared](https://github.com/calenvarek/shared)** - Shared utilities
728
+ - **[@theunwalked/unplayable](https://github.com/theunwalked/unplayable)** - Cross-platform audio library
729
+
730
+ ## 💬 Support
731
+
732
+ - 🚀 **Getting Started**: [Tutorial Guide](docs/GETTING_STARTED.md)
733
+ - 📖 **Documentation**: [Complete Docs](docs/INDEX.md)
734
+ - 🐛 **Issues**: [GitHub Issues](https://github.com/calenvarek/audio-tools/issues)
735
+ - 💡 **Discussions**: [GitHub Discussions](https://github.com/calenvarek/audio-tools/discussions)
736
+ - ❓ **FAQ**: [Frequently Asked Questions](docs/FAQ.md)
737
+
738
+ ## 📊 Changelog
739
+
740
+ See [RELEASE_NOTES.md](RELEASE_NOTES.md) for version history and changes.
63
741
 
64
- - ✅ macOS (CoreAudio)
65
- - ✅ Linux (ALSA/PulseAudio)
66
- - ✅ Windows (WASAPI)
742
+ ---
67
743
 
68
- Platform-specific requirements may apply.
744
+ <div align="center">
69
745
 
70
- ## License
746
+ Made with ❤️ by [Calen Varek](https://github.com/calenvarek)
71
747
 
72
- Apache-2.0
748
+ ⭐ Star this repo if you find it useful!
73
749
 
750
+ </div>