大学作业-JAVA音频播放器
项目源码和封装后的jar下载:https://pan.quark.cn/s/79c3773534ce
前言:
播放音频 和 图形界面 都不是 java 擅长的领域。http 和 web 相关的领域才是 java 广泛应用的地方。
所以这个项目没啥意义,建议直接抄吧。
项目使用的 java媒体框架jmf 是十几年前的老旧技术了,仅支持 wav 格式的音频文件播放。
jmf 官方网站:https://www.oracle.com/java/technologies/javase/java-media-framework.html
参考资料:
音频播放器参考:https://blog.csdn.net/m0_74288422/article/details/130651659
图形界面参考1:https://blog.csdn.net/yan_kai/article/details/52690491 (参考按钮监听事件)
图形界面参考1:https://blog.csdn.net/jjsr2002/article/details/129265130 (参考进度条音量等)
icon图标参考(播放图标大小64):
https://www.iconfont.cn/collections/detail?spm=a313x.7781069.1998910419.d9df05512&cid=22159
https://www.iconfont.cn/collections/index?spm=a313x.7781069.1998910419.89&keyword=%E6%92%AD%E6%94%BE&page=1
项目所需的 java 版本:1.8 或以上版本。maven 依赖如下:
<!-- lombok 非必要 --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.24</version> <scope>provided</scope> </dependency> <!-- Java Media Framework JAVA媒体框架 --> <dependency> <groupId>javax.media</groupId> <artifactId>jmf</artifactId> <version>2.1.1e</version> </dependency>
下面直接上代码:
项目启动入口:
/** * 项目主程序入口 */ public class JAudioApp { /** * 项目主程序入口 * * @param args */ public static void main(String[] args) { JAudioGUI gui = new JAudioGUI(new JAudioPlayer()); JAudioConst.AUDIO_FILE_PATH_LIST.forEach(x -> gui.addAudioFile(x)); } }
播放器实现类:
import java.io.IOException; import java.io.InputStream; import java.util.Timer; import java.util.TimerTask; import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.Clip; import javax.sound.sampled.DataLine; import javax.sound.sampled.UnsupportedAudioFileException; import javax.swing.JOptionPane; /** * 音频播放器 */ public class JAudioPlayer { /** 播放器 */ private Clip clip; /** 文件是否加载标志 */ private volatile boolean isAudioLoad; /** 是否正在播放标志 */ private volatile boolean isPlaying; /** 已播放时长 */ private double playTime; /** 音频总时长 */ private double audioFullTime; /** 歌词实体类 */ private JAudioLyricDTO audioLyricDTO; public JAudioPlayer() { // 记录已播放时长 Timer timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { if (isPlaying()) { playTime += 0.01; } } }, 0, 10); // 每10毫秒刷新一次 } // /** // * 测试播放的主方法 // * // * @param args // */ // public static void main(String[] args) { // String audioFilePath = JAudioConst.AUDIO_FILE_PATH_LIST.get(0); // System.out.println(audioFullTime(audioFilePath)); // testPlay(audioFilePath); // } // // private static void testPlay(String audioFilePath) { // // // 睡眠 n 秒 // Consumer<Integer> sleep = (seconds) -> { // try { // Thread.sleep(seconds * 1000L); // } catch (InterruptedException e) { // e.printStackTrace(); // } // }; // // /* // * 尝试播放一首歌,暂停后再播放,然后停止 // */ // JAudioPlayer player = new JAudioPlayer(); // try { // player.load(audioFilePath); // } catch (Exception e) { // System.err.println("加载文件出错!" + audioFilePath + ", error message:" + e.getMessage()); // } // // player.play(); // 播放 // // sleep.accept(5); // 等待几秒 // player.pause(); // 暂停 // // sleep.accept(5); // 等待几秒 // player.play(); // 继续播放 // // sleep.accept(5); // 等待几秒 // player.stop(); // 停止 // // player.play(); // stop() 后再调用此方法无效! // } /** * 获取音频总时长 * * @param audioFilePath * @return */ public static double audioFullTime(String audioFilePath) { try (InputStream in = JAudioUtils.loadFileAsStream(audioFilePath); AudioInputStream audioStream = AudioSystem.getAudioInputStream(in)) { AudioFormat audioFormat = audioStream.getFormat(); return audioStream.getFrameLength() / audioFormat.getSampleRate(); } catch (UnsupportedAudioFileException e) { e.printStackTrace(); JOptionPane.showMessageDialog(null, "解析音频时长出错:" + audioFilePath // + " error message:" + e.getMessage()); } catch (IOException e) { e.printStackTrace(); JOptionPane.showMessageDialog(null, "解析音频时长出错:" + audioFilePath // + " error message:" + e.getMessage()); } return 0; } /** * 加载文件,有问题时抛出异常 * * @param audioFilePath * @throws Exception */ public void load(String audioFilePath) throws Exception { // try { // } catch (UnsupportedAudioFileException e) { // throw new RuntimeException(e); // } catch (IOException e) { // throw new RuntimeException(e); // } catch (LineUnavailableException e) { // throw new RuntimeException(e); // } // 先清空资源 this.stop(); // 重新加载资源 // File audioFile = new File(audioFilePath); // AudioInputStream audioStream = AudioSystem.getAudioInputStream(audioFile); // AudioInputStream audioStream = AudioSystem // // .getAudioInputStream(JAudioPlayer.class.getResourceAsStream(audioFilePath)); AudioInputStream audioStream = AudioSystem // .getAudioInputStream(JAudioUtils.loadFileAsStream(audioFilePath)); AudioFormat audioFormat = audioStream.getFormat(); // 获取音频总时长 this.audioFullTime = audioStream.getFrameLength() / audioFormat.getSampleRate(); DataLine.Info info = new DataLine.Info(Clip.class, audioFormat); this.clip = (Clip) AudioSystem.getLine(info); this.clip.open(audioStream); this.isAudioLoad = true; // 加载歌词文件 String lyricFilePath = audioFilePath // .replace("audio/", "audioLyric/") // .replace(".wav", ".txt"); try { this.audioLyricDTO = JAudioUtils.readAudioLyricFile(lyricFilePath); } catch (Exception e) { e.printStackTrace(); } } /** * 播放,检测到未加载文件时抛出异常。 */ public void play() { if (clip == null) { JOptionPane.showMessageDialog(null, "请先加载音乐文件!"); throw new RuntimeException("请先加载音乐文件!"); } clip.start(); isPlaying = true; } /** * 暂停 */ public void pause() { if (clip != null && clip.isRunning()) { clip.stop(); } isPlaying = false; } /** * 停止,停止后不能继续播放。除非重新加载文件。 */ public void stop() { if (clip != null && clip.isRunning()) { clip.stop(); clip.close(); } // restore isAudioLoad = false; isPlaying = false; playTime = 0.0; audioFullTime = 0.0; audioLyricDTO = null; } /** * 音频文件是否已加载 * * @return */ public boolean isAudioLoad() { return isAudioLoad; } /** * 是否正在播放 * * @return */ public boolean isPlaying() { return isPlaying; } /** * 获取已播放时间 * * @return */ public double getPlayTime() { return playTime; } /** * 获取音频总时长 * * @return */ public double getAudioFullTime() { return audioFullTime; } /** * 获取歌词实体类 * * @return */ public JAudioLyricDTO getAudioLyricDTO() { return audioLyricDTO; } }
图形界面实现:
import java.awt.Color; import java.awt.Graphics; import java.awt.GridBagLayout; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.List; import java.util.Timer; import java.util.TimerTask; import java.util.Vector; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JProgressBar; import javax.swing.JTextPane; import javax.swing.border.EmptyBorder; import javax.swing.text.BadLocationException; import javax.swing.text.DefaultStyledDocument; import javax.swing.text.Style; import javax.swing.text.StyleConstants; import javax.swing.text.StyleContext; public class JAudioGUI extends JFrame { /** 播放器 */ private JAudioPlayer player; /** 全局背景 */ private JLabel background; /** 播放按钮 */ private JButton buttonPlay; /** 歌词模块 */ private JTextPane paneLyric; /** 歌词模块 - 歌词文本对象 */ private DefaultStyledDocument lyricDoc; /** 歌词模块 - 默认歌词格式 */ private Style styleLyricDefault; /** 歌词模块 - 正在播放行的歌词格式 */ private Style styleLyricFocus; /** 播放列表 */ private JList<String> playList; // /** 进度条 */ // private JLabel playTime; /** 进度条 */ private JProgressBar progressBar; /** 播放列表中的音频文件 */ private List<String> audioFilePathList = new ArrayList<>(); /** 播放列表显示的名称 */ private Vector<String> audioFileNames = new Vector<>(); // public JAudioGUI() { // this(null); // } public JAudioGUI(JAudioPlayer player) { this.player = player; super.setTitle("播放器"); super.setBounds(160, 100, 710, 430); super.setLayout(null); this.initBackground(); // 初始化全局背景 this.initButtonPlay(); // 初始化播放按钮 this.initPaneLyric(); // 初始化歌词模块 this.initPlayList(); // 初始化播放列表 this.initPlayProgress(); // 初始化进度条 this.initGif(); // 初始化GIF super.setVisible(true);// 放在添加组件后面执行 super.setDefaultCloseOperation(EXIT_ON_CLOSE); // 进度条 歌词滚动等 Timer timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { if (player == null) { return; } // 进度条 start double playTimeDouble = player.getPlayTime(); double progress = (playTimeDouble / player.getAudioFullTime()) * 1000; progressBar.setValue((int) progress); String playTimeStr = JAudioUtils.seconds2TimeStr((int) player.getPlayTime()); progressBar.setString(playTimeStr); // 进度条 end // 设置歌词滚动显示 start JAudioLyricDTO lyricDTO = player.getAudioLyricDTO(); if (lyricDTO == null || lyricDTO.getLyricTimeTextList().isEmpty()) { return; } // 取出歌词实体类 List<JAudioLyricTimeTextDTO> lyricTimeTextDTOList = lyricDTO.getLyricTimeTextList(); // 取出需要展示的部分歌词 List<JAudioLyricTimeTextDTO> lyric4Show = lyric4Show(lyricTimeTextDTOList, playTimeDouble); try { lyricDoc.remove(0, lyricDoc.getLength()); // 清除现有内容 for (JAudioLyricTimeTextDTO timeTextDTO : lyric4Show) { lyricDoc.insertString(lyricDoc.getLength(), timeTextDTO.getLyricText() + "\n", timeTextDTO.isFocusOn() ? styleLyricFocus : styleLyricDefault); } // lyricDoc.setCharacterAttributes(10, 10, styleLyricFocus, true); } catch (BadLocationException e) { e.printStackTrace(); } // 设置歌词滚动显示 end } }, 0, 100); // 每 100毫秒(0.1秒)刷新一次 } private List<JAudioLyricTimeTextDTO> lyric4Show(List<JAudioLyricTimeTextDTO> lyricTimeTextDTOList, double playTimeDouble) { lyricTimeTextDTOList.forEach(x -> x.setFocusOn(false)); // 重置 focusOn 的值 List<JAudioLyricTimeTextDTO> dtoList = new ArrayList<>(); // 找到正在播放的歌词所在的行 int targetIndex = -99; for (int i = 0; i < lyricTimeTextDTOList.size(); i++) { JAudioLyricTimeTextDTO timeTextDTO = lyricTimeTextDTOList.get(i); double lyricTimeDouble = timeTextDTO.getLyricTimeDouble(); if (lyricTimeDouble >= playTimeDouble) { // if (playTimeDouble - lyricTimeDouble <= 0.1) { // 提前 0.1 秒加载 targetIndex = i; timeTextDTO.setFocusOn(true); break; } } // 取前2行 ~ 后3行,共6行数据 int startIndex = targetIndex - 2; int endIndex = targetIndex + 3; for (int i = startIndex; i <= endIndex; i++) { if (i < 0 || i >= lyricTimeTextDTOList.size()) { dtoList.add(new JAudioLyricTimeTextDTO(null, "")); continue; } dtoList.add(lyricTimeTextDTOList.get(i)); } return dtoList; } /** * 添加音频文件 */ public void addAudioFile(String filePath) { audioFilePathList.add(filePath); double audioFullTime = JAudioPlayer.audioFullTime(filePath); String audioFullTimeStr = JAudioUtils.seconds2TimeStr((int) audioFullTime); String fileName = filePath.substring(filePath.lastIndexOf("/") + 1); audioFileNames.add(fileName + " " + audioFullTimeStr); } /** * 初始化全局背景 */ private void initBackground() { this.background = new JLabel(); // background.setIcon(new ImageIcon(JAudioConst.IMAGE_BACKGROUND)); // 设置背景图片 background.setIcon(JAudioUtils.readImageIcon(JAudioConst.IMAGE_BACKGROUND)); // 设置背景图片 background.setBounds(0, 0, 700, 400); // 设置背景控件大小 super.getLayeredPane().add(background, new Integer(Integer.MIN_VALUE)); // 背景图片控件置于最底层 ((JPanel) super.getContentPane()).setOpaque(false); // 控件透明 } /** * 初始化播放按钮 */ private void initButtonPlay() { this.buttonPlay = new JButton(); super.add(buttonPlay); buttonPlay.setBounds(322, 335, 40, 40); buttonPlay.setIcon(JAudioUtils.readImageIcon(JAudioConst.IMAGE_PLAY)); // 设置图标 // buttonPlay.setText("播放"); buttonPlay.setOpaque(false); // 背景透明 // 添加按钮响应 buttonPlay.addActionListener(actionEvent -> { if (player == null || !player.isAudioLoad()) { return; } if (player.isPlaying()) { player.pause(); // 正在播放则暂停 buttonPlay.setIcon(JAudioUtils.readImageIcon(JAudioConst.IMAGE_PLAY)); // 设置图标 } else { player.play(); // 不在播放则播放 buttonPlay.setIcon(JAudioUtils.readImageIcon(JAudioConst.IMAGE_PAUSE)); // 设置图标 } }); } /** * 初始化歌词模块 */ private void initPaneLyric() { // 初始化 歌词格式对象 StyleContext styleContext = new StyleContext(); this.styleLyricDefault = styleContext.getStyle(StyleContext.DEFAULT_STYLE); StyleConstants.setForeground(styleLyricDefault, Color.WHITE); this.styleLyricFocus = styleContext.addStyle("styleLyricFocus", null); StyleConstants.setForeground(styleLyricFocus, Color.RED); StyleConstants.setBold(styleLyricFocus, true); // 初始化歌词模块 this.lyricDoc = new DefaultStyledDocument(); this.paneLyric = new JTextPane(lyricDoc); super.add(paneLyric); paneLyric.setBounds(20, 100, 200, 100); paneLyric.setForeground(Color.white);// 字体白色 paneLyric.setEditable(false); paneLyric.setOpaque(false);// 背景透明 // paneLyric.setText("芙蓉花又栖满了枝头 \n" + "奈何蝶难留\n" + "漂泊如江水向东流\n" + "望断门前隔岸的杨柳 \n"); paneLyric.setText("------歌词------\n" // + "------歌词------\n" // + "------歌词------\n" // + "------歌词------\n" // + "------歌词------\n" // + "------歌词------" // ); // try { // // 添加文本时设置默认的格式 // lyricDoc.insertString(lyricDoc.getLength(), "line1: text text \n", styleLyricDefault); // lyricDoc.insertString(lyricDoc.getLength(), "line2: text text \n", styleLyricDefault); // lyricDoc.insertString(lyricDoc.getLength(), "line3: text text \n", styleLyricDefault); // lyricDoc.insertString(lyricDoc.getLength(), "line4: text text \n", styleLyricDefault); // lyricDoc.insertString(lyricDoc.getLength(), "line5: text text \n", styleLyricDefault); // lyricDoc.insertString(lyricDoc.getLength(), "line6: text text \n", styleLyricDefault); // lyricDoc.insertString(lyricDoc.getLength(), "line7: text text \n", styleLyricDefault); // lyricDoc.insertString(lyricDoc.getLength(), "line8: text text \n", styleLyricFocus); // lyricDoc.insertString(lyricDoc.getLength(), "line9: text text \n", styleLyricDefault); // // // 修改已有文本的格式 // lyricDoc.setCharacterAttributes(10, 10, styleLyricFocus, true); // // 删除文本 // lyricDoc.remove(0, 3); // } catch (BadLocationException e) { // e.printStackTrace(); // } } /** * 初始化播放列表 */ private void initPlayList() { this.playList = new JList(); // 创建播放列表 super.add(playList); // 添加播放列表至窗口中 playList.setBounds(500, 100, 150, 150); // 设置播放列表大小 playList.setOpaque(false);// 设置播放列表透明 playList.setBackground(new Color(0, 0, 0, 0));// 设置播放列表背景颜色 playList.setForeground(Color.white);// 设置播放列表字体颜色 // playFiles.forEach( // x -> vertor.add(x.getName() + "\t" + Math.floor(JAudioPlayer.audioFullTime(x.getAbsolutePath())))); // // Vector<String> vertor = new Vector<>(); // vertor.add("花海"); // vertor.add("珊瑚海"); // vertor.add("七里香"); // vertor.add("浪漫手机"); // playList.setListData(vertor); playList.setListData(audioFileNames); playList.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent mouseEvent) { // 双击 if (mouseEvent.getClickCount() == 2) { int jlistIndex = playList.getSelectedIndex(); // 停止播放当前的音乐 player.stop(); // 加载双击选中的文件 String audioFilePath = audioFilePathList.get(jlistIndex); try { player.load(audioFilePath); } catch (Exception e) { JOptionPane.showMessageDialog(null, "加载音频文件出错:" + audioFilePath); // JOptionPane.showMessageDialog(null, "加载音频文件出错:" //// + e.getMessage() + "\n" // + e.getStackTrace() //// + e.getCause() // ); } // 播放双击选中的文件 player.play(); // 更改播放按钮的图标 buttonPlay.setIcon(JAudioUtils.readImageIcon(JAudioConst.IMAGE_PAUSE)); // 设置图标 } } }); } /** * 初始化进度条 */ private void initPlayProgress() { // this.playTime = new JLabel(); // 创建播放进度条对象 // playTime.setIcon(new ImageIcon(imageFilePath_timeFlag)); // playTime.setBounds(0,324,0,3); // 设置播放进度条对象大小 // super.add(playTime); // 添加播放进度条至窗口中 // progressBar.setForeground(Color.BLACK); // progressBar.setStringPainted(true); // progressBar.setOpaque(false); // progressBar.setBounds(73, 103, 434, 24); // this.getContentPane().add(progressBar); this.progressBar = new JProgressBar(); super.add(progressBar); progressBar.setMaximum(1000); progressBar.setMinimum(0); progressBar.setStringPainted(true); progressBar.setIndeterminate(false); progressBar.setBounds(0, 314, 700, 20); progressBar.setOpaque(false); // 透明 // progressBar.setPreferredSize(new Dimension(780, 30)); // progressBar.setValue(50); // 进度百分值 // progressBar.setString("02:19"); // 显示文本 } private void initGif() { // 创建面板 JPanel jPanel = new JPanel() { @Override protected void paintComponent(Graphics graphics) { super.paintComponent(graphics); graphics.setColor(getBackground()); graphics.fillRect(0, 0, super.getWidth(), super.getHeight()); } }; jPanel.setBounds(240, 100, 200, 100); jPanel.setLayout(new GridBagLayout()); jPanel.setBorder(new EmptyBorder(12, 12, 12, 12)); jPanel.setOpaque(false); jPanel.setBackground(new Color(0, 0, 0, 150)); JLabel loadBar = new JLabel(JAudioUtils.readImageIcon(JAudioConst.GIF_PATH)); loadBar.setHorizontalAlignment(JLabel.CENTER); loadBar.setVerticalAlignment(JLabel.CENTER); jPanel.add(loadBar); this.background.add(jPanel); } }
项目的工具类:
import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; import java.util.function.BiFunction; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.ImageIcon; import javax.swing.JOptionPane; /** * 工具类 */ public class JAudioUtils { /** * 将秒数转换为时分秒 HH:mm:ss * * @param seconds * @return */ public static String seconds2TimeStr(int seconds) { if (seconds < 0) { return ""; } // 计算 int second = seconds % 60; int minutes = seconds / 60; int minute = minutes % 60; int hours = minutes / 60; // 拼接 StringBuilder sb = new StringBuilder(); if (hours > 0) { sb.append(hours).append(":"); } sb.append(String.format("%02d", minute)).append(":"); sb.append(String.format("%02d", second)); return sb.toString(); } /** * 读取歌词文件,并封装成实体类 * * @param lyricFilePath * @return */ public static JAudioLyricDTO readAudioLyricFile(String lyricFilePath) { List<String> lines = readTextFile(lyricFilePath); return analyzeLyricLines(lines); } /** * 按行读取文本文件 * * @param textFilePath * @return */ public static List<String> readTextFile(String textFilePath) { List<String> lines = new ArrayList<>(); // 按行读取歌词文件 try (InputStreamReader isr = new InputStreamReader(JAudioUtils.loadFileAsStream(textFilePath), "UTF-8"); BufferedReader reader = new BufferedReader(isr)) { String line = null; while ((line = reader.readLine()) != null) { lines.add(line); } } catch (FileNotFoundException e) { e.printStackTrace(); JOptionPane.showMessageDialog(null, "读取文本文件出错:" + textFilePath // + " error message:" + e.getMessage()); } catch (IOException e) { e.printStackTrace(); JOptionPane.showMessageDialog(null, "读取文本文件出错:" + textFilePath // + " error message:" + e.getMessage()); } return lines; } /** * 解析歌词 * * @param lyricLines * @return */ public static JAudioLyricDTO analyzeLyricLines(List<String> lyricLines) { // [ti:千里之外] // [ar:周杰伦/费玉清] // [al:依然范特西] // [by:] // [offset:0] // [00:00.00]千里之外 - 周杰伦 (Jay Chou)/费玉清 (Yu-Ching Fei) // [00:04.91]词:方文山 // [00:09.82]曲:周杰伦 // [00:14.73]编曲:林迈可 // [00:19.64]周: // [00:24.66]屋檐如悬崖 // [00:26.75]风铃如沧海 // [00:28.76]我等燕归来 // 正则表达式,用于提取 歌词内容 String regexTitle = "^\\[ti:(.*)\\]$"; String regexAuthor = "^\\[ar:(.*)\\]$"; String regexAlbum = "^\\[al:(.*)\\]$"; String regexBy = "^\\[by:(.*)\\]$"; String regexOffset = "^\\[offset:(.*)\\]$"; String regexLyricTimeText = "^\\[(\\d{2}:\\d{2}.\\d{2})\\](.*)$"; // 用于提取 title author 等字段的 function BiFunction<String, List<String>, String> matchFunc = (regex, strList) -> { Pattern pattern = Pattern.compile(regex); for (String str : strList) { Matcher matcher = pattern.matcher(str); if (matcher.matches()) { return matcher.group(1); } } return ""; }; // 用于提取 歌词时间 歌词内容的 function BiFunction<String, List<String>, List<JAudioLyricTimeTextDTO>> matchFunc2 = (regex, strList) -> { List<JAudioLyricTimeTextDTO> lyricTimeTextList = new ArrayList<>(); Pattern pattern = Pattern.compile(regex); for (String str : strList) { Matcher matcher = pattern.matcher(str); if (matcher.matches()) { String lyricTime = matcher.group(1); String lyricText = matcher.group(2); lyricTimeTextList.add(new JAudioLyricTimeTextDTO(lyricTime, lyricText)); } } return lyricTimeTextList; }; // 提取歌词文件的内容,并封装对象 JAudioLyricDTO dto = new JAudioLyricDTO(); dto.setTitle(matchFunc.apply(regexTitle, lyricLines)); dto.setAuthor(matchFunc.apply(regexAuthor, lyricLines)); dto.setAlbum(matchFunc.apply(regexAlbum, lyricLines)); dto.setBy(matchFunc.apply(regexBy, lyricLines)); dto.setOffset(matchFunc.apply(regexOffset, lyricLines)); dto.setLyricTimeTextList(matchFunc2.apply(regexLyricTimeText, lyricLines)); // 将歌词所在时间 转换为 double dto.getLyricTimeTextList().forEach(x -> { // [01:13.24]我送你离开千里之外你无声黑白 String lyricTimeStr = x.getLyricTime(); int minutes = Integer.valueOf(lyricTimeStr.substring(0, 2)); double seconds = Double.valueOf(lyricTimeStr.substring(3)); double lyricTimeDouble = minutes * 60 + seconds; x.setLyricTimeDouble(lyricTimeDouble); }); // 修正歌词后期不准的问题,根据百分比,修正 0-2 秒 // double lastLyricTimeDouble = // 最后一句歌词 // dto.getLyricTimeTextList().get(dto.getLyricTimeTextList().size() - 1).getLyricTimeDouble(); // dto.getLyricTimeTextList().forEach(x -> { //// double fixValue = x.getLyricTimeDouble() / lastLyricTimeDouble * 1.5; // x.setLyricTimeDouble(x.getLyricTimeDouble() * 0.95); // }); return dto; } /** * 通过流的方式读取 image文件 * * @param relativePath * @return */ public static ImageIcon readImageIcon(String relativePath) { // BufferedImage image = ImageIO.read(JAudioUtils.class.getResourceAsStream(relativePath)); return new ImageIcon(JAudioUtils.class.getResource(relativePath)); } /** * 将文件加载为 BufferedInputStream <br> * 注意本方法不会关闭流 * * @param relativePath * @return */ public static BufferedInputStream loadFileAsStream(String relativePath) { return new BufferedInputStream(JAudioUtils.class.getResourceAsStream(relativePath)); } public static void main(String[] args) { // System.out.println(seconds2TimeStr(261)); // System.out.println(seconds2TimeStr(3861)); // testRegex(); JAudioLyricDTO dto = readAudioLyricFile("./src/main/resources/audioLyric/千里之外.txt"); System.out.println(dto); } // private static void testRegex() { // String regexTitle = "^\\[ti:(.*)\\]$"; // String regexAuthor = "^\\[ar:(.*)\\]$"; // String regexAlbum = "^\\[al:(.*)\\]$"; // String regexBy = "^\\[by:(.*)\\]$"; // String regexOffset = "^\\[offset:(.*)\\]$"; // String regexLyric = "^\\[(\\d{2}:\\d{2}.\\d{2})\\](.*)$"; // // String title = "[ti:千里之外]"; // String author = "[ar:周杰伦/费玉清]"; // String album = "[al:依然范特西]"; // String by = "[by:]"; // String offset = "[offset:0]"; // String lyric = "[00:00.00]千里之外 - 周杰伦 (Jay Chou)/费玉清 (Yu-Ching Fei)"; // // Matcher matcher = Pattern.compile(regexLyric).matcher(lyric); // System.out.println(matcher.matches()); // System.out.println(matcher.group(1)); // System.out.println(matcher.group(2)); // } }
项目的常量类:
import java.util.Arrays; import java.util.List; /** * 常量类 */ public interface JAudioConst { /** 默认的音频文件 */ List<String> AUDIO_FILE_PATH_LIST = Arrays.asList( // "audio/千里之外.wav", // "audio/晴天.wav", // "audio/稻香.wav", // "audio/简单爱.wav", // "audio/花海.wav", // "audio/青花瓷.wav" // ); /** 图片路径:背景图 */ String IMAGE_BACKGROUND = "image/background_pink.jpg"; /** 图片路径:播放按钮 */ String IMAGE_PLAY = "image/play.png"; /** 图片路径:播放按钮 */ String IMAGE_PAUSE = "image/pause.png"; // /** 图片路径:进度条 */ // String IMAGE_PROGRESS = "image/progress.png"; /** gif 动图路径 */ // String GIF_PATH = "image/gif_flower.gif"; String GIF_PATH = "image/gif_bongoCat.gif"; }
项目的实体类:
import java.util.List; import lombok.Data; /** * 歌词实体类 */ @Data public class JAudioLyricDTO { private String title; // 标题 private String author; // 作者 private String album; // 专辑 private String by; // 这不知道是啥 private String offset; // 这不知道是啥 // 歌词 时间 和 文字 private List<JAudioLyricTimeTextDTO> lyricTimeTextList; }
import lombok.Data; /** * 单句歌词实体类 */ @Data public class JAudioLyricTimeTextDTO { private String lyricTime; private String lyricText; private double lyricTimeDouble; // 歌词所在时间转换为 double 方便计算 private boolean focusOn; // 是否正在播放本句 public JAudioLyricTimeTextDTO(String lyricTime, String lyricText) { this.lyricTime = lyricTime; this.lyricText = lyricText; } }