From 1e3af49d8f31236ba1a506f6d33d0323f94f1cad Mon Sep 17 00:00:00 2001 From: Ahmed Kamal Date: Wed, 11 Oct 2023 01:39:04 +1100 Subject: [PATCH] feat: add `sliceAudio` method (#92) --- .gitignore | 2 ++ README.md | 12 ++++++++++++ package.json | 4 ++-- src/crunker.ts | 38 ++++++++++++++++++++++++++++++++++++++ test/test.js | 4 ++++ 5 files changed, 58 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index b967f4a..59e47f1 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,5 @@ test/*.bundle.js !.yarn/releases !.yarn/sdks !.yarn/versions + +.idea diff --git a/README.md b/README.md index 65ab167..5a16223 100644 --- a/README.md +++ b/README.md @@ -118,6 +118,18 @@ Concatenate two or more audio buffers in the order specified.\ Pad the audio with silence, at the beginning, the end, or any specified points through the audio.\ **Returns:** a single `AudioBuffer` object. +## crunker.sliceAudio(buffer, start, end, fadeIn, fadeOut); + +Slice the audio to the specified range, removing any content outside the range. Optionally add a fade-in at the start and a fade-out at the end to avoid audible clicks. + +- **buffer:** The audio buffer to be trimmed. +- **start:** The starting second from where the audio should begin. +- **end:** The ending second where the audio should be trimmed. +- **fadeIn:** (Optional) Number of seconds for the fade-in effect at the beginning. Default is `0`. +- **fadeOut:** (Optional) Number of seconds for the fade-out effect at the end. Default is `0`. + +**Returns:** a single `AudioBuffer` object. + ## crunker.export(buffer, type); Export an audio buffers with MIME type option.\ diff --git a/package.json b/package.json index 5b99cc4..d25fcbf 100644 --- a/package.json +++ b/package.json @@ -38,9 +38,9 @@ "author": "Jack Edgson", "license": "MIT", "files": [ - "LICENSE" + "LICENSE", "README.md", - "dist", + "dist" ], "bugs": { "url": "https://github.com/jaggad/crunker/issues" diff --git a/src/crunker.ts b/src/crunker.ts index a0f9209..1303dd7 100644 --- a/src/crunker.ts +++ b/src/crunker.ts @@ -181,6 +181,44 @@ export default class Crunker { return updatedBuffer; } + /** + * Slices an AudioBuffer from the specified start time to the end time, with optional fade in and out. + * + * @param buffer AudioBuffer to slice + * @param start Start time (in seconds) + * @param end End time (in seconds) + * @param fadeIn Fade in duration (in seconds, default is 0) + * @param fadeOut Fade out duration (in seconds, default is 0) + */ + sliceAudio(buffer: AudioBuffer, start: number, end: number, fadeIn: number = 0, fadeOut: number = 0): AudioBuffer { + if (start >= end) throw new Error('Crunker: "start" time should be less than "end" time in sliceAudio method'); + + const length = Math.round((end - start) * this._sampleRate); + const offset = Math.round(start * this._sampleRate); + const newBuffer = this._context.createBuffer(buffer.numberOfChannels, length, this._sampleRate); + + for (let channel = 0; channel < buffer.numberOfChannels; channel++) { + const inputData = buffer.getChannelData(channel); + const outputData = newBuffer.getChannelData(channel); + + for (let i = 0; i < length; i++) { + outputData[i] = inputData[offset + i]; + + // Apply fade in + if (i < fadeIn * this._sampleRate) { + outputData[i] *= i / (fadeIn * this._sampleRate); + } + + // Apply fade out + if (i > length - fadeOut * this._sampleRate) { + outputData[i] *= (length - i) / (fadeOut * this._sampleRate); + } + } + } + + return newBuffer; + } + /** * Plays the provided AudioBuffer in an AudioBufferSourceNode. */ diff --git a/test/test.js b/test/test.js index 0a0a1b3..0a86787 100644 --- a/test/test.js +++ b/test/test.js @@ -49,6 +49,10 @@ describe('Crunker', () => { expect(audio.concatAudio(buffers).duration.toFixed(2)).to.equal('16.30'); }); + it('slices a buffer correctly', () => { + expect(audio.sliceAudio(buffers[0], 0, 1, 0.1, 0.1).duration.toFixed(2)).to.equal('1.00'); + }); + it('exports an object', () => { const output = audio.export(buffers[0]); expect(output).to.not.equal(null);