peasy-audio-js 0.1.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Peasy Tools
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,263 @@
1
+ # peasy-audio-js
2
+
3
+ [![npm](https://img.shields.io/npm/v/peasy-audio-js)](https://www.npmjs.com/package/peasy-audio-js)
4
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.7-blue)](https://www.typescriptlang.org/)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
6
+
7
+ Audio processing library for Node.js -- convert between 6 formats (MP3, WAV, OGG, FLAC, AAC, M4A), trim segments, merge files, normalize volume, apply fade effects, adjust speed, and generate silence. FFmpeg-powered, TypeScript-first with full type safety.
8
+
9
+ Built from [PeasyAudio](https://peasyaudio.com), a free online audio toolkit with 10 browser-based tools for converting, trimming, merging, normalizing, and analyzing audio files.
10
+
11
+ > **Try the interactive tools at [peasyaudio.com](https://peasyaudio.com)** -- audio conversion, trimming, merging, normalization, and analysis
12
+
13
+ <p align="center">
14
+ <img src="demo.gif" alt="peasy-audio-js demo — audio info, format conversion, and volume operations in Node.js" width="800">
15
+ </p>
16
+
17
+ ## Table of Contents
18
+
19
+ - [Prerequisites](#prerequisites)
20
+ - [Install](#install)
21
+ - [Quick Start](#quick-start)
22
+ - [What You Can Do](#what-you-can-do)
23
+ - [Audio Info & Metadata](#audio-info--metadata)
24
+ - [Format Conversion](#format-conversion)
25
+ - [Trimming & Merging](#trimming--merging)
26
+ - [Volume & Normalization](#volume--normalization)
27
+ - [Audio Effects](#audio-effects)
28
+ - [TypeScript Types](#typescript-types)
29
+ - [API Reference](#api-reference)
30
+ - [Also Available for Python](#also-available-for-python)
31
+ - [Peasy Developer Tools](#peasy-developer-tools)
32
+ - [License](#license)
33
+
34
+ ## Prerequisites
35
+
36
+ peasy-audio-js uses FFmpeg under the hood. Install it before using this library:
37
+
38
+ | Platform | Command |
39
+ |----------|---------|
40
+ | **macOS** | `brew install ffmpeg` |
41
+ | **Ubuntu/Debian** | `sudo apt install ffmpeg` |
42
+ | **Fedora/RHEL** | `sudo dnf install ffmpeg-free` |
43
+ | **Windows** | `choco install ffmpeg` |
44
+
45
+ ## Install
46
+
47
+ ```bash
48
+ npm install peasy-audio-js
49
+ ```
50
+
51
+ ## Quick Start
52
+
53
+ ```typescript
54
+ import { info, convert, trim, merge, normalize } from "peasy-audio-js";
55
+
56
+ // Get audio file metadata
57
+ const metadata = await info("song.mp3");
58
+ console.log(metadata.duration, metadata.sampleRate); // 240.5 44100
59
+
60
+ // Convert MP3 to WAV
61
+ const wavPath = await convert("song.mp3", { format: "wav" });
62
+
63
+ // Trim to 30-second clip
64
+ const clip = await trim("song.mp3", { start: 10, duration: 30 });
65
+
66
+ // Merge multiple audio files
67
+ const combined = await merge(["intro.mp3", "main.mp3", "outro.mp3"]);
68
+
69
+ // Normalize volume to consistent levels
70
+ const normalized = await normalize("quiet-recording.mp3");
71
+ ```
72
+
73
+ ## What You Can Do
74
+
75
+ ### Audio Info & Metadata
76
+
77
+ Every audio file has metadata -- duration, sample rate, channels, bitrate, and codec information. The `info()` function uses FFprobe to extract this data without decoding the entire file, making it fast even for large files.
78
+
79
+ ```typescript
80
+ import { info } from "peasy-audio-js";
81
+
82
+ // Extract audio metadata using FFprobe
83
+ const meta = await info("podcast.mp3");
84
+ console.log(meta.duration); // 3600.5 (seconds)
85
+ console.log(meta.sampleRate); // 44100 (Hz)
86
+ console.log(meta.channels); // 2 (stereo)
87
+ console.log(meta.bitrate); // 320000 (bits/sec)
88
+ console.log(meta.format); // "mp3"
89
+ ```
90
+
91
+ Learn more: [Peasy Audio Tools](https://peasyaudio.com) · [Glossary](https://peasytools.com/glossary/)
92
+
93
+ ### Format Conversion
94
+
95
+ Audio format conversion transforms audio data between container formats and codecs. Common conversions include MP3 to WAV (for editing), WAV to FLAC (lossless archiving), and any format to AAC/M4A (Apple ecosystem compatibility).
96
+
97
+ | Format | Extension | Use Case |
98
+ |--------|-----------|----------|
99
+ | MP3 | `.mp3` | Universal playback, streaming |
100
+ | WAV | `.wav` | Editing, uncompressed quality |
101
+ | OGG | `.ogg` | Open-source, web audio |
102
+ | FLAC | `.flac` | Lossless archiving |
103
+ | AAC | `.aac` | Apple ecosystem, efficient |
104
+ | M4A | `.m4a` | iTunes, Apple Music |
105
+
106
+ ```typescript
107
+ import { convert } from "peasy-audio-js";
108
+
109
+ // Convert MP3 to WAV for editing
110
+ const wav = await convert("music.mp3", { format: "wav" });
111
+
112
+ // Convert to FLAC with custom sample rate
113
+ const flac = await convert("music.mp3", {
114
+ format: "flac",
115
+ sampleRate: 48000,
116
+ });
117
+
118
+ // Downmix stereo to mono
119
+ const mono = await convert("stereo.wav", {
120
+ format: "mp3",
121
+ channels: 1,
122
+ bitrate: "128k",
123
+ });
124
+ ```
125
+
126
+ Learn more: [Peasy Audio Tools](https://peasyaudio.com) · [Glossary](https://peasytools.com/glossary/)
127
+
128
+ ### Trimming & Merging
129
+
130
+ Audio trimming extracts a segment by specifying start time and duration or end time. Merging concatenates multiple audio files sequentially into a single output file.
131
+
132
+ ```typescript
133
+ import { trim, merge } from "peasy-audio-js";
134
+
135
+ // Extract a 30-second segment starting at 1 minute
136
+ const clip = await trim("podcast.mp3", { start: 60, duration: 30 });
137
+
138
+ // Trim from start to end time
139
+ const intro = await trim("song.mp3", { start: 0, end: 15 });
140
+
141
+ // Merge multiple files into one
142
+ const combined = await merge([
143
+ "chapter1.mp3",
144
+ "chapter2.mp3",
145
+ "chapter3.mp3",
146
+ ]);
147
+ ```
148
+
149
+ Learn more: [Peasy Audio Tools](https://peasyaudio.com) · [Glossary](https://peasytools.com/glossary/)
150
+
151
+ ### Volume & Normalization
152
+
153
+ Audio normalization adjusts the overall volume level to a target loudness, measured in dBFS (decibels relative to full scale). The EBU R128 standard defines target loudness at -23 LUFS for broadcast, while streaming platforms typically target -14 LUFS.
154
+
155
+ ```typescript
156
+ import { normalize, changeVolume } from "peasy-audio-js";
157
+
158
+ // Normalize volume using FFmpeg loudnorm filter
159
+ const normalized = await normalize("quiet-recording.mp3");
160
+
161
+ // Increase volume by 6dB (roughly doubles perceived loudness)
162
+ const louder = await changeVolume("track.mp3", { change: 6 });
163
+
164
+ // Decrease volume by 3dB
165
+ const softer = await changeVolume("loud-track.mp3", { change: -3 });
166
+ ```
167
+
168
+ Learn more: [Peasy Audio Tools](https://peasyaudio.com) · [Glossary](https://peasytools.com/glossary/)
169
+
170
+ ### Audio Effects
171
+
172
+ Apply fade effects, speed changes, reversal, and generate silence programmatically. These operations use FFmpeg audio filters for sample-accurate processing.
173
+
174
+ ```typescript
175
+ import { fade, speed, reverseAudio, silence } from "peasy-audio-js";
176
+
177
+ // Apply 3-second fade in and 5-second fade out
178
+ const faded = await fade("song.mp3", { fadeIn: 3, fadeOut: 5 });
179
+
180
+ // Double the playback speed (pitch shifts)
181
+ const fast = await speed("podcast.mp3", { factor: 2.0 });
182
+
183
+ // Slow down to 75% speed
184
+ const slow = await speed("audiobook.mp3", { factor: 0.75 });
185
+
186
+ // Reverse audio
187
+ const reversed = await reverseAudio("sample.mp3");
188
+
189
+ // Generate 5 seconds of silence as WAV
190
+ const gap = await silence({ duration: 5, format: "wav", sampleRate: 44100 });
191
+ ```
192
+
193
+ Learn more: [Peasy Audio Tools](https://peasyaudio.com) · [Glossary](https://peasytools.com/glossary/)
194
+
195
+ ## TypeScript Types
196
+
197
+ ```typescript
198
+ import type {
199
+ AudioFormat,
200
+ AudioInfo,
201
+ ConvertOptions,
202
+ TrimOptions,
203
+ FadeOptions,
204
+ SpeedOptions,
205
+ VolumeOptions,
206
+ SilenceOptions,
207
+ } from "peasy-audio-js";
208
+
209
+ // AudioFormat — "mp3" | "wav" | "ogg" | "flac" | "aac" | "m4a"
210
+ const format: AudioFormat = "mp3";
211
+
212
+ // AudioInfo — metadata from info()
213
+ const meta: AudioInfo = {
214
+ duration: 240.5,
215
+ format: "mp3",
216
+ sampleRate: 44100,
217
+ channels: 2,
218
+ bitrate: 320000,
219
+ size: 9_600_000,
220
+ };
221
+ ```
222
+
223
+ ## API Reference
224
+
225
+ | Function | Description |
226
+ |----------|-------------|
227
+ | `info(input)` | Get audio metadata (duration, format, sample rate, channels, bitrate) |
228
+ | `convert(input, options)` | Convert between audio formats (MP3, WAV, OGG, FLAC, AAC, M4A) |
229
+ | `trim(input, options)` | Extract a segment by start/end/duration |
230
+ | `merge(inputs)` | Concatenate multiple audio files sequentially |
231
+ | `normalize(input)` | Normalize volume using EBU R128 loudnorm filter |
232
+ | `changeVolume(input, options)` | Adjust volume by dB amount |
233
+ | `fade(input, options)` | Apply fade in/out effects |
234
+ | `speed(input, options)` | Change playback speed (0.5x to 4.0x) |
235
+ | `reverseAudio(input)` | Reverse audio playback |
236
+ | `silence(options)` | Generate silence of specified duration |
237
+
238
+ ## Also Available for Python
239
+
240
+ ```bash
241
+ pip install peasy-audio
242
+ ```
243
+
244
+ The Python package provides the same 12 audio operations with CLI and pydub engine. See [peasy-audio on PyPI](https://pypi.org/project/peasy-audio/).
245
+
246
+ ## Peasy Developer Tools
247
+
248
+ | Package | PyPI | npm | Description |
249
+ |---------|------|-----|-------------|
250
+ | peasy-pdf | [PyPI](https://pypi.org/project/peasy-pdf/) | [npm](https://www.npmjs.com/package/peasy-pdf-js) | PDF merge, split, compress, rotate, watermark |
251
+ | peasy-image | [PyPI](https://pypi.org/project/peasy-image/) | [npm](https://www.npmjs.com/package/peasy-image-js) | Image resize, crop, compress, convert, watermark |
252
+ | peasytext | [PyPI](https://pypi.org/project/peasytext/) | [npm](https://www.npmjs.com/package/peasytext-js) | Text analysis, case conversion, slugs, word count |
253
+ | peasy-css | [PyPI](https://pypi.org/project/peasy-css/) | [npm](https://www.npmjs.com/package/peasy-css-js) | CSS gradients, shadows, flexbox, grid generators |
254
+ | peasy-compress | [PyPI](https://pypi.org/project/peasy-compress/) | [npm](https://www.npmjs.com/package/peasy-compress-js) | ZIP, gzip, brotli, deflate compression |
255
+ | peasy-document | [PyPI](https://pypi.org/project/peasy-document/) | [npm](https://www.npmjs.com/package/peasy-document-js) | Markdown, HTML, CSV, JSON, YAML conversion |
256
+ | **peasy-audio** | [PyPI](https://pypi.org/project/peasy-audio/) | **[npm](https://www.npmjs.com/package/peasy-audio-js)** | **Audio convert, trim, merge, normalize, effects** |
257
+ | peasy-video | [PyPI](https://pypi.org/project/peasy-video/) | [npm](https://www.npmjs.com/package/peasy-video-js) | Video trim, resize, thumbnails, GIF conversion |
258
+
259
+ Part of the [Peasy](https://peasytools.com) developer tools ecosystem.
260
+
261
+ ## License
262
+
263
+ MIT
@@ -0,0 +1,238 @@
1
+ /**
2
+ * peasy-audio-js — Audio processing types.
3
+ *
4
+ * @packageDocumentation
5
+ */
6
+ /** Supported audio formats. */
7
+ type AudioFormat = "mp3" | "wav" | "ogg" | "flac" | "aac" | "m4a";
8
+ /** Audio file metadata. */
9
+ interface AudioInfo {
10
+ /** Duration in seconds. */
11
+ duration: number;
12
+ /** Container format name (e.g. "mp3", "wav"). */
13
+ format: string;
14
+ /** Sample rate in Hz (e.g. 44100, 48000). */
15
+ sampleRate: number;
16
+ /** Number of audio channels (1 = mono, 2 = stereo). */
17
+ channels: number;
18
+ /** Bitrate in bits per second. */
19
+ bitrate: number;
20
+ /** File size in bytes. */
21
+ size: number;
22
+ }
23
+ /** Options for audio conversion. */
24
+ interface ConvertOptions {
25
+ /** Target audio format. */
26
+ format: AudioFormat;
27
+ /** Target bitrate (e.g. "128k", "320k"). */
28
+ bitrate?: string;
29
+ /** Target sample rate in Hz (e.g. 44100, 48000). */
30
+ sampleRate?: number;
31
+ /** Number of output channels (1 = mono, 2 = stereo). */
32
+ channels?: number;
33
+ }
34
+ /** Options for audio trimming. */
35
+ interface TrimOptions {
36
+ /** Start time in seconds. */
37
+ start?: number;
38
+ /** End time in seconds. */
39
+ end?: number;
40
+ /** Duration in seconds (alternative to end). */
41
+ duration?: number;
42
+ }
43
+ /** Options for fade effects. */
44
+ interface FadeOptions {
45
+ /** Fade-in duration in seconds. */
46
+ fadeIn?: number;
47
+ /** Fade-out duration in seconds. */
48
+ fadeOut?: number;
49
+ }
50
+ /** Options for speed adjustment. */
51
+ interface SpeedOptions {
52
+ /** Speed factor (e.g. 0.5 = half speed, 2.0 = double speed). */
53
+ factor: number;
54
+ }
55
+ /** Options for volume adjustment. */
56
+ interface VolumeOptions {
57
+ /** Volume change in dB (e.g., 3 for +3dB, -5 for -5dB). */
58
+ change: number;
59
+ }
60
+ /** Options for silence generation. */
61
+ interface SilenceOptions {
62
+ /** Duration of silence in seconds. */
63
+ duration: number;
64
+ /** Output format (default: "wav"). */
65
+ format?: AudioFormat;
66
+ /** Sample rate in Hz (default: 44100). */
67
+ sampleRate?: number;
68
+ }
69
+
70
+ /**
71
+ * peasy-audio-js — Audio processing engine.
72
+ *
73
+ * All operations use fluent-ffmpeg to invoke FFmpeg for audio processing.
74
+ * Functions take file paths and return Promises that resolve to output paths.
75
+ *
76
+ * @packageDocumentation
77
+ */
78
+
79
+ /**
80
+ * Get metadata for an audio file using ffprobe.
81
+ *
82
+ * @param input - Path to the audio file
83
+ * @returns Audio metadata including duration, format, sample rate, channels
84
+ *
85
+ * @example
86
+ * ```typescript
87
+ * const metadata = await info("song.mp3");
88
+ * console.log(metadata.duration); // 180.5
89
+ * console.log(metadata.sampleRate); // 44100
90
+ * ```
91
+ */
92
+ declare function info(input: string): Promise<AudioInfo>;
93
+ /**
94
+ * Convert an audio file to a different format.
95
+ *
96
+ * @param input - Path to the source audio file
97
+ * @param options - Conversion options (format, bitrate, sampleRate, channels)
98
+ * @returns Path to the converted output file
99
+ *
100
+ * @example
101
+ * ```typescript
102
+ * // Convert MP3 to WAV
103
+ * const wav = await convert("song.mp3", { format: "wav" });
104
+ *
105
+ * // Convert with specific bitrate and sample rate
106
+ * const mp3 = await convert("song.wav", {
107
+ * format: "mp3",
108
+ * bitrate: "320k",
109
+ * sampleRate: 48000,
110
+ * });
111
+ * ```
112
+ */
113
+ declare function convert(input: string, options: ConvertOptions): Promise<string>;
114
+ /**
115
+ * Trim an audio file to a specific time range.
116
+ *
117
+ * @param input - Path to the source audio file
118
+ * @param options - Trim options (start, end, duration)
119
+ * @returns Path to the trimmed output file
120
+ *
121
+ * @example
122
+ * ```typescript
123
+ * // Trim from 10s to 30s
124
+ * const trimmed = await trim("song.mp3", { start: 10, end: 30 });
125
+ *
126
+ * // Trim first 5 seconds
127
+ * const intro = await trim("song.mp3", { start: 0, duration: 5 });
128
+ * ```
129
+ */
130
+ declare function trim(input: string, options: TrimOptions): Promise<string>;
131
+ /**
132
+ * Merge multiple audio files into a single file.
133
+ *
134
+ * Files are concatenated in the order provided. All files should have
135
+ * compatible formats (same sample rate and channels for best results).
136
+ *
137
+ * @param inputs - Array of paths to audio files to merge
138
+ * @returns Path to the merged output file
139
+ *
140
+ * @example
141
+ * ```typescript
142
+ * const merged = await merge(["intro.mp3", "main.mp3", "outro.mp3"]);
143
+ * ```
144
+ */
145
+ declare function merge(inputs: string[]): Promise<string>;
146
+ /**
147
+ * Normalize audio loudness using the EBU R128 loudnorm filter.
148
+ *
149
+ * @param input - Path to the source audio file
150
+ * @returns Path to the normalized output file
151
+ *
152
+ * @example
153
+ * ```typescript
154
+ * const normalized = await normalize("quiet-recording.mp3");
155
+ * ```
156
+ */
157
+ declare function normalize(input: string): Promise<string>;
158
+ /**
159
+ * Adjust the volume of an audio file.
160
+ *
161
+ * @param input - Path to the source audio file
162
+ * @param options - Volume options with change in dB
163
+ * @returns Path to the volume-adjusted output file
164
+ *
165
+ * @example
166
+ * ```typescript
167
+ * // Increase volume by 3 dB
168
+ * const louder = await changeVolume("song.mp3", { change: 3 });
169
+ *
170
+ * // Decrease volume by 5 dB
171
+ * const quieter = await changeVolume("song.mp3", { change: -5 });
172
+ * ```
173
+ */
174
+ declare function changeVolume(input: string, options: VolumeOptions): Promise<string>;
175
+ /**
176
+ * Apply fade-in and/or fade-out effects to an audio file.
177
+ *
178
+ * @param input - Path to the source audio file
179
+ * @param options - Fade options with fadeIn and/or fadeOut durations in seconds
180
+ * @returns Path to the output file with fade effects
181
+ *
182
+ * @example
183
+ * ```typescript
184
+ * // Fade in over 2 seconds and fade out over 3 seconds
185
+ * const faded = await fade("song.mp3", { fadeIn: 2, fadeOut: 3 });
186
+ * ```
187
+ */
188
+ declare function fade(input: string, options: FadeOptions): Promise<string>;
189
+ /**
190
+ * Change the playback speed of an audio file.
191
+ *
192
+ * Uses the atempo filter which supports factors between 0.5 and 100.0.
193
+ * For factors outside the 0.5-2.0 range, multiple atempo filters are chained.
194
+ *
195
+ * @param input - Path to the source audio file
196
+ * @param options - Speed options with factor (e.g. 0.5 = half, 2.0 = double)
197
+ * @returns Path to the speed-adjusted output file
198
+ *
199
+ * @example
200
+ * ```typescript
201
+ * // Double speed
202
+ * const fast = await speed("podcast.mp3", { factor: 2.0 });
203
+ *
204
+ * // Half speed
205
+ * const slow = await speed("podcast.mp3", { factor: 0.5 });
206
+ * ```
207
+ */
208
+ declare function speed(input: string, options: SpeedOptions): Promise<string>;
209
+ /**
210
+ * Reverse an audio file.
211
+ *
212
+ * @param input - Path to the source audio file
213
+ * @returns Path to the reversed output file
214
+ *
215
+ * @example
216
+ * ```typescript
217
+ * const reversed = await reverseAudio("message.mp3");
218
+ * ```
219
+ */
220
+ declare function reverseAudio(input: string): Promise<string>;
221
+ /**
222
+ * Generate a silent audio file.
223
+ *
224
+ * @param options - Silence options including duration, format, and sample rate
225
+ * @returns Path to the generated silence file
226
+ *
227
+ * @example
228
+ * ```typescript
229
+ * // Generate 5 seconds of silence as WAV
230
+ * const gap = await silence({ duration: 5 });
231
+ *
232
+ * // Generate 2 seconds of silence as MP3 at 48kHz
233
+ * const gap48 = await silence({ duration: 2, format: "mp3", sampleRate: 48000 });
234
+ * ```
235
+ */
236
+ declare function silence(options: SilenceOptions): Promise<string>;
237
+
238
+ export { type AudioFormat, type AudioInfo, type ConvertOptions, type FadeOptions, type SilenceOptions, type SpeedOptions, type TrimOptions, type VolumeOptions, changeVolume, convert, fade, info, merge, normalize, reverseAudio, silence, speed, trim };
package/dist/index.js ADDED
@@ -0,0 +1,150 @@
1
+ // src/engine.ts
2
+ import ffmpeg from "fluent-ffmpeg";
3
+ import { tmpdir } from "os";
4
+ import { join } from "path";
5
+ import { randomUUID } from "crypto";
6
+ import { extname } from "path";
7
+ function tmpOutput(ext) {
8
+ return join(tmpdir(), `peasy-audio-${randomUUID()}.${ext}`);
9
+ }
10
+ function run(command, output) {
11
+ return new Promise((resolve, reject) => {
12
+ command.output(output).on("end", () => resolve(output)).on("error", (err) => reject(err)).run();
13
+ });
14
+ }
15
+ function getExt(filePath) {
16
+ return extname(filePath).slice(1) || "wav";
17
+ }
18
+ function info(input) {
19
+ return new Promise((resolve, reject) => {
20
+ ffmpeg.ffprobe(input, (err, metadata) => {
21
+ if (err) return reject(err);
22
+ const audio = metadata.streams.find((s) => s.codec_type === "audio");
23
+ resolve({
24
+ duration: metadata.format.duration ?? 0,
25
+ format: metadata.format.format_name ?? "unknown",
26
+ sampleRate: audio?.sample_rate ? Number(audio.sample_rate) : 0,
27
+ channels: audio?.channels ?? 0,
28
+ bitrate: metadata.format.bit_rate ? Number(metadata.format.bit_rate) : 0,
29
+ size: metadata.format.size ?? 0
30
+ });
31
+ });
32
+ });
33
+ }
34
+ function convert(input, options) {
35
+ const output = tmpOutput(options.format);
36
+ const cmd = ffmpeg(input);
37
+ if (options.bitrate) {
38
+ cmd.audioBitrate(options.bitrate);
39
+ }
40
+ if (options.sampleRate) {
41
+ cmd.audioFrequency(options.sampleRate);
42
+ }
43
+ if (options.channels) {
44
+ cmd.audioChannels(options.channels);
45
+ }
46
+ return run(cmd, output);
47
+ }
48
+ function trim(input, options) {
49
+ const ext = getExt(input);
50
+ const output = tmpOutput(ext);
51
+ const cmd = ffmpeg(input);
52
+ if (options.start !== void 0) {
53
+ cmd.setStartTime(options.start);
54
+ }
55
+ if (options.duration !== void 0) {
56
+ cmd.setDuration(options.duration);
57
+ } else if (options.end !== void 0 && options.start !== void 0) {
58
+ cmd.setDuration(options.end - options.start);
59
+ } else if (options.end !== void 0) {
60
+ cmd.setDuration(options.end);
61
+ }
62
+ return run(cmd, output);
63
+ }
64
+ function merge(inputs) {
65
+ if (inputs.length === 0) {
66
+ return Promise.reject(new Error("At least one input file is required"));
67
+ }
68
+ const ext = getExt(inputs[0]);
69
+ const output = tmpOutput(ext);
70
+ return new Promise((resolve, reject) => {
71
+ const cmd = ffmpeg();
72
+ for (const input of inputs) {
73
+ cmd.input(input);
74
+ }
75
+ cmd.on("end", () => resolve(output)).on("error", (err) => reject(err)).mergeToFile(output, tmpdir());
76
+ });
77
+ }
78
+ function normalize(input) {
79
+ const ext = getExt(input);
80
+ const output = tmpOutput(ext);
81
+ const cmd = ffmpeg(input).audioFilters("loudnorm");
82
+ return run(cmd, output);
83
+ }
84
+ function changeVolume(input, options) {
85
+ const ext = getExt(input);
86
+ const output = tmpOutput(ext);
87
+ const cmd = ffmpeg(input).audioFilters(`volume=${options.change}dB`);
88
+ return run(cmd, output);
89
+ }
90
+ async function fade(input, options) {
91
+ const ext = getExt(input);
92
+ const output = tmpOutput(ext);
93
+ const filters = [];
94
+ if (options.fadeIn !== void 0 && options.fadeIn > 0) {
95
+ filters.push(`afade=t=in:st=0:d=${options.fadeIn}`);
96
+ }
97
+ if (options.fadeOut !== void 0 && options.fadeOut > 0) {
98
+ const metadata = await info(input);
99
+ const fadeStart = metadata.duration - options.fadeOut;
100
+ filters.push(`afade=t=out:st=${fadeStart}:d=${options.fadeOut}`);
101
+ }
102
+ const cmd = ffmpeg(input);
103
+ if (filters.length > 0) {
104
+ cmd.audioFilters(filters);
105
+ }
106
+ return run(cmd, output);
107
+ }
108
+ function speed(input, options) {
109
+ const ext = getExt(input);
110
+ const output = tmpOutput(ext);
111
+ const filters = [];
112
+ let remaining = options.factor;
113
+ while (remaining > 2) {
114
+ filters.push("atempo=2.0");
115
+ remaining /= 2;
116
+ }
117
+ while (remaining < 0.5) {
118
+ filters.push("atempo=0.5");
119
+ remaining /= 0.5;
120
+ }
121
+ filters.push(`atempo=${remaining}`);
122
+ const cmd = ffmpeg(input).audioFilters(filters);
123
+ return run(cmd, output);
124
+ }
125
+ function reverseAudio(input) {
126
+ const ext = getExt(input);
127
+ const output = tmpOutput(ext);
128
+ const cmd = ffmpeg(input).audioFilters("areverse");
129
+ return run(cmd, output);
130
+ }
131
+ function silence(options) {
132
+ const format = options.format ?? "wav";
133
+ const sampleRate = options.sampleRate ?? 44100;
134
+ const output = tmpOutput(format);
135
+ return new Promise((resolve, reject) => {
136
+ ffmpeg().input("anullsrc").inputFormat("lavfi").inputOptions([`-channel_layout=stereo`, `-sample_rate=${sampleRate}`]).duration(options.duration).output(output).on("end", () => resolve(output)).on("error", (err) => reject(err)).run();
137
+ });
138
+ }
139
+ export {
140
+ changeVolume,
141
+ convert,
142
+ fade,
143
+ info,
144
+ merge,
145
+ normalize,
146
+ reverseAudio,
147
+ silence,
148
+ speed,
149
+ trim
150
+ };
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "peasy-audio-js",
3
+ "version": "0.1.1",
4
+ "description": "Audio processing library for Node.js — convert, trim, merge, normalize, fade, speed. FFmpeg-powered, TypeScript-first.",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "scripts": {
18
+ "build": "tsup src/index.ts --format esm --dts",
19
+ "test": "vitest run",
20
+ "typecheck": "tsc --noEmit"
21
+ },
22
+ "keywords": [
23
+ "audio",
24
+ "mp3",
25
+ "wav",
26
+ "ffmpeg",
27
+ "convert",
28
+ "trim",
29
+ "merge",
30
+ "peasy"
31
+ ],
32
+ "author": "Peasy Tools",
33
+ "license": "MIT",
34
+ "repository": {
35
+ "url": "https://github.com/peasytools/peasy-audio-js.git"
36
+ },
37
+ "homepage": "https://peasyaudio.com",
38
+ "dependencies": {
39
+ "fluent-ffmpeg": "^2.1"
40
+ },
41
+ "devDependencies": {
42
+ "@types/fluent-ffmpeg": "^2.1",
43
+ "tsup": "^8.0",
44
+ "typescript": "^5.7",
45
+ "vitest": "^3.0"
46
+ }
47
+ }