课程设计
大二下 Java + MySQL 两者结合的课程设计。
主题
一个音乐播放器,界面简陋,功能未能实现。只能对一个 .wav 格式的音频进行解码播放,仅此,想加上一个歌词同步功能,搞了好久都搞不起,遂放弃,觉得搞个其他的算了,格式转换太麻烦了。数据库未能来得及加上,已经放弃。暑假或者以后有时间再来完善一下,接着搞这个。
源码
package MusicPlayer;
import javax.sound.sampled.*;
import javax.swing.*;
import javax.swing.Timer;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.List;
/**
* @author WangYH
* @version 2021.1.3
* @date 2023/6/1 22:14
*/
public class MusicPlayer extends JFrame implements ActionListener {
private JButton openButton, playButton, pauseButton, stopButton, lyricButton;
private JFileChooser fileChooser, lyricChooser;
private JLabel nameLabel, timeLabel, lyricLabel;
private Clip clip;
private Timer timer;
private ArrayList<Long> timeList;
private ArrayList<String> lyricList;
Map<Long, String> lyricMap;
Map<Long, String> sortedMap;
private boolean flag = true;
private int count = 1;
File lyricFile = null;
public MusicPlayer() {
super("音乐播放器");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(800, 500);
setVisible(true);
// 创建按钮
openButton = new JButton("选择歌曲");
playButton = new JButton("播放");
pauseButton = new JButton("暂停");
stopButton = new JButton("停止");
lyricButton = new JButton("选择歌词");
// 添加按钮监听器
openButton.addActionListener(this);
playButton.addActionListener(this);
pauseButton.addActionListener(this);
stopButton.addActionListener(this);
lyricButton.addActionListener(this);
// 创建文件选择器
fileChooser = new JFileChooser();
fileChooser.setCurrentDirectory(new File("D:\\JAVA\\IDEAProject\\MusicPlayer\\src\\music"));
lyricChooser = new JFileChooser();
lyricChooser.setCurrentDirectory(new File("D:\\JAVA\\IDEAProject\\MusicPlayer\\src\\music"));
nameLabel = new JLabel("歌曲名称");
timeLabel = new JLabel("00:00 / 00:00");
lyricLabel = new JLabel();
// 创建面板并添加按钮
JPanel buttonPanel = new JPanel();
buttonPanel.add(playButton);
buttonPanel.add(pauseButton);
buttonPanel.add(stopButton);
//
JPanel selectFilePanel = new JPanel();
selectFilePanel.setPreferredSize(new Dimension(400, 200));
selectFilePanel.setVisible(true);
selectFilePanel.setLayout(null);
openButton.setBounds(20, 20, 90, 30);
lyricButton.setBounds(150, 20, 90, 30);
selectFilePanel.add(openButton);
selectFilePanel.add(lyricButton);
JPanel infoPanel = new JPanel();
infoPanel.setLayout(new GridLayout(3, 1));
infoPanel.add(nameLabel);
infoPanel.add(timeLabel);
infoPanel.add(lyricLabel);
// 将面板添加到窗口
Container contentPane = getContentPane();
contentPane.add(buttonPanel, BorderLayout.SOUTH);
contentPane.add(selectFilePanel, BorderLayout.NORTH);
contentPane.add(infoPanel, BorderLayout.CENTER);
contentPane.setLocation(800, 500);
pack();
this.setVisible(true);
//创建定时器
timer = new Timer(500, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (clip != null && clip.isRunning()) {
long position = clip.getMicrosecondPosition() / 1000;
long duration = clip.getMicrosecondLength();
String timeStr = formatTime(position) + "/" + formatTime(duration);
timeLabel.setText(timeStr);
/*long time1 = 0, time = 0,time2 = 0,time3 = 0;
time1 = Long.parseLong(timeParts[0]) * 60 * 1000;
time2 = Long.parseLong(timeParts[1]) * 1000;
time3 = Long.parseLong(timeParts[2]);
time = ( time1 + time2 + time3);*/
if(flag){
// 将Map转换为List
List<Map.Entry<Long, String>> list = new ArrayList<>(lyricMap.entrySet());
// 对List进行排序
Collections.sort(list,new Comparator< Map.Entry< Long,String>>(){
@Override
public int compare(Map.Entry<Long, String> o1, Map.Entry<Long, String> o2) {
return o1.getKey().compareTo(o2.getKey());
}
});
// 将排序后的List转换为Map
sortedMap = new LinkedHashMap<>();
for (Map.Entry<Long, String> entry : list) {
sortedMap.put(entry.getKey(), entry.getValue());
}
flag = false;
}
long time1 = 0,time2 = 0;
//查找当前时间对应的歌词
if (sortedMap != null) {
for(Map.Entry<Long,String> entry : sortedMap.entrySet()){
if(count == 3){
count = 1;
break;
}
if(count == 1){
time1 = entry.getKey();
count++;
continue;
}
if (count == 2) {
time2 = entry.getKey();
count++;
continue;
}
}
String lyric = sortedMap.get(time1);
sortedMap.remove(time1);
if (lyric == null) {
lyric = " ";
}
lyricLabel.setText(lyric);
try {
if (time1 < 1000) {
Thread.sleep(time2 - time1);
}
else {
Thread.sleep(time2 - time1);
}
} catch (InterruptedException interruptedException) {
interruptedException.printStackTrace();
}
}
}
}
});
}
@Override
public void actionPerformed(ActionEvent e) {
class LyricMap <K> implements Map<Long, String> {
private HashMap<Long,String> map;
public LyricMap(){
map = new HashMap<Long, String>();
}
@Override
public int size() {
return map.size();
}
@Override
public boolean isEmpty() {
return map.isEmpty();
}
@Override
public boolean containsKey(Object key) {
return map.containsKey(key);
}
@Override
public boolean containsValue(Object value) {
return map.containsValue(value);
}
@Override
public String get(Object key) {
return map.get(key);
}
@Override
public String put(Long key, String value) {
return map.put(key,value);
}
@Override
public String remove(Object key) {
return map.remove(key);
}
@Override
public void putAll(Map<? extends Long, ? extends String> m) {
map.putAll(m);
}
@Override
public void clear() {
map.clear();
}
@Override
public Set<Long> keySet() {
return map.keySet();
}
@Override
public Collection<String> values() {
return map.values();
}
@Override
public Set<Entry<Long, String>> entrySet() {
return map.entrySet();
}
}
if (e.getSource() == openButton) {
// 显示文件选择器
int resultSing = fileChooser.showOpenDialog(this);
if (resultSing == JFileChooser.APPROVE_OPTION) {
// 获取用户选择的文件
File selectedFile = fileChooser.getSelectedFile();
try {
// 创建音频输入流
AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(selectedFile);
AudioFormat format = audioInputStream.getFormat();
DataLine.Info info = new DataLine.Info(Clip.class, format);
// 创建音频剪辑
clip = (Clip) AudioSystem.getLine(info);
// 打开音频剪辑
clip.open(audioInputStream);
//更新标签内容
nameLabel.setText("歌曲名称 " + selectedFile.getName());
timeLabel.setText("00:00/ " + formatTime(clip.getMicrosecondLength()));
int resultLyric = lyricChooser.showOpenDialog(this);
if (resultLyric == JFileChooser.APPROVE_OPTION) {
// 获取用户选择的文件
lyricFile = lyricChooser.getSelectedFile();
}
if (lyricFile.exists()) {
BufferedReader reader = new BufferedReader(new FileReader(lyricFile));
lyricMap = new LyricMap<>();
timeList = new ArrayList<>();
lyricList = new ArrayList<>();
String line;
while ((line = reader.readLine()) != null) {
String[] parts = line.split("\\]|\\[");
int partslength = parts.length;
for (int i = 1; i < partslength; i += 2) {
String timeStr = parts[i].substring(1);
if (" ".equals(timeStr)){
continue;
}
String[] timeParts = timeStr.split("[:.]");
if (timeParts.length == 3) {
long time1 = 0, time = 0,time2 = 0,time3 = 0;
try {
time1 = Long.parseLong(timeParts[0]) * 60 * 1000;
time2 = Long.parseLong(timeParts[1]) * 1000;
time3 = Long.parseLong(timeParts[2]);
time = ( time1 + time2 + time3);
if (time != 0) {
timeList.add(time);
lyricList.add(parts[i+1]);
}
/* lyricMap.put(time,parts[i + 1]);*/
} catch (Exception e1) {
// 处理异常,例如输出错误信息或设置默认值
System.err.println("Invalid time string: " + time);
time = -1;
// 设置默认值为-1
}
/* timeList.add(time);
lyricList.add(parts[i+1]);*/
}
}
}
reader.close();
/**
* put() 方法用于将键值对插入到 lyricMap 中。
* 在这里,timeList.get(i) 是获取第 i 个时间戳,
* lyricList.get(i) 是获取第 i 个歌词内容,然后将它们作为键值对插入到 lyricMap 中。
*/
for (int i = 0; i < timeList.size(); i++) {
lyricMap.put(timeList.get(i),lyricList.get(i));
}
}
timer.start();
} catch (UnsupportedAudioFileException | IOException | LineUnavailableException ex) {
JOptionPane.showMessageDialog(this, "无法打开文件:" + ex.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
}
}
} else if (e.getSource() == playButton) {
// 播放音频剪辑
if (clip != null) {
clip.start();
}
} else if (e.getSource() == pauseButton) {
// 暂停音频剪辑
if (clip != null) {
clip.stop();
}
} else if (e.getSource() == stopButton) {
// 停止音频剪辑
if (clip != null) {
clip.stop();
clip.setFramePosition(0);
//clip.setFramePosition(0)的意思是将音频剪辑的帧位置设置为0,也就是从音频剪辑的开头开始播放。
//
//这个方法通常用于重复播放音频剪辑,当音频剪辑播放完成后,我们可以使用该方法将帧位置重置为0,从而实现循环播放的效果。
lyricLabel.setText("歌词");
}
}
}
/**
* 将时间(以微秒为单位)格式化为字符串
*
* @param time 时间(以微秒为单位)
* @return 格式化后的字符串(格式为“mm:ss”)
*/
private String formatTime(long time) {
SimpleDateFormat formatter = new SimpleDateFormat("mm:ss");
return formatter.format(time / 1000);
}
}
测试
package MusicPlayer;
import com.musicplayer.MusicUI;
/**
* @author WangYH
* @version 2021.1.3
* @date 2023/6/2 22:08
*/
public class MusicplayTest {
public static void main(String[] args) {
MusicPlayer musicPlayer = new MusicPlayer();
musicPlayer.setVisible(true);
}
}
转换歌词
package com.musicplayer;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Map;
import java.util.TreeMap;
/**
* @author WangYH
* @version 2021.1.3
* @date 2023/6/2 20:18
*/
public class LrcParser {
private Map<Long, String> lyricMap;
private ArrayList<Long> timeList;
private ArrayList<String> lyricList;
public LrcParser() {
lyricMap = new TreeMap<>();
timeList = new ArrayList<>();
lyricList = new ArrayList<>();
}
public void readLyricFile(String filePath) {
try {
BufferedReader reader = new BufferedReader(new FileReader(filePath));
String line;
while ((line = reader.readLine()) != null) {
String[] parts = line.split("\\]|\\[");
int partslength = parts.length;
for (int i = 1; i < partslength; i+=2){
String timeStr = parts[i].substring(1);
String[] timeParts = timeStr.split("[:.]");
if (timeParts.length == 3) {
long time1 = 0,time = 0,time2 = 0,time3 = 0;
try {
time1 = Long.parseLong(timeParts[0]) * 60 * 1000;
time2 = Long.parseLong(timeParts[1]) * 1000;
time3 = Long.parseLong(timeParts[2]);
time = ( time1 + time2 + time3);
lyricMap.put(time,parts[i + 1]);
}catch (Exception e){
// 处理异常,例如输出错误信息或设置默认值
System.err.println("Invalid time string: " + time);
time = -1;
// 设置默认值为-1
}
/*timeList.add(time);
lyricList.add(parts[i+1]);*/
}
}
}
reader.close();
/*
for (int i = 0; i < timeList.size(); i++) {
lyricMap.put(timeList.get(i), lyricList.get(i));
}*/
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
LrcParser parser = new LrcParser();
parser.readLyricFile("D:\\JAVA\\IDEAProject\\MusicPlayer\\src\\music\\我的名字 - 焦迈奇.lrc");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
/*parser.lyricMap.forEach((Key, value) -> System.out.println(Key + ":" + value));*/
/*
for (Map.Entry<Long, String> entry : parser.lyricMap.entrySet()) {
Long key = entry.getKey();
String value = entry.getValue();
System.out.println(key + ": " + value);
}*/
PrintWriter writer = new PrintWriter(new OutputStreamWriter(System.out, StandardCharsets.UTF_8), true);
parser.lyricMap.forEach((key, value) -> writer.println(key + ": " + value));
}
}