Please bookmark this page to avoid losing your image tool!

Audio Trimming Tool

(Free & Supports Bulk Upload)

Drag & drop your images here or

The result will appear here...
You can edit the below JavaScript code to customize the image tool.
function processImage(originalImg, defaultStart = "0", defaultEnd = "10") {
    // Create the main container
    const container = document.createElement('div');
    container.style.fontFamily = 'system-ui, -apple-system, sans-serif';
    container.style.padding = '20px';
    container.style.maxWidth = '500px';
    container.style.margin = '0 auto';
    container.style.background = '#ffffff';
    container.style.border = '1px solid #e0e0e0';
    container.style.borderRadius = '12px';
    container.style.boxShadow = '0 4px 15px rgba(0,0,0,0.05)';
    container.style.display = 'flex';
    container.style.flexDirection = 'column';
    container.style.gap = '20px';
    container.style.color = '#333';

    // Header section wrapper
    const header = document.createElement('div');
    header.style.display = 'flex';
    header.style.alignItems = 'center';
    header.style.gap = '15px';
    header.style.borderBottom = '1px solid #f0f0f0';
    header.style.paddingBottom = '15px';

    // Safely incorporate the originalImg as a thumbnail display
    if (originalImg) {
        try {
            const imgCanvas = document.createElement('canvas');
            imgCanvas.width = 60;
            imgCanvas.height = 60;
            const ctx = imgCanvas.getContext('2d');
            ctx.drawImage(originalImg, 0, 0, 60, 60);
            
            const imgEl = document.createElement('img');
            imgEl.src = imgCanvas.toDataURL('image/png');
            imgEl.style.width = '60px';
            imgEl.style.height = '60px';
            imgEl.style.objectFit = 'cover';
            imgEl.style.borderRadius = '8px';
            imgEl.style.boxShadow = '0 2px 4px rgba(0,0,0,0.1)';
            header.appendChild(imgEl);
        } catch(e) {
            // Ignore cors issues if any, just skip thumbnail
        }
    }

    const titleContainer = document.createElement('div');
    const title = document.createElement('h2');
    title.innerText = 'Audio Trimming Tool';
    title.style.margin = '0 0 5px 0';
    title.style.fontSize = '20px';
    
    const subtitle = document.createElement('p');
    subtitle.innerText = 'Trim your audio files directly in the browser.';
    subtitle.style.margin = '0';
    subtitle.style.fontSize = '12px';
    subtitle.style.color = '#666';

    titleContainer.appendChild(title);
    titleContainer.appendChild(subtitle);
    header.appendChild(titleContainer);
    container.appendChild(header);

    // File Input Section
    const fileContainer = document.createElement('div');
    fileContainer.style.display = 'flex';
    fileContainer.style.flexDirection = 'column';
    fileContainer.style.gap = '8px';
    
    const fileLabel = document.createElement('label');
    fileLabel.innerText = '1. Select Audio File';
    fileLabel.style.fontWeight = '600';
    fileLabel.style.fontSize = '14px';
    
    const fileInput = document.createElement('input');
    fileInput.type = 'file';
    fileInput.accept = 'audio/*';
    fileInput.style.padding = '8px';
    fileInput.style.border = '1px dashed #ccc';
    fileInput.style.borderRadius = '6px';
    fileInput.style.background = '#fafafa';
    fileInput.style.cursor = 'pointer';

    fileContainer.appendChild(fileLabel);
    fileContainer.appendChild(fileInput);
    container.appendChild(fileContainer);

    // Original Audio Preview
    const originalAudioContainer = document.createElement('div');
    originalAudioContainer.style.display = 'none';
    originalAudioContainer.style.flexDirection = 'column';
    originalAudioContainer.style.gap = '8px';

    const originalAudioLabel = document.createElement('label');
    originalAudioLabel.innerText = 'Original Audio Preview:';
    originalAudioLabel.style.fontSize = '13px';
    originalAudioLabel.style.color = '#555';

    const originalAudio = document.createElement('audio');
    originalAudio.controls = true;
    originalAudio.style.width = '100%';

    originalAudioContainer.appendChild(originalAudioLabel);
    originalAudioContainer.appendChild(originalAudio);
    container.appendChild(originalAudioContainer);

    // Controls Section
    const controlsContainer = document.createElement('div');
    controlsContainer.style.display = 'flex';
    controlsContainer.style.gap = '15px';
    controlsContainer.style.alignItems = 'center';

    const startWrapper = document.createElement('div');
    startWrapper.style.display = 'flex';
    startWrapper.style.flexDirection = 'column';
    startWrapper.style.gap = '4px';

    const startLabel = document.createElement('label');
    startLabel.innerText = '2. Start Time (s)';
    startLabel.style.fontWeight = '600';
    startLabel.style.fontSize = '14px';

    const startInput = document.createElement('input');
    startInput.type = 'number';
    startInput.value = defaultStart;
    startInput.min = '0';
    startInput.step = '0.1';
    startInput.style.padding = '8px';
    startInput.style.border = '1px solid #ccc';
    startInput.style.borderRadius = '6px';
    startInput.style.width = '100px';

    startWrapper.appendChild(startLabel);
    startWrapper.appendChild(startInput);

    const endWrapper = document.createElement('div');
    endWrapper.style.display = 'flex';
    endWrapper.style.flexDirection = 'column';
    endWrapper.style.gap = '4px';

    const endLabel = document.createElement('label');
    endLabel.innerText = '3. End Time (s)';
    endLabel.style.fontWeight = '600';
    endLabel.style.fontSize = '14px';

    const endInput = document.createElement('input');
    endInput.type = 'number';
    endInput.value = defaultEnd;
    endInput.min = '0';
    endInput.step = '0.1';
    endInput.style.padding = '8px';
    endInput.style.border = '1px solid #ccc';
    endInput.style.borderRadius = '6px';
    endInput.style.width = '100px';

    endWrapper.appendChild(endLabel);
    endWrapper.appendChild(endInput);

    controlsContainer.appendChild(startWrapper);
    controlsContainer.appendChild(endWrapper);
    container.appendChild(controlsContainer);

    // Action Button
    const trimBtn = document.createElement('button');
    trimBtn.innerText = 'Trim Audio';
    trimBtn.style.padding = '12px 20px';
    trimBtn.style.background = '#007BFF';
    trimBtn.style.color = '#fff';
    trimBtn.style.border = 'none';
    trimBtn.style.borderRadius = '6px';
    trimBtn.style.fontWeight = 'bold';
    trimBtn.style.fontSize = '15px';
    trimBtn.style.cursor = 'pointer';
    trimBtn.style.transition = 'background 0.2s';
    trimBtn.onmouseover = () => { trimBtn.style.background = '#0056b3'; };
    trimBtn.onmouseout = () => { trimBtn.style.background = '#007BFF'; };
    container.appendChild(trimBtn);

    // Status Message
    const statusMsg = document.createElement('div');
    statusMsg.style.fontSize = '13px';
    statusMsg.style.color = '#d9534f';
    statusMsg.style.minHeight = '18px';
    container.appendChild(statusMsg);

    // Output Section
    const outputContainer = document.createElement('div');
    outputContainer.style.display = 'none';
    outputContainer.style.flexDirection = 'column';
    outputContainer.style.gap = '15px';
    outputContainer.style.marginTop = '10px';
    outputContainer.style.paddingTop = '15px';
    outputContainer.style.borderTop = '1px solid #f0f0f0';

    const outputLabel = document.createElement('label');
    outputLabel.innerText = 'Trimmed Result:';
    outputLabel.style.fontWeight = '600';
    outputLabel.style.fontSize = '14px';

    const trimmedAudio = document.createElement('audio');
    trimmedAudio.controls = true;
    trimmedAudio.style.width = '100%';

    const downloadBtn = document.createElement('a');
    downloadBtn.innerText = 'Download Trimmed Audio (WAV)';
    downloadBtn.style.padding = '10px 15px';
    downloadBtn.style.background = '#28a745';
    downloadBtn.style.color = '#fff';
    downloadBtn.style.textDecoration = 'none';
    downloadBtn.style.borderRadius = '6px';
    downloadBtn.style.textAlign = 'center';
    downloadBtn.style.fontWeight = 'bold';
    downloadBtn.style.fontSize = '14px';
    downloadBtn.style.cursor = 'pointer';

    outputContainer.appendChild(outputLabel);
    outputContainer.appendChild(trimmedAudio);
    outputContainer.appendChild(downloadBtn);
    container.appendChild(outputContainer);

    // Event Listeners
    let currentInputFile = null;

    fileInput.addEventListener('change', () => {
        if (fileInput.files.length > 0) {
            currentInputFile = fileInput.files[0];
            const url = URL.createObjectURL(currentInputFile);
            originalAudio.src = url;
            originalAudioContainer.style.display = 'flex';
            statusMsg.innerText = '';
            
            // Suggest end time based on actual duration when loaded
            originalAudio.onloadedmetadata = () => {
                if (originalAudio.duration && isFinite(originalAudio.duration)) {
                    endInput.value = originalAudio.duration.toFixed(2);
                }
            };
        } else {
            currentInputFile = null;
            originalAudioContainer.style.display = 'none';
        }
    });

    trimBtn.addEventListener('click', async () => {
        if (!currentInputFile) {
            statusMsg.style.color = '#d9534f';
            statusMsg.innerText = 'Please select an audio file first.';
            return;
        }

        const startVal = parseFloat(startInput.value);
        const endVal = parseFloat(endInput.value);

        if (isNaN(startVal) || isNaN(endVal) || startVal < 0 || startVal >= endVal) {
            statusMsg.style.color = '#d9534f';
            statusMsg.innerText = 'Invalid start/end times. Ensure Start is less than End.';
            return;
        }

        try {
            statusMsg.style.color = '#007BFF';
            statusMsg.innerText = 'Processing your audio...';
            trimBtn.disabled = true;
            trimBtn.style.opacity = '0.7';

            // Decode the selected audio file
            const arrayBuffer = await currentInputFile.arrayBuffer();
            const audioContext = new (window.AudioContext || window.webkitAudioContext)();
            const originalBuffer = await audioContext.decodeAudioData(arrayBuffer);

            const duration = originalBuffer.duration;
            let actualStart = startVal;
            let actualEnd = endVal;

            if (actualEnd > duration) actualEnd = duration;
            if (actualStart >= duration) {
                throw new Error('Start time is beyond the audio duration.');
            }

            const sampleRate = originalBuffer.sampleRate;
            const channels = originalBuffer.numberOfChannels;
            
            const startOffset = Math.floor(actualStart * sampleRate);
            const endOffset = Math.floor(actualEnd * sampleRate);
            const frameCount = endOffset - startOffset;

            // Create a new AudioBuffer for the trimmed fragment
            const newAudioBuffer = audioContext.createBuffer(channels, frameCount, sampleRate);

            // Copy data channel by channel
            for (let channel = 0; channel < channels; channel++) {
                const channelData = originalBuffer.getChannelData(channel);
                const newChannelData = newAudioBuffer.getChannelData(channel);
                for (let i = 0; i < frameCount; i++) {
                    newChannelData[i] = channelData[startOffset + i];
                }
            }

            // Convert to WAV Blob
            const wavBlob = audioBufferToWav(newAudioBuffer);
            const wavUrl = URL.createObjectURL(wavBlob);

            // Update UI Outputs
            trimmedAudio.src = wavUrl;
            
            // Format filename safely
            const originalName = currentInputFile.name.replace(/\.[^/.]+$/, "");
            downloadBtn.href = wavUrl;
            downloadBtn.download = `${originalName}_trimmed.wav`;
            
            outputContainer.style.display = 'flex';
            statusMsg.style.color = '#28a745';
            statusMsg.innerText = 'Audio successfully trimmed!';

            // Close context to free resources
            if(audioContext.state !== 'closed') {
                audioContext.close();
            }

        } catch (err) {
            console.error(err);
            statusMsg.style.color = '#d9534f';
            statusMsg.innerText = err.message || 'Error processing audio. File might be unsupported or corrupted.';
            outputContainer.style.display = 'none';
        } finally {
            trimBtn.disabled = false;
            trimBtn.style.opacity = '1';
        }
    });

    /**
     * Helper function to encode AudioBuffer to a WAV format Blob
     * @param {AudioBuffer} buffer 
     * @returns {Blob}
     */
    function audioBufferToWav(buffer) {
        const numChannels = buffer.numberOfChannels;
        const sampleRate = buffer.sampleRate;
        const format = 1; // PCM
        const bitDepth = 16;
        
        let result;
        if (numChannels === 2) {
            result = interleave(buffer.getChannelData(0), buffer.getChannelData(1));
        } else {
            result = buffer.getChannelData(0);
        }

        const dataLength = result.length * (bitDepth / 8);
        const bufferArray = new ArrayBuffer(44 + dataLength);
        const view = new DataView(bufferArray);

        // write string helper
        function writeString(view, offset, string) {
            for (let i = 0; i < string.length; i++) {
                view.setUint8(offset + i, string.charCodeAt(i));
            }
        }

        // RIFF header
        writeString(view, 0, 'RIFF');
        view.setUint32(4, 36 + dataLength, true); // file length - 8
        writeString(view, 8, 'WAVE');
        
        // fmt chunk
        writeString(view, 12, 'fmt ');
        view.setUint32(16, 16, true);             // chunk length
        view.setUint16(20, format, true);         // format
        view.setUint16(22, numChannels, true);
        view.setUint32(24, sampleRate, true);
        view.setUint32(28, sampleRate * numChannels * (bitDepth / 8), true); // byte rate
        view.setUint16(32, numChannels * (bitDepth / 8), true); // block align
        view.setUint16(34, bitDepth, true);       // bits per sample
        
        // data chunk
        writeString(view, 36, 'data');
        view.setUint32(40, dataLength, true);

        // Write PCM samples
        let offset = 44;
        for (let i = 0; i < result.length; i++, offset += 2) {
            let sample = Math.max(-1, Math.min(1, result[i]));
            // 16-bit signed integer conversion
            sample = sample < 0 ? sample * 32768 : sample * 32767;
            view.setInt16(offset, sample, true);
        }

        return new Blob([view], { type: 'audio/wav' });

        // Utility strictly used to interleave stereo channels
        function interleave(inputL, inputR) {
            const length = inputL.length + inputR.length;
            const result = new Float32Array(length);
            let index = 0;
            let inputIndex = 0;
            while (index < length) {
                result[index++] = inputL[inputIndex];
                result[index++] = inputR[inputIndex];
                inputIndex++;
            }
            return result;
        }
    }

    return container;
}

Free Image Tool Creator

Can't find the image tool you're looking for?
Create one based on your own needs now!

Description

The Audio Trimming Tool allows you to select an audio file and extract a specific segment by defining a start and end time in seconds. This tool processes audio directly in your browser and provides a preview of the original file and the trimmed result. It is useful for creating short audio clips, removing unwanted silence or noise from recordings, or isolating specific sound bites for use in videos, podcasts, and presentations.

Leave a Reply

Your email address will not be published. Required fields are marked *