最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

基于純Java實(shí)現(xiàn)WAV音頻切割的具體方案

 更新時(shí)間:2025年11月04日 08:47:46   作者:一鍵難忘  
在音頻處理領(lǐng)域,FFmpeg 一直是開(kāi)發(fā)者的首選工具,它功能強(qiáng)大,能處理幾乎所有格式的音視頻,但在某些應(yīng)用場(chǎng)景中,我們希望擺脫對(duì)外部依賴(lài)的束縛,本文將介紹一種基于Java Sound API (javax.sound.sampled)的方案,實(shí)現(xiàn)一個(gè)純Java的WAV音頻切割工具,需要的朋友可以參考下

摘要

在音頻處理領(lǐng)域,FFmpeg 一直是開(kāi)發(fā)者的首選工具,它功能強(qiáng)大,能處理幾乎所有格式的音視頻。但在某些應(yīng)用場(chǎng)景中,我們希望擺脫對(duì)外部依賴(lài)的束縛,尤其是在:

Java 原生項(xiàng)目中,不希望通過(guò)命令行調(diào)用外部程序;沙箱環(huán)境(如 Web 容器或受限服務(wù)器),無(wú)法執(zhí)行 FFmpeg;輕量級(jí)音頻工具開(kāi)發(fā)中,只需簡(jiǎn)單的分割功能,不想打包數(shù)十 MB 的二進(jìn)制文件。

本文將介紹一種基于 Java Sound API (javax.sound.sampled) 的方案,實(shí)現(xiàn)一個(gè)純 Java 的 WAV 音頻切割工具,無(wú)需依賴(lài)任何外部庫(kù)或命令行。

在這里插入圖片描述

一、背景與限制

在開(kāi)始實(shí)現(xiàn)前,我們先了解一下Java Sound API 的局限性

  • 僅支持 PCM 編碼的 WAV 文件,也就是“未壓縮”的音頻;
  • 對(duì)于 MP3、AAC 等壓縮格式,需要額外的第三方庫(kù)(如 mp3spijlayer);
  • 所以本文僅聚焦于 WAV (PCM) 文件的分割。

但優(yōu)點(diǎn)也很明顯:

? 不需要 FFmpeg、SoX 等外部依賴(lài);
? 跨平臺(tái)純 Java 實(shí)現(xiàn);
? 操作精確到幀,切割后的文件可以立即播放。

在這里插入圖片描述

二、切割思路解析

WAV 文件的音頻流由一系列幀(frame)組成,每一幀表示音頻信號(hào)在某一時(shí)刻的采樣結(jié)果。
切割的核心思想是:

根據(jù)起止時(shí)間計(jì)算出幀范圍 → 跳過(guò)前面幀 → 讀取目標(biāo)幀 → 寫(xiě)入新文件。

整個(gè)過(guò)程可以概括為以下步驟:

讀取源音頻文件
使用 AudioSystem.getAudioInputStream() 打開(kāi) WAV 文件。

計(jì)算幀位置
根據(jù)音頻采樣率(frameRate)和起止時(shí)間(秒),計(jì)算出對(duì)應(yīng)的幀區(qū)間。

跳過(guò)起始幀
通過(guò) AudioInputStream.skip() 精確跳過(guò)前面的音頻字節(jié)。

讀取并寫(xiě)入新的音頻段
創(chuàng)建一個(gè)新的 AudioInputStream,只包含目標(biāo)幀數(shù)量,然后寫(xiě)入到目標(biāo) WAV 文件。

三、完整實(shí)現(xiàn)代碼

以下是核心實(shí)現(xiàn)邏輯(已省略輔助類(lèi)的定義部分,如 AudioTime、AudioPairTime)。

    /**
     * 切割音頻
     * 只支持 PCM WAV 文件
     * @param originPath 原始地址
     * @param pairTime   切割時(shí)間對(duì)
     * @param targetPath 切割后的音頻存在地址
     */
    public static void split(String originPath, AudioPairTime pairTime, String targetPath) throws IOException {

        AudioTime startTime = pairTime.getStartTime();
        AudioTime endTime = pairTime.getEndTime();

        File sourceFile = new File(originPath);
        try (AudioInputStream originalStream = AudioSystem.getAudioInputStream(sourceFile)) {

            AudioFormat format = originalStream.getFormat();
            int bytesPerFrame = format.getFrameSize();
            float frameRate = format.getFrameRate();

            long startFrame = (long) (startTime.toSeconds() * frameRate);
            long endFrame = (long) (endTime.toSeconds() * frameRate);
            long framesToRead = endFrame - startFrame;

            long skippedBytes = originalStream.skip(startFrame * bytesPerFrame);
            if (skippedBytes != startFrame * bytesPerFrame) {
                throw new IOException("無(wú)法跳轉(zhuǎn)到指定開(kāi)始幀");
            }

            try (AudioInputStream shortenedStream = new AudioInputStream(originalStream, format, framesToRead)) {
                File targetFile = new File(targetPath);
                AudioSystem.write(shortenedStream, AudioFileFormat.Type.WAVE, targetFile);
            }
        } catch (javax.sound.sampled.UnsupportedAudioFileException e) {
            throw new IOException("只支持 PCM WAV 文件", e);
        }
    }



