sfxmix 1.3.0 → 1.3.2
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/demo/demo_8.js +33 -0
- package/demo/package.json +12 -0
- package/demo/part1.mp3 +0 -0
- package/index.js +92 -1
- package/package.json +2 -1
- /package/demo/{demo_1.mjs → demo_1.js} +0 -0
- /package/demo/{demo_2.mjs → demo_2.js} +0 -0
- /package/demo/{demo_3.mjs → demo_3.js} +0 -0
- /package/demo/{demo_4.mjs → demo_4.js} +0 -0
- /package/demo/{demo_5.mjs → demo_5.js} +0 -0
- /package/demo/{demo_6.mjs → demo_6.js} +0 -0
- /package/demo/{demo_7.mjs → demo_7.js} +0 -0
package/demo/demo_8.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import SfxMix from '../index.js';
|
|
2
|
+
|
|
3
|
+
// Example 1: Trim silence without padding
|
|
4
|
+
console.log('Example 1: Trimming without padding...');
|
|
5
|
+
const sfx1 = new SfxMix();
|
|
6
|
+
await sfx1
|
|
7
|
+
.add('part1.mp3')
|
|
8
|
+
.trim()
|
|
9
|
+
.save('part1_trimmed.mp3')
|
|
10
|
+
.then(() => {
|
|
11
|
+
console.log('✓ Successfully exported: vo_intro_text_3_trimmed.mp3');
|
|
12
|
+
})
|
|
13
|
+
.catch((error) => {
|
|
14
|
+
console.error('Error during audio processing:', error);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
// Example 2: Trim silence with padding (200ms at start, 300ms at end)
|
|
18
|
+
console.log('\nExample 2: Trimming with padding...');
|
|
19
|
+
const sfx2 = new SfxMix();
|
|
20
|
+
await sfx2
|
|
21
|
+
.add('part1.mp3')
|
|
22
|
+
.trim({
|
|
23
|
+
paddingStart: 100, // 100ms of silence at the start
|
|
24
|
+
paddingEnd: 100 // 100ms of silence at the end
|
|
25
|
+
})
|
|
26
|
+
.save('part1_trimmed_padded.mp3')
|
|
27
|
+
.then(() => {
|
|
28
|
+
console.log('✓ Successfully exported: vo_intro_text_3_trimmed_padded.mp3');
|
|
29
|
+
})
|
|
30
|
+
.catch((error) => {
|
|
31
|
+
console.error('Error during audio processing:', error);
|
|
32
|
+
});
|
|
33
|
+
|
package/demo/part1.mp3
CHANGED
|
Binary file
|
package/index.js
CHANGED
|
@@ -51,6 +51,11 @@ class SfxMix {
|
|
|
51
51
|
return this;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
trim(options = {}) {
|
|
55
|
+
this.actions.push({ type: 'trim', options });
|
|
56
|
+
return this;
|
|
57
|
+
}
|
|
58
|
+
|
|
54
59
|
|
|
55
60
|
|
|
56
61
|
convertAudio(inputFile, outputFile, outputOptions = {}) {
|
|
@@ -161,6 +166,16 @@ class SfxMix {
|
|
|
161
166
|
fs.unlinkSync(this.currentFile);
|
|
162
167
|
}
|
|
163
168
|
this.currentFile = tempFile;
|
|
169
|
+
} else if (action.type === 'trim') {
|
|
170
|
+
if (this.currentFile == null) {
|
|
171
|
+
throw new Error('No audio to trim. Add audio before trimming.');
|
|
172
|
+
}
|
|
173
|
+
const tempFile = path.join(this.TMP_DIR, `temp_trim_${uuidv4()}.mp3`);
|
|
174
|
+
await this.applyTrim(this.currentFile, action.options, tempFile);
|
|
175
|
+
if (this.isTempFile(this.currentFile)) {
|
|
176
|
+
fs.unlinkSync(this.currentFile);
|
|
177
|
+
}
|
|
178
|
+
this.currentFile = tempFile;
|
|
164
179
|
}
|
|
165
180
|
}
|
|
166
181
|
|
|
@@ -224,7 +239,8 @@ class SfxMix {
|
|
|
224
239
|
filename.includes('temp_concat_') ||
|
|
225
240
|
filename.includes('temp_mix_') ||
|
|
226
241
|
filename.includes('temp_silence_') ||
|
|
227
|
-
filename.includes('temp_filter_')
|
|
242
|
+
filename.includes('temp_filter_') ||
|
|
243
|
+
filename.includes('temp_trim_')
|
|
228
244
|
);
|
|
229
245
|
}
|
|
230
246
|
|
|
@@ -399,6 +415,81 @@ class SfxMix {
|
|
|
399
415
|
});
|
|
400
416
|
}
|
|
401
417
|
|
|
418
|
+
applyTrim(inputFile, options, outputFile) {
|
|
419
|
+
return new Promise(async (resolve, reject) => {
|
|
420
|
+
try {
|
|
421
|
+
// Default options for silenceremove filter
|
|
422
|
+
// start_periods: number of silence periods at start to remove (1 = remove silence from start)
|
|
423
|
+
// start_duration: minimum duration of silence to detect at start (in seconds)
|
|
424
|
+
// start_threshold: noise tolerance for start (in dB, e.g., -50dB)
|
|
425
|
+
// stop_periods: number of silence periods at end to remove (-1 = remove all silence from end)
|
|
426
|
+
// stop_duration: minimum duration of silence to detect at end (in seconds)
|
|
427
|
+
// stop_threshold: noise tolerance for end (in dB)
|
|
428
|
+
// paddingStart: milliseconds of silence to add at the start (after removing silence)
|
|
429
|
+
// paddingEnd: milliseconds of silence to add at the end (after removing silence)
|
|
430
|
+
|
|
431
|
+
const startPeriods = options.startPeriods !== undefined ? options.startPeriods : 1;
|
|
432
|
+
const startDuration = options.startDuration !== undefined ? options.startDuration : 0;
|
|
433
|
+
const startThreshold = options.startThreshold !== undefined ? options.startThreshold : -50;
|
|
434
|
+
const stopPeriods = options.stopPeriods !== undefined ? options.stopPeriods : -1;
|
|
435
|
+
const stopDuration = options.stopDuration !== undefined ? options.stopDuration : 0;
|
|
436
|
+
const stopThreshold = options.stopThreshold !== undefined ? options.stopThreshold : -50;
|
|
437
|
+
const paddingStart = options.paddingStart || 0; // in milliseconds
|
|
438
|
+
const paddingEnd = options.paddingEnd || 0; // in milliseconds
|
|
439
|
+
|
|
440
|
+
// Build filter chain
|
|
441
|
+
const filters = [];
|
|
442
|
+
|
|
443
|
+
// Add silenceremove filter
|
|
444
|
+
filters.push(`silenceremove=start_periods=${startPeriods}:start_duration=${startDuration}:start_threshold=${startThreshold}dB:stop_periods=${stopPeriods}:stop_duration=${stopDuration}:stop_threshold=${stopThreshold}dB`);
|
|
445
|
+
|
|
446
|
+
// Add padding at start if specified
|
|
447
|
+
if (paddingStart > 0) {
|
|
448
|
+
filters.push(`adelay=${paddingStart}|${paddingStart}`);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// Add padding at end if specified
|
|
452
|
+
if (paddingEnd > 0) {
|
|
453
|
+
const paddingSec = paddingEnd / 1000;
|
|
454
|
+
filters.push(`apad=pad_dur=${paddingSec}`);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
const filterChain = filters.join(',');
|
|
458
|
+
|
|
459
|
+
let bitrateKbps;
|
|
460
|
+
|
|
461
|
+
// If bitrate is null, auto-detect from input file
|
|
462
|
+
if (this.bitrate === null) {
|
|
463
|
+
let audioInfo = null;
|
|
464
|
+
try {
|
|
465
|
+
audioInfo = await this.getAudioInfo(inputFile);
|
|
466
|
+
} catch (err) {
|
|
467
|
+
console.warn('Could not get audio info for trim, using 128k default:', err.message);
|
|
468
|
+
}
|
|
469
|
+
bitrateKbps = audioInfo ? Math.floor(audioInfo.bitrate / 1000) + 'k' : '128k';
|
|
470
|
+
} else {
|
|
471
|
+
// Use configured default bitrate
|
|
472
|
+
bitrateKbps = Math.floor(this.bitrate / 1000) + 'k';
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
const command = ffmpeg()
|
|
476
|
+
.input(inputFile)
|
|
477
|
+
.audioFilters(filterChain)
|
|
478
|
+
.audioCodec('libmp3lame')
|
|
479
|
+
.audioBitrate(bitrateKbps)
|
|
480
|
+
.format('mp3')
|
|
481
|
+
.output(outputFile);
|
|
482
|
+
|
|
483
|
+
command
|
|
484
|
+
.on('end', () => resolve())
|
|
485
|
+
.on('error', (err) => reject(err))
|
|
486
|
+
.run();
|
|
487
|
+
} catch (err) {
|
|
488
|
+
reject(err);
|
|
489
|
+
}
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
|
|
402
493
|
getFilterChain(filterName, options) {
|
|
403
494
|
switch (filterName) {
|
|
404
495
|
case 'normalize':
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sfxmix",
|
|
3
3
|
"description": "🎧 SfxMix - Powerful and easy-to-use module for processing audio.",
|
|
4
|
-
"version": "1.3.
|
|
4
|
+
"version": "1.3.2",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"dependencies": {
|
|
7
7
|
"fluent-ffmpeg": "^2.1.3",
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"phaser",
|
|
30
30
|
"compressor",
|
|
31
31
|
"flanger",
|
|
32
|
+
"trim",
|
|
32
33
|
"reverb",
|
|
33
34
|
"highpass",
|
|
34
35
|
"lowpass",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|