JAVA音頻處理依賴(lài)庫(kù)示例操作大全(從格式轉(zhuǎn)換到音頻拼接)
一、引言
在現(xiàn)代應(yīng)用開(kāi)發(fā)中,音頻處理是常見(jiàn)需求,包括格式轉(zhuǎn)換、音頻拼接、剪輯、降噪等操作。Spring Boot作為流行的Java開(kāi)發(fā)框架,結(jié)合專(zhuān)門(mén)的音頻處理庫(kù),可以高效實(shí)現(xiàn)這些功能。本教程將介紹Spring Boot中常用的音頻處理依賴(lài)庫(kù),比較它們的特性、區(qū)別及社區(qū)活躍程度,并提供實(shí)用代碼示例。
二、主流Spring Boot音頻處理依賴(lài)庫(kù)
1. JAVE (Java Audio Video Encoder)
??簡(jiǎn)介??:JAVE是最流行的Java音頻視頻轉(zhuǎn)碼庫(kù),基于FFmpeg封裝,提供簡(jiǎn)單易用的API。
??主要功能??:
- 音頻格式轉(zhuǎn)換(如WAV轉(zhuǎn)MP3、FLAC轉(zhuǎn)AAC等)
- 采樣率、比特率和聲道數(shù)調(diào)整
- 視頻轉(zhuǎn)碼(雖然本教程聚焦音頻,但JAVE也支持)
??依賴(lài)配置??:
<dependency>
<groupId>ws.schild</groupId>
<artifactId>jave-core</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>ws.schild</groupId>
<artifactId>jave-nativebin-win64</artifactId>
<version>3.3.1</version>
<!-- 根據(jù)您的操作系統(tǒng)選擇: win64, linux64, mac64等 -->
</dependency>??示例代碼??:
import ws.schild.jave.*;
public class AudioConverter {
public void convertWavToMp3(File source, File target) {
AudioAttributes audio = new AudioAttributes();
audio.setCodec("libmp3lame");
audio.setBitRate(128000);
audio.setChannels(2);
audio.setSamplingRate(44100);
EncodingAttributes attrs = new EncodingAttributes();
attrs.setFormat("mp3");
attrs.setAudioAttributes(audio);
Encoder encoder = new Encoder();
try {
encoder.encode(new MultimediaObject(source), target, attrs);
} catch (Exception e) {
e.printStackTrace();
}
}
}??特點(diǎn)??:
- 優(yōu)點(diǎn):簡(jiǎn)單易用,基于強(qiáng)大的FFmpeg,支持幾乎所有音頻格式
- 缺點(diǎn):需要本地FFmpeg庫(kù),跨平臺(tái)部署稍復(fù)雜
- 社區(qū)活躍度:高,定期更新,廣泛使用
2. LAME-Java (MP3編碼專(zhuān)用)
??簡(jiǎn)介??:LAME-Java是LAME MP3編碼器的Java封裝,專(zhuān)注于MP3編碼。
??主要功能??:
- PCM到MP3的高效編碼
- 可配置的MP3質(zhì)量和比特率
- 低延遲MP3編碼
??依賴(lài)配置??:
<dependency>
<groupId>com.googlecode.soundlibs</groupId>
<artifactId>lame</artifactId>
<version>3.99.5</version>
</dependency>??示例代碼??:
import com.googlecode.lame.MP3Encoder;
import com.googlecode.lame.LameEncoder;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@Service
public class Mp3EncodingService {
public byte[] encodeToMp3(byte[] pcmData, int sampleRate, int channels, int bitDepth) throws IOException {
ByteArrayOutputStream mp3OutputStream = new ByteArrayOutputStream();
LameEncoder encoder = new LameEncoder(sampleRate, channels, bitDepth, 5); // 5為質(zhì)量參數(shù)
int bufferSize = 8192;
byte[] buffer = new byte[bufferSize];
int bytesRead;
int offset = 0;
while (offset < pcmData.length) {
bytesRead = Math.min(bufferSize, pcmData.length - offset);
System.arraycopy(pcmData, offset, buffer, 0, bytesRead);
offset += bytesRead;
byte[] mp3Data = encoder.encode(buffer, 0, bytesRead);
if (mp3Data != null) {
mp3OutputStream.write(mp3Data);
}
}
byte[] finalMp3 = encoder.flush();
if (finalMp3 != null) {
mp3OutputStream.write(finalMp3);
}
return mp3OutputStream.toByteArray();
}
}??特點(diǎn)??:
- 優(yōu)點(diǎn):MP3編碼質(zhì)量高,專(zhuān)門(mén)優(yōu)化
- 缺點(diǎn):僅支持MP3編碼,功能較單一
- 社區(qū)活躍度:中等,維護(hù)較穩(wěn)定但不頻繁
3. TarsosDSP
??簡(jiǎn)介??:TarsosDSP是一個(gè)功能豐富的Java音頻處理庫(kù),提供底層音頻處理能力。
??主要功能??:
- 音頻格式轉(zhuǎn)換
- 音頻拼接與混合
- 實(shí)時(shí)音頻處理
- 音高校正、節(jié)拍檢測(cè)等高級(jí)功能
??依賴(lài)配置??:
<dependency>
<groupId>be.tarsos</groupId>
<artifactId>TarsosDSP</artifactId>
<version>2.4</version>
</dependency>??示例代碼(音頻拼接)??:
import be.tarsos.dsp.io.jvm.AudioDispatcherFactory;
import be.tarsos.dsp.AudioDispatcher;
import be.tarsos.dsp.AudioEvent;
import be.tarsos.dsp.AudioProcessor;
import java.io.File;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.List;
public class AudioConcatenator {
public byte[] concatenateAudioFiles(List<File> audioFiles) throws Exception {
List<byte[]> audioChunks = new ArrayList<>();
int sampleRate = 44100; // 假設(shè)所有音頻文件具有相同的采樣率
for (File file : audioFiles) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// 使用TarsosDSP讀取音頻文件
AudioDispatcher dispatcher = AudioDispatcherFactory.fromPipe(file.getAbsolutePath(), sampleRate, 1024, 0);
dispatcher.addAudioProcessor(new AudioProcessor() {
@Override
public boolean process(AudioEvent audioEvent) {
byte[] audioData = audioEvent.getByteBuffer();
// 保存音頻數(shù)據(jù)塊
synchronized (audioChunks) {
// 這里簡(jiǎn)化處理,實(shí)際需要更復(fù)雜的緩沖區(qū)管理
// 可能需要使用AudioInputStream和AudioSystem進(jìn)行格式轉(zhuǎn)換
}
return true;
}
@Override
public void processingFinished() {
}
});
new Thread(dispatcher).start();
// 等待處理完成(簡(jiǎn)化示例,實(shí)際需要更完善的同步)
Thread.sleep(1000);
}
// 實(shí)際實(shí)現(xiàn)需要更復(fù)雜的音頻數(shù)據(jù)合并邏輯
// 這里只是概念性代碼
return combineAudioData(audioChunks, sampleRate);
}
private byte[] combineAudioData(List<byte[]> audioChunks, int sampleRate) {
// 實(shí)現(xiàn)音頻數(shù)據(jù)合并
// 需要考慮音頻格式、采樣率、聲道數(shù)等
return new byte[0]; // 簡(jiǎn)化返回
}
}??特點(diǎn)??:
- 優(yōu)點(diǎn):功能全面,支持實(shí)時(shí)處理,社區(qū)活躍
- 缺點(diǎn):API相對(duì)復(fù)雜,學(xué)習(xí)曲線較陡
- 社區(qū)活躍度:高,有活躍的維護(hù)者和用戶社區(qū)
4. Java Sound API (標(biāo)準(zhǔn)庫(kù))
??簡(jiǎn)介??:Java標(biāo)準(zhǔn)庫(kù)中的音頻處理API,無(wú)需額外依賴(lài)。
??主要功能??:
- 基本音頻播放和錄制
- 簡(jiǎn)單的音頻格式轉(zhuǎn)換
- 音頻混音和效果處理
??依賴(lài)配置??:無(wú)需額外依賴(lài),Java標(biāo)準(zhǔn)庫(kù)的一部分
??示例代碼??:
import javax.sound.sampled.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
public class BasicAudioProcessor {
public void convertAudioFormat(File inputFile, File outputFile, AudioFormat targetFormat)
throws UnsupportedAudioFileException, IOException {
AudioInputStream inputStream = AudioSystem.getAudioInputStream(inputFile);
AudioFormat sourceFormat = inputStream.getFormat();
// 創(chuàng)建目標(biāo)格式的音頻輸入流
AudioInputStream convertedStream = AudioSystem.getAudioInputStream(targetFormat, inputStream);
// 寫(xiě)入目標(biāo)文件
AudioSystem.write(convertedStream,
AudioFileFormat.Type.WAVE, // 或其他支持的類(lèi)型
outputFile);
convertedStream.close();
inputStream.close();
}
public byte[] concatenateAudioBytes(byte[] audio1, byte[] audio2, AudioFormat format)
throws IOException, UnsupportedAudioFileException {
// 注意:此簡(jiǎn)化方法假設(shè)兩個(gè)音頻字節(jié)數(shù)組具有完全相同的格式
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
outputStream.write(audio1);
outputStream.write(audio2);
return outputStream.toByteArray();
}
}??特點(diǎn)??:
- 優(yōu)點(diǎn):無(wú)需額外依賴(lài),Java標(biāo)準(zhǔn)功能
- 缺點(diǎn):功能有限,不支持許多現(xiàn)代音頻格式
- 社區(qū)活躍度:高(作為Java標(biāo)準(zhǔn)庫(kù)的一部分)
三、音頻處理庫(kù)對(duì)比分析
| 特性 | JAVE | LAME-Java | TarsosDSP | Java Sound API |
|---|---|---|---|---|
| ??格式支持?? | 極廣(通過(guò)FFmpeg) | 僅MP3 | 廣泛 | 有限 |
| ??音頻轉(zhuǎn)換?? | 優(yōu)秀 | 僅MP3編碼 | 優(yōu)秀 | 基本 |
| ??音頻拼接?? | 通過(guò)轉(zhuǎn)換實(shí)現(xiàn) | 不直接支持 | 優(yōu)秀 | 有限支持 |
| ??實(shí)時(shí)處理?? | 有限 | 不支持 | 優(yōu)秀 | 有限 |
| ??依賴(lài)復(fù)雜度?? | 需要本地FFmpeg | 輕量 | 中等 | 無(wú) |
| ??學(xué)習(xí)曲線?? | 簡(jiǎn)單 | 簡(jiǎn)單 | 較陡 | 簡(jiǎn)單 |
| ??社區(qū)活躍度?? | 高 | 中等 | 高 | 高(標(biāo)準(zhǔn)庫(kù)) |
| ??適合場(chǎng)景?? | 通用格式轉(zhuǎn)換 | MP3編碼專(zhuān)用 | 高級(jí)/實(shí)時(shí)處理 | 簡(jiǎn)單任務(wù) |
四、音頻處理常見(jiàn)場(chǎng)景實(shí)現(xiàn)
1. 音頻格式轉(zhuǎn)換最佳實(shí)踐
??使用JAVE進(jìn)行多種格式轉(zhuǎn)換??:
@Service
public class AudioConversionService {
public void convertAudioFormat(File source, File target, String targetFormat,
int bitrate, int channels, int sampleRate) {
try {
AudioAttributes audio = new AudioAttributes();
audio.setCodec(getCodecForFormat(targetFormat));
audio.setBitRate(bitrate);
audio.setChannels(channels);
audio.setSamplingRate(sampleRate);
EncodingAttributes attrs = new EncodingAttributes();
attrs.setFormat(targetFormat);
attrs.setAudioAttributes(audio);
Encoder encoder = new Encoder();
encoder.encode(new MultimediaObject(source), target, attrs);
} catch (Exception e) {
throw new RuntimeException("音頻轉(zhuǎn)換失敗", e);
}
}
private String getCodecForFormat(String format) {
switch (format.toLowerCase()) {
case "mp3": return "libmp3lame";
case "wav": return "pcm_s16le";
case "aac": return "aac";
case "flac": return "flac";
default: return "copy"; // 嘗試保持原編碼
}
}
}2. 音頻拼接實(shí)現(xiàn)方案
??使用TarsosDSP實(shí)現(xiàn)高質(zhì)量音頻拼接??:
@Service
public class AudioConcatenationService {
public File concatenateAudioFiles(List<File> inputFiles, File outputFile, String outputFormat)
throws Exception {
// 獲取第一個(gè)文件的音頻格式作為基準(zhǔn)
AudioInputStream firstStream = AudioSystem.getAudioInputStream(inputFiles.get(0));
AudioFormat format = firstStream.getFormat();
firstStream.close();
// 創(chuàng)建目標(biāo)音頻輸出流
AudioInputStream concatenatedStream = null;
AudioInputStream currentStream = null;
try {
for (File file : inputFiles) {
currentStream = AudioSystem.getAudioInputStream(file);
if (concatenatedStream == null) {
concatenatedStream = currentStream;
} else {
// 拼接音頻流
concatenatedStream = new SequenceAudioInputStream(format,
concatenatedStream, currentStream);
}
}
// 寫(xiě)入輸出文件
AudioSystem.write(concatenatedStream,
AudioFileFormat.Type.valueOf(outputFormat.toUpperCase()),
outputFile);
} finally {
if (currentStream != null) currentStream.close();
if (concatenatedStream != null && concatenatedStream != currentStream) {
concatenatedStream.close();
}
}
return outputFile;
}
// 自定義SequenceAudioInputStream實(shí)現(xiàn)音頻流拼接
private static class SequenceAudioInputStream extends AudioInputStream {
private final List<AudioInputStream> streams;
private int currentStreamIndex = 0;
public SequenceAudioInputStream(AudioFormat format,
AudioInputStream... streams) {
super(streams[0], format, AudioSystem.NOT_SPECIFIED);
this.streams = new ArrayList<>(Arrays.asList(streams));
}
@Override
public int read() throws IOException {
if (currentStreamIndex >= streams.size()) return -1;
int result = streams.get(currentStreamIndex).read();
if (result == -1 && currentStreamIndex < streams.size() - 1) {
currentStreamIndex++;
return read(); // 遞歸讀取下一個(gè)流
}
return result;
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
if (currentStreamIndex >= streams.size()) return -1;
int bytesRead = streams.get(currentStreamIndex).read(b, off, len);
if (bytesRead == -1 && currentStreamIndex < streams.size() - 1) {
currentStreamIndex++;
// 嘗試從下一個(gè)流讀取剩余的數(shù)據(jù)
int nextBytesRead = read(b, off + bytesRead, len - bytesRead);
if (nextBytesRead > 0) {
bytesRead += nextBytesRead;
}
}
return bytesRead;
}
}
}3. 音頻降噪處理
??使用TarsosDSP實(shí)現(xiàn)簡(jiǎn)單降噪??:
@Service
public class AudioDenoisingService {
public File denoiseAudio(File inputFile, File outputFile) throws Exception {
// 使用TarsosDSP的噪聲抑制處理器
AudioDispatcher dispatcher = AudioDispatcherFactory.fromFile(inputFile, 1024, 0);
// 創(chuàng)建降噪處理器(簡(jiǎn)化示例,實(shí)際需要更復(fù)雜的降噪算法)
AudioProcessor denoisingProcessor = new AudioProcessor() {
@Override
public boolean process(AudioEvent audioEvent) {
float[] audioBuffer = audioEvent.getFloatBuffer();
// 簡(jiǎn)單的降噪:減去均值(實(shí)際應(yīng)使用更復(fù)雜的算法)
float mean = 0;
for (float sample : audioBuffer) {
mean += sample;
}
mean /= audioBuffer.length;
for (int i = 0; i < audioBuffer.length; i++) {
audioBuffer[i] = (float) (audioBuffer[i] - mean * 0.5); // 減少噪聲影響
}
return true;
}
@Override
public void processingFinished() {
}
};
dispatcher.addAudioProcessor(denoisingProcessor);
// 輸出到文件
AudioProcessor fileWriterProcessor = new AudioProcessor() {
@Override
public boolean process(AudioEvent audioEvent) {
// 這里應(yīng)該寫(xiě)入文件,簡(jiǎn)化處理
return true;
}
@Override
public void processingFinished() {
}
};
// 實(shí)際實(shí)現(xiàn)需要更完整的文件寫(xiě)入邏輯
new Thread(dispatcher).start();
// 簡(jiǎn)化實(shí)現(xiàn),實(shí)際需要更復(fù)雜的處理
return processWithTarsosDsp(inputFile, outputFile);
}
// 更完整的TarsosDSP降噪實(shí)現(xiàn)
private File processWithTarsosDsp(File inputFile, File outputFile) throws Exception {
// 實(shí)際項(xiàng)目中,可以使用更專(zhuān)業(yè)的降噪庫(kù)或算法
// 這里只是一個(gè)框架,實(shí)際降噪算法需要更復(fù)雜的實(shí)現(xiàn)
return inputFile; // 簡(jiǎn)化返回
}
}五、庫(kù)選擇建議
1. 根據(jù)需求選擇合適的庫(kù)
??簡(jiǎn)單格式轉(zhuǎn)換??:
- 選擇:Java Sound API(如果格式支持)或JAVE
- 理由:無(wú)需復(fù)雜依賴(lài),簡(jiǎn)單易用
??專(zhuān)業(yè)MP3編碼??:
- 選擇:LAME-Java
- 理由:高質(zhì)量的MP3編碼,專(zhuān)為MP3優(yōu)化
??復(fù)雜音頻處理??:
- 選擇:TarsosDSP
- 理由:功能全面,支持實(shí)時(shí)處理和高級(jí)音頻操作
??通用、全面的解決方案??:
- 選擇:JAVE
- 理由:基于FFmpeg,支持幾乎所有音頻格式和操作
2. 社區(qū)與維護(hù)性考慮
- ??高社區(qū)活躍度??:JAVE和TarsosDSP有活躍的社區(qū),遇到問(wèn)題容易找到解決方案
- ??穩(wěn)定性??:Java Sound API作為標(biāo)準(zhǔn)庫(kù)最穩(wěn)定,但功能有限
- ??長(zhǎng)期維護(hù)??:LAME-Java和JAVE都有穩(wěn)定的維護(hù)歷史
六、Spring Boot集成最佳實(shí)踐
1. 創(chuàng)建音頻處理微服務(wù)
@RestController
@RequestMapping("/api/audio")
public class AudioProcessingController {
@Autowired
private AudioConversionService conversionService;
@Autowired
private AudioConcatenationService concatenationService;
@PostMapping("/convert")
public ResponseEntity<?> convertAudio(
@RequestParam("file") MultipartFile file,
@RequestParam("targetFormat") String targetFormat,
@RequestParam(value = "bitrate", defaultValue = "128000") int bitrate) {
try {
// 創(chuàng)建臨時(shí)文件
File inputFile = File.createTempFile("input", getFileExtension(file.getOriginalFilename()));
File outputFile = File.createTempFile("output", "." + targetFormat);
file.transferTo(inputFile);
// 轉(zhuǎn)換音頻格式
conversionService.convertAudioFormat(inputFile, outputFile, targetFormat,
bitrate, 2, 44100);
// 讀取轉(zhuǎn)換后的文件并返回
byte[] fileContent = Files.readAllBytes(outputFile.toPath());
// 清理臨時(shí)文件
inputFile.delete();
outputFile.delete();
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=\"converted." + targetFormat + "\"")
.body(fileContent);
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("音頻轉(zhuǎn)換失敗: " + e.getMessage());
}
}
@PostMapping("/concatenate")
public ResponseEntity<?> concatenateAudios(@RequestParam("files") MultipartFile[] files) {
try {
List<File> inputFiles = new ArrayList<>();
// 創(chuàng)建臨時(shí)輸入文件
for (MultipartFile file : files) {
File tempFile = File.createTempFile("input", getFileExtension(file.getOriginalFilename()));
file.transferTo(tempFile);
inputFiles.add(tempFile);
}
File outputFile = File.createTempFile("concatenated", ".wav");
// 拼接音頻
concatenationService.concatenateAudioFiles(inputFiles, outputFile, "wav");
byte[] fileContent = Files.readAllBytes(outputFile.toPath());
// 清理臨時(shí)文件
for (File file : inputFiles) {
file.delete();
}
outputFile.delete();
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=\"concatenated.wav\"")
.body(fileContent);
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("音頻拼接失敗: " + e.getMessage());
}
}
private String getFileExtension(String filename) {
if (filename == null || filename.lastIndexOf(".") == -1) {
return "";
}
return filename.substring(filename.lastIndexOf(".") + 1);
}
}2. 異步處理與性能優(yōu)化
對(duì)于大文件或批量處理,考慮使用異步處理:
@Service
public class AsyncAudioProcessingService {
@Async
public CompletableFuture<File> asyncConvertAudio(File inputFile, File outputFile,
String targetFormat, int bitrate) {
try {
// 模擬耗時(shí)操作
Thread.sleep(1000);
// 實(shí)際轉(zhuǎn)換邏輯
// conversionService.convertAudioFormat(inputFile, outputFile, targetFormat, bitrate, 2, 44100);
return CompletableFuture.completedFuture(outputFile);
} catch (Exception e) {
throw new RuntimeException("異步音頻轉(zhuǎn)換失敗", e);
}
}
}
@RestController
@RequestMapping("/api/async-audio")
public class AsyncAudioController {
@Autowired
private AsyncAudioProcessingService asyncService;
@PostMapping("/convert")
public ResponseEntity<?> asyncConvertAudio(@RequestParam("file") MultipartFile file) {
try {
File inputFile = File.createTempFile("async-input",
getFileExtension(file.getOriginalFilename()));
File outputFile = File.createTempFile("async-output", ".mp3");
file.transferTo(inputFile);
CompletableFuture<File> future = asyncService.asyncConvertAudio(
inputFile, outputFile, "mp3", 128000);
return ResponseEntity.accepted()
.body(Map.of("message", "音頻轉(zhuǎn)換已開(kāi)始",
"trackId", UUID.randomUUID().toString()));
// 實(shí)際項(xiàng)目中,應(yīng)該實(shí)現(xiàn)跟蹤機(jī)制來(lái)獲取處理結(jié)果
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("處理啟動(dòng)失敗: " + e.getMessage());
}
}
private String getFileExtension(String filename) {
if (filename == null || filename.lastIndexOf(".") == -1) {
return "";
}
return filename.substring(filename.lastIndexOf(".") + 1);
}
}七、總結(jié)
在Spring Boot應(yīng)用中集成音頻處理功能,有多種優(yōu)秀的庫(kù)可供選擇,每種庫(kù)都有其特定的優(yōu)勢(shì)和適用場(chǎng)景:
- ??JAVE??是最全面的解決方案,特別適合需要處理多種音頻格式轉(zhuǎn)換的項(xiàng)目,基于強(qiáng)大的FFmpeg,功能豐富但需要管理本地依賴(lài)。
- ??LAME-Java??是MP3編碼的專(zhuān)業(yè)選擇,適合只需要MP3編碼功能的應(yīng)用,提供高質(zhì)量的MP3編碼能力。
- ??TarsosDSP??是功能最豐富的音頻處理庫(kù),適合需要實(shí)現(xiàn)高級(jí)音頻處理功能如實(shí)時(shí)處理、音頻分析和復(fù)雜變換的項(xiàng)目。
- ??Java Sound API??作為Java標(biāo)準(zhǔn)庫(kù)的一部分,適合簡(jiǎn)單的音頻處理任務(wù),無(wú)需額外依賴(lài)但功能相對(duì)有限。
根據(jù)您的具體需求、項(xiàng)目復(fù)雜度和目標(biāo)平臺(tái),選擇最適合的音頻處理庫(kù)。對(duì)于大多數(shù)Spring Boot應(yīng)用,JAVE提供了良好的平衡點(diǎn),結(jié)合了功能豐富性和相對(duì)簡(jiǎn)單的集成過(guò)程。
到此這篇關(guān)于JAVA音頻處理依賴(lài)庫(kù)全面教程:從格式轉(zhuǎn)換到音頻拼接的文章就介紹到這了,更多相關(guān)java音頻處理依賴(lài)庫(kù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MyBatis中的關(guān)聯(lián)關(guān)系配置與多表查詢的操作代碼
本文介紹了在MyBatis中配置和使用一對(duì)多和多對(duì)多關(guān)系的方法,通過(guò)合理的實(shí)體類(lèi)設(shè)計(jì)、Mapper接口和XML文件的配置,我們可以方便地進(jìn)行多表查詢,并豐富了應(yīng)用程序的功能和靈活性,需要的朋友可以參考下2023-09-09
解決Error:(5,55)java:程序包org.springframework.cloud.netflix.eure
這篇文章主要介紹了解決Error:(5,55)java:程序包org.springframework.cloud.netflix.eureka.server不存在問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11
Java詳細(xì)分析String類(lèi)與StringBuffer和StringBuilder的使用方法
當(dāng)對(duì)字符串進(jìn)行修改的時(shí)候,需要使用 StringBuffer 和 StringBuilder類(lèi),和String類(lèi)不同的是,StringBuffer和 StringBuilder類(lèi)的對(duì)象能夠被多次的修改,并且不產(chǎn)生新的未使用對(duì)象2022-04-04
Java正則表達(dá)式_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
什么是正則表達(dá)式,正則表達(dá)式的作用是什么?這篇文章主要為大家詳細(xì)介紹了Java正則表達(dá)式的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-05-05