四、核心要點(diǎn)解讀

1. 時(shí)間到幀的轉(zhuǎn)換

每秒鐘音頻包含 frameRate 幀,因此:

long startFrame = (long) (startTime.toSeconds() * frameRate);

舉例:如果采樣率為 44100Hz,想從第 10 秒切割,則應(yīng)從第 10 * 44100 = 441000 幀開(kāi)始。

2. 精確跳過(guò)字節(jié)

每一幀的大小由 frameSize 決定,單位是字節(jié)。
在 PCM 編碼下:

frameSize = 聲道數(shù) × 每個(gè)樣本的字節(jié)數(shù)

例如:16-bit 雙聲道音頻 → 2 * 2 = 4 字節(jié)/幀。

因此跳過(guò) N 幀應(yīng)跳過(guò):

skipBytes = N * bytesPerFrame;

3. AudioInputStream 的截取機(jī)制

Java 提供的 AudioInputStream 支持限定讀取幀數(shù)的構(gòu)造函數(shù):

new AudioInputStream(originalStream, format, framesToRead)

意味著即使源文件更長(zhǎng),輸出流也會(huì)在讀完指定幀數(shù)后自動(dòng)結(jié)束。

4. 寫(xiě)出 WAV 文件

輸出部分同樣使用標(biāo)準(zhǔn) API:

AudioSystem.write(shortenedStream, AudioFileFormat.Type.WAVE, targetFile);

無(wú)需手動(dòng)維護(hù)文件頭,Java 會(huì)自動(dòng)寫(xiě)入 WAV 頭部與數(shù)據(jù)塊。

五、輔助時(shí)間類(lèi)(可選設(shè)計(jì))

為了讓調(diào)用更直觀,我們可以設(shè)計(jì)如下輔助類(lèi):

public class AudioTime {
    private int hour;
    private int minute;
    private int second;

    public double toSeconds() {
        return hour * 3600 + minute * 60 + second;
    }
}

public class AudioPairTime {
    private AudioTime startTime;
    private AudioTime endTime;
    // getter / setter ...
}

調(diào)用示例:

AudioPairTime segment = new AudioPairTime(
    new AudioTime(0, 0, 10),
    new AudioTime(0, 0, 20)
);
split("input.wav", segment, "output_cut.wav");

六、性能與可靠性

性能方面:
由于只進(jìn)行字節(jié)級(jí)拷貝,不做解碼/編碼,處理速度接近文件 IO 的理論極限。
一個(gè) 100MB 的 WAV 文件可在數(shù)百毫秒內(nèi)切割完成。

可靠性:
PCM WAV 是無(wú)壓縮格式,幀之間無(wú)依賴(lài)關(guān)系,因此切割不會(huì)破壞數(shù)據(jù)結(jié)構(gòu),切片可直接播放。

七、局限與擴(kuò)展方向

方面當(dāng)前方案可擴(kuò)展思路
格式支持僅支持 PCM WAV可接入 JLayer(MP3)或 Tritonus SPI
精度控制基于幀精度(毫秒級(jí))若需采樣點(diǎn)精度可使用 ByteBuffer 操作
批量處理單文件可批量循環(huán)分割多個(gè)片段
可視化無(wú)可結(jié)合 JavaFX 或 Web 前端展示波形圖

八、總結(jié)

本文介紹了一個(gè)純 Java 實(shí)現(xiàn)的 WAV 音頻切割方案,不依賴(lài) FFmpeg 或任何第三方庫(kù)。
它充分利用了 Java 自帶的 AudioSystemAudioInputStream,能夠在多平臺(tái)環(huán)境中輕量、穩(wěn)定地運(yùn)行。

適用于:

