0

我使用 JLayer 在 Java 中创建了一个媒体播放器,它接受 mp3 文件。一旦用户播放该歌曲,我也会显示特定歌曲的歌词,但现在我想以某种方式突出显示或更改歌曲中听到的歌词的文本颜色(如卡拉 OK)。我只需要为一首歌曲执行此操作 - 我将在我的程序中实现歌词。我已经搜索过如何做到这一点,但似乎无法准确找到我正在寻找的东西。下面我将代码添加到播放音乐文件的类中。先谢谢了!

public class PlayMusic {

/**
 * Global variables. FileInputStream obtains input bytes from a file system
 * and reads streas of raw bytes. BufferedInputStream adds functionality
 * to the fis, and creates an internal buffer array.
 */
private String filename;
private Player player; 
private boolean canResume;
private boolean valid;
private int total;
private int stopped;
FileInputStream fis;
BufferedInputStream bis;


/**
 * Constructor the takes in the path of the mp3 file to be played.
 * @param filename - path of the mp3 file
 */
public PlayMusic(String filename) {
    this.filename = filename;
    this.canResume = false;
    this.valid = false;
    this.total = 0;
    this.stopped = 0;
    this.fis = null;
    this.bis = null;
}

/**
 * Function called to stop a song altogether as opposed to pausing.
 */
public void close() { 
    if (player != null) 
        player.close(); 
    stopped = 0;
    fis = null;
    bis = null;
    player = null;
    canResume = false;
    }


/**
 * Function called to pause a song. Fis.available() is a method that returns
 * the number of remaining bytes that can be read from the input stream.
 */
public void pause(){ 
    try {
        if (fis!=null)
            stopped = fis.available();
        if (player!= null)
            player.close();
        fis = null;
        bis = null;
        player = null;
        if(valid) 
            canResume = true;
    } catch (IOException e) {

    }


}

/**
 * Function called when we want to resume a song from where it left off
 * after being paused.
 */
public void resume()
{
    if(!canResume)
        return;
    if(play(total-stopped))
        canResume = false;
}

/**
 * Function called to play the song and keep track of where in the song the
 * user presses stop in order for the resume button to work properly. Fis.skip
 * skips over and discards pos bytes of data from fis.
 * @param pos - The position of the song in which we want to resume play
 * @return
 */
public boolean play(int pos) {
    valid = true;
    canResume = false;
    try {
        fis = new FileInputStream(filename);
        total = fis.available();
        if(pos> -1)
            fis.skip(pos);
        bis = new BufferedInputStream(fis);
        player = new Player(bis);

    }
    catch (Exception e) {
        System.out.println("Problem playing file " + filename);
        System.out.println(e);
    }



    /**
     * Run the play button in a new thread so the music plays in the background.
     */
    new Thread() {
        public void run() {
            try { player.play(); }
            catch (Exception e) { System.out.println(e); valid = false; }
        }
    }.start();


    return valid;

}

}

4

1 回答 1

2

您将无法检测到歌曲中正在唱什么词(至少很容易),但是如果您将歌曲的歌词保存在文件中,并且您有歌曲的声音文件,那么对我来说听起来您可以在该歌词文件中添加更多信息,以创建歌词中歌词何时在歌曲中演唱的地图。

例如,如果我要对歌曲Jingle Bells执行此操作,我可能有一个包含歌词的制表符分隔文件,其中一行是一个单词,开始和结束时间相对于歌曲的开始时间(以毫秒为单位)。

jingle 0 1000
bells 1001 1500
jingle 1501 2500
bells 2501 3000
... and so on

编辑以解释如何编写代码来跟踪歌曲播放了多长时间。

创建实例变量的两种方法叫做say,totalTimeSongHasBeenPlaying

  1. 我不确定您是如何抽象出播放声音文件的,但是说您将其抽象到一个Sound类中,那么您可以有三个方法,sound.soundStarted, sound.soundStopped, sound.soundRestarted,然后在开始播放可以调用的声音时soundStarted可以抓取aSystem.nanoTime或 aSystem.currentTimeMillis和 on soundStopped,您可以再次抓取它并获取差异并将其添加到totalTimeSongHasBeenPlaying,然后soundRestart您可以设置totalTimeSongHasBeenPlaying为零。

  2. 对当前播放的声音的帧位置与该文件的每秒帧数进行一些数学运算。我不知道确切的库JLayer,因为我使用它已经有一段时间了,但该方法也应该告诉你你在文件中的距离。

之后,Sound 类也可以有一个方法,例如currentWordBeingSung(),它查看totalTimeSongHasBeenPlaying并使用您在构建期间从歌词文件中创建的查找表,并唯一地返回特定单词(可能是重复的)。当你创建它时,你的 guiJLyricsViewer可以保存你的对象的一个​​实例,Sound你可以使用 aSwingTimer每隔 50 毫秒左右重新绘制它,在你的paintComponent方法中它在哪里查看currentWordBeingSung()

于 2014-04-28T16:16:30.383 回答