需求说明
需要根据时间切割mp3、wav文件
切割:列如一个时常2分钟的mp3,需要保留XX秒后的音频数据,XX秒之前则丢弃
合并:需要在MP3或wav歌曲播放之前写入指定音频,将其连在一起
技术实现
环境准备
该工具为了快速实现本地化功能,采用了javafx8
在切割MP3和WAV时使用到了第三方库jaudiotagger
pom依赖:
1 2 3 4 5 6
| <!-- https://mvnrepository.com/artifact/net.jthink/jaudiotagger --> <dependency> <groupId>net.jthink</groupId> <artifactId>jaudiotagger</artifactId> <version>3.0.1</version> </dependency>
|
在合并时可能出现音频格式不一致,由于jaudiotagger没有发现针对mp3音频格式控制的接口暴露,所以采用了FFmpeg,使用javaac集成包
添加pom依赖
1 2 3 4 5 6 7
| <!-- https://mvnrepository.com/artifact/org.bytedeco/javacv-platform --> <dependency> <groupId>org.bytedeco</groupId> <artifactId>javacv-platform</artifactId> <version>1.5.9</version> </dependency>
|
核心功能实现
mp3切割实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
|
public File cutMusicByTime(File music, String savePath, long time) { long beginTime = time * 1000; MP3File mp3 = new MP3File(music); MP3AudioHeader header = (MP3AudioHeader) mp3.getAudioHeader(); int length = header.getTrackLength() ; long endTime = length * 1000; long bitRateKbps = header.getBitRateAsNumber(); long beginBitRateBpm = (bitRateKbps* 1024L / 8L / 1000L) * beginTime; long firstFrameByte = header.getMp3StartByte(); long beginByte = firstFrameByte + beginBitRateBpm; long endByte = beginByte + (bitRateKbps* 1024L / 8L / 1000L) * (endTime - beginTime); File dFile = new File(savePath); RandomAccessFile dRaf = new RandomAccessFile(dFile, "rw"); RandomAccessFile sRaf = new RandomAccessFile(music, "rw"); for(long i = 0; i< firstFrameByte;i++){ int m = sRaf.read(); dRaf.write(m); } sRaf.seek(beginByte); for(long i = 0; i<= endByte-beginByte ;i++){ int m = sRaf.read(); dRaf.write(m); } sRaf.close(); dRaf.close(); return dFile; }
|
mp3合并实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| public static void convertAudioParameters(String fileAPath, String fileBPath, String outputPath) throws FrameGrabber.Exception, FrameRecorder.Exception {
FFmpegFrameGrabber grabberA = new FFmpegFrameGrabber(fileAPath); FFmpegFrameGrabber grabberB = new FFmpegFrameGrabber(fileBPath); grabberA.start(); grabberB.start(); FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outputPath, grabberB.getAudioChannels()); recorder.setSampleRate(grabberB.getSampleRate()); recorder.setAudioBitrate(grabberB.getAudioBitrate()); for (Map.Entry<String, String> entry : grabberB.getMetadata().entrySet()) { recorder.setMetadata(entry.getKey(),entry.getValue()); } recorder.start(); Frame frameA; Frame frameB; while ((frameA = grabberA.grab()) != null) { recorder.record(frameA); } while ((frameB = grabberB.grab()) != null) { recorder.record(frameB); } grabberA.stop(); grabberB.stop(); recorder.stop(); }
|
wav切割实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| public File cutMusicByTime(File inputFile, String savePath, long time) { AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(inputFile);
int bytesPerFrame = audioInputStream.getFormat().getFrameSize(); int frameRate = (int) audioInputStream.getFormat().getFrameRate(); audioInputStream.skip(time * frameRate * bytesPerFrame); long lengthToRead = audioInputStream.getFrameLength() * bytesPerFrame; AudioInputStream shortenedStream = new AudioInputStream( audioInputStream, audioInputStream.getFormat(), lengthToRead / bytesPerFrame ); File outputFile = new File(savePath); AudioSystem.write(shortenedStream, AudioFileFormat.Type.WAVE, outputFile); copyAlbumInformation(inputFile, outputFile); return outputFile; } private static void copyAlbumInformation(File sourceFile, File outputFile) throws UnsupportedAudioFileException, IOException, TagException, ReadOnlyFileException, CannotWriteException, CannotReadException, InvalidAudioFrameException { AudioFile sourceAudioFile = AudioFileIO.read(sourceFile); Tag sourceTag = sourceAudioFile.getTag(); AudioHeader audioHeader = sourceAudioFile.getAudioHeader(); if (sourceTag != null) { AudioFile outputAudioFile = AudioFileIO.read(outputFile); Tag outputTag = outputAudioFile.getTag(); Iterator<TagField> fields = sourceTag.getFields(); while (fields.hasNext()){ TagField tagField = fields.next(); outputTag.setField(tagField); } outputAudioFile.commit(); } }
|
wav合并实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public void mergeWAV(File inputFile1, File inputFile2, String outputFilePath) throws IOException, UnsupportedAudioFileException { AudioInputStream audioInputStream1 = AudioSystem.getAudioInputStream(inputFile1); AudioInputStream audioInputStream2 = AudioSystem.getAudioInputStream(inputFile2);
AudioFormat format1 = audioInputStream1.getFormat(); AudioFormat format2 = audioInputStream2.getFormat();
if (!format1.matches(format2)) { audioInputStream1 = AudioSystem.getAudioInputStream(format2, audioInputStream1); format1 = audioInputStream1.getFormat(); }
AudioInputStream appendedFiles = new AudioInputStream( new SequenceInputStream(audioInputStream1, audioInputStream2), format1, audioInputStream1.getFrameLength() + audioInputStream2.getFrameLength() );
AudioSystem.write(appendedFiles, AudioFileFormat.Type.WAVE, new File(outputFilePath)); }
|