Java 桌面工具;嵌入式或服務(wù)端音頻預(yù)處理;自動(dòng)化音頻切片任務(wù)(如語(yǔ)音識(shí)別片段提?。?。

通過(guò)本文的實(shí)踐,我們證明了 Java 完全可以在不依賴(lài) FFmpeg 的情況下,實(shí)現(xiàn)對(duì) PCM WAV 音頻的高效切割。
核心思想在于利用 AudioInputStream 對(duì)幀級(jí)數(shù)據(jù)的精準(zhǔn)控制:根據(jù)時(shí)間計(jì)算幀范圍、跳過(guò)無(wú)關(guān)幀、讀取目標(biāo)段并重新寫(xiě)出文件。

這種方式不僅保持了 純 Java、跨平臺(tái)、無(wú)外部依賴(lài) 的特性,還能在毫秒級(jí)實(shí)現(xiàn)穩(wěn)定的音頻截取,適合用于語(yǔ)音數(shù)據(jù)預(yù)處理、音頻標(biāo)注、語(yǔ)音識(shí)別等任務(wù)。

雖然目前僅限于未壓縮的 WAV 文件,但該方案為進(jìn)一步擴(kuò)展(如 MP3 支持、批量切割、波形可視化)奠定了堅(jiān)實(shí)基礎(chǔ),是構(gòu)建輕量級(jí)音頻處理模塊的理想起點(diǎn)。

以上就是基于純Java實(shí)現(xiàn)WAV音頻切割的具體方案的詳細(xì)內(nèi)容,更多關(guān)于純Java WAV音頻切割的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • SpringBoot返回long,前端接收進(jìn)度丟失,@JsonSerialize不生效問(wèn)題

    SpringBoot返回long,前端接收進(jìn)度丟失,@JsonSerialize不生效問(wèn)題

    這篇文章主要介紹了SpringBoot返回long,前端接收進(jìn)度丟失,@JsonSerialize不生效問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • springboot整合JPA過(guò)程解析

    springboot整合JPA過(guò)程解析

    這篇文章主要介紹了springboot整合JPA過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • Java不可變類(lèi)機(jī)制淺析

    Java不可變類(lèi)機(jī)制淺析

    所謂的不可變類(lèi)是指這個(gè)類(lèi)的實(shí)例一旦創(chuàng)建完成后,就不能改變其成員變量值。如JDK內(nèi)部自帶的很多不可變類(lèi):Interger、Long和String等。接下來(lái)通過(guò)本文給大家介紹Java不可變類(lèi)機(jī)制,需要的朋友參考下
    2017-02-02
  • SpringBoot 多環(huán)境配置和啟動(dòng)詳解

    SpringBoot 多環(huán)境配置和啟動(dòng)詳解

    這篇文章主要為大家介紹了SpringBoot多環(huán)境配置和啟動(dòng)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-10-10
  • SpringBoot整合RabbitMQ實(shí)現(xiàn)延遲隊(duì)列和死信隊(duì)列

    SpringBoot整合RabbitMQ實(shí)現(xiàn)延遲隊(duì)列和死信隊(duì)列

    RabbitMQ的死信隊(duì)列用于接收其他隊(duì)列中的“死信”消息,所謂“死信”,是指滿(mǎn)足一定條件而無(wú)法被消費(fèi)者正確處理的消息,死信隊(duì)列通常與RabbitMQ的延遲隊(duì)列一起使用,本文給大家介紹了SpringBoot整合RabbitMQ實(shí)現(xiàn)延遲隊(duì)列和死信隊(duì)列,需要的朋友可以參考下
    2024-06-06
  • Activiti常用類(lèi)簡(jiǎn)介

    Activiti常用類(lèi)簡(jiǎn)介

    這篇文章主要介紹了Activiti常用類(lèi),需要的朋友可以參考下
    2014-08-08
  • Java正則環(huán)視和反向引用功能與用法詳解

    Java正則環(huán)視和反向引用功能與用法詳解

    這篇文章主要介紹了Java正則環(huán)視和反向引用功能與用法,結(jié)合實(shí)例形式較為詳細(xì)的分析了java正則環(huán)視與反向引用的相關(guān)概念與使用方法,需要的朋友可以參考下
    2018-01-01
  • 基于Java實(shí)現(xiàn)獲取本地IP地址和主機(jī)名

    基于Java實(shí)現(xiàn)獲取本地IP地址和主機(jī)名

    這篇文章主要介紹了基于Java實(shí)現(xiàn)獲取本地IP地址和主機(jī)名,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-05-05
  • Java怎么重命名?Amazon?S3?中的文件和文件夾

    Java怎么重命名?Amazon?S3?中的文件和文件夾

    在本文中,我們探討了使用適用于 Java 的 AWS 開(kāi)發(fā)工具包重命名 S3 存儲(chǔ)桶中的文件和文件夾的方法,我們探索了兩種不同的情況,它們使用相同的概念來(lái)重命名對(duì)象,用新名稱(chēng)復(fù)制它們并刪除原始名稱(chēng)
    2023-10-10
  • StringUtils工具包中字符串非空判斷isNotEmpty和isNotBlank的區(qū)別

    StringUtils工具包中字符串非空判斷isNotEmpty和isNotBlank的區(qū)別

    今天小編就為大家分享一篇關(guān)于StringUtils工具包中字符串非空判斷isNotEmpty和isNotBlank的區(qū)別,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2018-12-12

最新評(píng)論

双柏县| 通许县| 和田市| 巴彦淖尔市| 怀来县| 沛县| 鄂托克旗| 呼玛县| 永登县| 右玉县| 龙山县| 吴江市| 大冶市| 巫溪县| 长武县| 钦州市| 邹平县| 新源县| 饶平县| 台中县| 抚宁县| 若羌县| 德清县| 宝应县| 锡林郭勒盟| 天水市| 屏东市| 丹阳市| 蒙山县| 宜州市| 衡山县| 沁阳市| 安福县| 农安县| 高安市| 平南县| 四川省| 凌海市| 西乌珠穆沁旗| 新龙县| 烟台市|