diff --git a/src/daudio/src/main/java/com/cauc/deaudio/controller/AudioClippingController.java b/src/daudio/src/main/java/com/cauc/deaudio/controller/AudioClippingController.java index bd5c1f5..33b3e2f 100644 --- a/src/daudio/src/main/java/com/cauc/deaudio/controller/AudioClippingController.java +++ b/src/daudio/src/main/java/com/cauc/deaudio/controller/AudioClippingController.java @@ -16,6 +16,8 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.HashMap; import java.util.Map; +import java.util.List; +import java.util.ArrayList; @RestController @RequestMapping("/api/clipping") @@ -291,6 +293,56 @@ public class AudioClippingController { cleanupTempFiles(filePath1, filePath2, resultPath); } } + + @PostMapping("/merge-multiple") + public ResponseEntity mergeMultipleAudio(@RequestParam("files") MultipartFile[] files) { + + List filePaths = new ArrayList<>(); + String resultPath = null; + + try { + // 验证文件数量 + if (files == null || files.length < 2) { + return ResponseEntity.badRequest().body(Map.of("error", "At least two audio files are required for merging")); + } + + // 验证并保存所有文件 + for (MultipartFile file : files) { + validateUploadedFile(file); + filePaths.add(saveUploadedFile(file)); + } + + // 执行合并操作 + resultPath = audioProcessingService.mergeMultipleAudio(filePaths); + + // 生成文件名 + StringBuilder filenameBuilder = new StringBuilder("merged_"); + for (int i = 0; i < files.length; i++) { + if (i > 0) filenameBuilder.append("_"); + filenameBuilder.append(files[i].getOriginalFilename()); + } + + // 返回结果文件 + return processAudioResult(resultPath, filenameBuilder.toString(), "merge"); + + } catch (IllegalArgumentException e) { + return ResponseEntity.badRequest().body(Map.of("error", e.getMessage())); + } catch (IOException e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(Map.of("error", "Audio processing failed: " + e.getMessage())); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(Map.of("error", "Audio processing exception: " + e.getMessage())); + } finally { + // 清理临时文件 + if (filePaths != null && !filePaths.isEmpty()) { + cleanupTempFiles(filePaths.toArray(new String[0])); + } + if (resultPath != null) { + cleanupTempFiles(resultPath); + } + } + } @GetMapping("/test") public ResponseEntity> test() { diff --git a/src/daudio/src/main/java/com/cauc/deaudio/service/AudioProcessingService.java b/src/daudio/src/main/java/com/cauc/deaudio/service/AudioProcessingService.java index 527730b..9730eb1 100644 --- a/src/daudio/src/main/java/com/cauc/deaudio/service/AudioProcessingService.java +++ b/src/daudio/src/main/java/com/cauc/deaudio/service/AudioProcessingService.java @@ -6,6 +6,7 @@ import javax.sound.sampled.*; import java.io.*; import java.util.List; import java.util.ArrayList; +import java.util.Arrays; // MP3解码相关导入 import javazoom.jl.decoder.Bitstream; @@ -500,44 +501,143 @@ public class AudioProcessingService { * @return merged file path */ public String mergeAudio(String filePath1, String filePath2) throws Exception { - AudioInputStream stream1 = AudioSystem.getAudioInputStream(new File(filePath1)); - AudioInputStream stream2 = AudioSystem.getAudioInputStream(new File(filePath2)); - - AudioFormat format1 = stream1.getFormat(); - AudioFormat format2 = stream2.getFormat(); + // 检测文件格式 + String fileExtension1 = filePath1.toLowerCase(); + String fileExtension2 = filePath2.toLowerCase(); - // Check if audio formats are compatible - if (!format1.matches(format2)) { - throw new IllegalArgumentException("Audio formats are not compatible, cannot merge"); + // 如果两个文件都是MP3格式,使用MP3合并方法 + if (fileExtension1.endsWith(".mp3") && fileExtension2.endsWith(".mp3")) { + return mergeMP3Audio(filePath1, filePath2); + } else { + // 其他格式使用原来的WAV合并方法 + AudioInputStream stream1 = AudioSystem.getAudioInputStream(new File(filePath1)); + AudioInputStream stream2 = AudioSystem.getAudioInputStream(new File(filePath2)); + + AudioFormat format1 = stream1.getFormat(); + AudioFormat format2 = stream2.getFormat(); + + // Check if audio formats are compatible + if (!format1.matches(format2)) { + throw new IllegalArgumentException("Audio formats are not compatible, cannot merge"); + } + + // Read both audio files' data + byte[] audioData1 = stream1.readAllBytes(); + byte[] audioData2 = stream2.readAllBytes(); + + stream1.close(); + stream2.close(); + + // Merge audio data + byte[] mergedData = new byte[audioData1.length + audioData2.length]; + System.arraycopy(audioData1, 0, mergedData, 0, audioData1.length); + System.arraycopy(audioData2, 0, mergedData, audioData1.length, audioData2.length); + + // Create new audio stream + ByteArrayInputStream bais = new ByteArrayInputStream(mergedData); + AudioInputStream mergedStream = new AudioInputStream(bais, format1, + mergedData.length / format1.getFrameSize()); + + // Save merged file - use absolute path + File tempDir = new File(TEMP_DIR); + if (!tempDir.isAbsolute()) { + tempDir = new File(System.getProperty("user.dir"), TEMP_DIR); + } + String outputPath = new File(tempDir, "merge_" + System.currentTimeMillis() + ".wav").getAbsolutePath(); + AudioSystem.write(mergedStream, AudioFileFormat.Type.WAVE, new File(outputPath)); + + mergedStream.close(); + return outputPath; + } + } + + /** + * 合并多个音频文件 + * @param filePaths 音频文件路径列表 + * @return 合并后的文件路径 + */ + public String mergeMultipleAudio(List filePaths) throws Exception { + if (filePaths == null || filePaths.size() < 2) { + throw new IllegalArgumentException("At least two audio files are required for merging"); } - // Read both audio files' data - byte[] audioData1 = stream1.readAllBytes(); - byte[] audioData2 = stream2.readAllBytes(); - - stream1.close(); - stream2.close(); - - // Merge audio data - byte[] mergedData = new byte[audioData1.length + audioData2.length]; - System.arraycopy(audioData1, 0, mergedData, 0, audioData1.length); - System.arraycopy(audioData2, 0, mergedData, audioData1.length, audioData2.length); - - // Create new audio stream - ByteArrayInputStream bais = new ByteArrayInputStream(mergedData); - AudioInputStream mergedStream = new AudioInputStream(bais, format1, - mergedData.length / format1.getFrameSize()); - - // Save merged file - use absolute path - File tempDir = new File(TEMP_DIR); - if (!tempDir.isAbsolute()) { - tempDir = new File(System.getProperty("user.dir"), TEMP_DIR); + // 检查所有文件是否都是MP3格式 + boolean allMP3 = true; + for (String filePath : filePaths) { + if (!filePath.toLowerCase().endsWith(".mp3")) { + allMP3 = false; + break; + } } - String outputPath = new File(tempDir, "merge_" + System.currentTimeMillis() + ".wav").getAbsolutePath(); - AudioSystem.write(mergedStream, AudioFileFormat.Type.WAVE, new File(outputPath)); - mergedStream.close(); - return outputPath; + if (allMP3) { + return mergeMultipleMP3Audio(filePaths); + } else { + // 对于混合格式,使用WAV合并方法 + List streams = new ArrayList<>(); + List audioDataList = new ArrayList<>(); + AudioFormat baseFormat = null; + + try { + // 读取所有音频文件 + for (String filePath : filePaths) { + AudioInputStream stream = AudioSystem.getAudioInputStream(new File(filePath)); + AudioFormat format = stream.getFormat(); + + if (baseFormat == null) { + baseFormat = format; + } else if (!baseFormat.matches(format)) { + throw new IllegalArgumentException("Audio formats are not compatible, cannot merge"); + } + + streams.add(stream); + audioDataList.add(stream.readAllBytes()); + } + + // 计算总数据长度 + int totalLength = 0; + for (byte[] data : audioDataList) { + totalLength += data.length; + } + + // 合并音频数据 + byte[] mergedData = new byte[totalLength]; + int currentPosition = 0; + for (byte[] data : audioDataList) { + System.arraycopy(data, 0, mergedData, currentPosition, data.length); + currentPosition += data.length; + } + + // 创建新的音频流 + if (baseFormat == null) { + throw new IOException("Unable to determine audio format, merge failed"); + } + ByteArrayInputStream bais = new ByteArrayInputStream(mergedData); + AudioInputStream mergedStream = new AudioInputStream(bais, baseFormat, + mergedData.length / baseFormat.getFrameSize()); + + // 保存合并后的文件 + File tempDir = new File(TEMP_DIR); + if (!tempDir.isAbsolute()) { + tempDir = new File(System.getProperty("user.dir"), TEMP_DIR); + } + String outputPath = new File(tempDir, "merge_multiple_" + System.currentTimeMillis() + ".wav").getAbsolutePath(); + AudioSystem.write(mergedStream, AudioFileFormat.Type.WAVE, new File(outputPath)); + + mergedStream.close(); + return outputPath; + + } finally { + // 关闭所有流 + for (AudioInputStream stream : streams) { + try { + stream.close(); + } catch (IOException e) { + // 忽略关闭异常 + } + } + } + } } /** @@ -805,7 +905,7 @@ public class AudioProcessingService { } /** - * Get MP3 frame data + * Get MP3 frame data */ private byte[] getFrameData(Bitstream bitstream, Header header) throws IOException { // Get frame data @@ -819,4 +919,83 @@ public class AudioProcessingService { return frameData; } + + /** + * 合并两个MP3文件 + * @param filePath1 第一个MP3文件路径 + * @param filePath2 第二个MP3文件路径 + * @return 合并后的MP3文件路径 + */ + private String mergeMP3Audio(String filePath1, String filePath2) throws IOException { + FileInputStream fis1 = new FileInputStream(filePath1); + FileInputStream fis2 = new FileInputStream(filePath2); + + byte[] data1 = fis1.readAllBytes(); + byte[] data2 = fis2.readAllBytes(); + + fis1.close(); + fis2.close(); + + // 合并MP3数据 + byte[] mergedData = new byte[data1.length + data2.length]; + System.arraycopy(data1, 0, mergedData, 0, data1.length); + System.arraycopy(data2, 0, mergedData, data1.length, data2.length); + + // 保存合并后的MP3文件 + File tempDir = new File(TEMP_DIR); + if (!tempDir.isAbsolute()) { + tempDir = new File(System.getProperty("user.dir"), TEMP_DIR); + } + String outputPath = new File(tempDir, "merge_mp3_" + System.currentTimeMillis() + ".mp3").getAbsolutePath(); + + FileOutputStream fos = new FileOutputStream(outputPath); + fos.write(mergedData); + fos.close(); + + return outputPath; + } + + /** + * 合并多个MP3文件 + * @param filePaths MP3文件路径列表 + * @return 合并后的MP3文件路径 + */ + private String mergeMultipleMP3Audio(List filePaths) throws IOException { + List audioDataList = new ArrayList<>(); + + // 读取所有MP3文件数据 + for (String filePath : filePaths) { + FileInputStream fis = new FileInputStream(filePath); + byte[] data = fis.readAllBytes(); + fis.close(); + audioDataList.add(data); + } + + // 计算总数据长度 + int totalLength = 0; + for (byte[] data : audioDataList) { + totalLength += data.length; + } + + // 合并MP3数据 + byte[] mergedData = new byte[totalLength]; + int currentPosition = 0; + for (byte[] data : audioDataList) { + System.arraycopy(data, 0, mergedData, currentPosition, data.length); + currentPosition += data.length; + } + + // 保存合并后的MP3文件 + File tempDir = new File(TEMP_DIR); + if (!tempDir.isAbsolute()) { + tempDir = new File(System.getProperty("user.dir"), TEMP_DIR); + } + String outputPath = new File(tempDir, "merge_multiple_mp3_" + System.currentTimeMillis() + ".mp3").getAbsolutePath(); + + FileOutputStream fos = new FileOutputStream(outputPath); + fos.write(mergedData); + fos.close(); + + return outputPath; + } } \ No newline at end of file