Как выделить тексты песен при воспроизведении mp3-файла (например, караоке) с помощью JLayer

Я создал медиаплеер на Java с помощью JLayer, и он принимает файлы mp3. У меня также есть текст конкретной песни, который появляется, когда пользователь воспроизводит эту песню, но теперь я хочу каким-то образом выделить или изменить цвет текста текста, когда он звучит в песне (например, караоке). Мне нужно сделать это только для одной песни, и у меня уже есть лирика, встроенная в мою программу. Я уже искал, как это сделать, но не могу найти именно то, что ищу. Ниже я добавил в свой класс код, который воспроизводит музыкальный файл. Заранее спасибо!

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;

}

}


person user3078608    schedule 28.04.2014    source источник
comment
Если вам нужно сделать это только для одной песни, я бы посоветовал сделать видео с текстами, в которых основные моменты появляются в нужное время, с помощью видеоредактора.   -  person DJClayworth    schedule 28.04.2014
comment
Используете ли вы файл в формате .srt?   -  person ggovan    schedule 28.04.2014
comment
@DJClayworth это определенно было бы проще, но я работаю над окончательным проектом для класса программирования и хотел бы сделать это с помощью кодирования.   -  person user3078608    schedule 28.04.2014
comment
@ggovan нет, моя программа принимает только файлы mp3.   -  person user3078608    schedule 28.04.2014
comment
Итак, как узнать, когда отображать текст?   -  person ggovan    schedule 28.04.2014
comment
Поскольку я пытаюсь сделать это только для одной конкретной песни, когда пользователь нажимает кнопку воспроизведения песни, я проверяю, совпадают ли исполнитель и название песни с исполнителем и названием конкретной песни, которую я хочу добавить. лирика/караоке. Если это совпадает, то, поскольку эти тексты уже сохранены в моей программе, они будут отображаться.   -  person user3078608    schedule 28.04.2014


Ответы (1)


Вы не сможете определить, какие слова поются в песне (по крайней мере, с легкостью), но если у вас есть текст песни в файле, и у вас есть звуковой файл песни, то для меня это Похоже, вы могли бы просто добавить больше информации в этот файл с текстом, чтобы создать карту того, когда слова текста поются в песне.

Например, если бы я сделал это с песней Jingle Bells, я мог бы разделить табуляцию файл, содержащий тексты песен, где одна строка — это одно слово, с временем начала и окончания относительно начала песни в миллисекундах.

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

Отредактируйте для объяснения того, как кодировать, отслеживая, как долго играет песня.

Два метода для создания переменной экземпляра с именем, скажем, totalTimeSongHasBeenPlaying

  1. Я не уверен, как вы абстрагировались от воспроизведения ваших звуковых файлов, но скажем, что вы абстрагировали это до класса Sound, тогда у вас может быть три метода: sound.soundStarted, sound.soundStopped, sound.soundRestarted, затем в начале воспроизведения звука вы можете вызовите soundStarted, который мог бы получить System.nanoTime или System.currentTimeMillis, а на soundStopped вы могли бы взять его снова, взять разницу и добавить ее к totalTimeSongHasBeenPlaying, а на soundRestart вы могли бы установить totalTimeSongHasBeenPlaying равным нулю.

  2. Сделайте некоторые математические вычисления относительно положения кадра, в котором звук, который вы воспроизводите в данный момент, зависит от того, сколько кадров в секунду для этого файла. Я не знаю точных библиотек для JLayer, я давно его не использовал, но этот метод также должен сообщить вам, как далеко вы продвинулись в файле.

После этого класс Sound также может иметь такой метод, как currentWordBeingSung(), который просматривает totalTimeSongHasBeenPlaying и использует таблицу поиска, которую вы создали из файла текстов песен во время построения, и однозначно возвращает конкретное слово (могут быть дубликаты). Ваш графический интерфейс, когда вы его создаете, скажем, ваш JLyricsViewer, может содержать экземпляр вашего объекта Sound, и вы можете использовать SwingTimer для перерисовки его каждые 50 мс или около того, где в вашем методе paintComponent он смотрит на currentWordBeingSung().

person NESPowerGlove    schedule 28.04.2014
comment
Это имеет смысл, но как я могу добавить что-то в свою программу во время воспроизведения песни, которая будет проверять, если (миллисекунды> 0 и миллисекунды> 1000), а затем показывать jingle ? - person user3078608; 28.04.2014
comment
Я не уверен, как вы абстрагировались от воспроизведения своих звуковых файлов, но скажем, что вы абстрагировали это от класса Sound, тогда у вас может быть три метода: sound.soundStarted, sound.soundStopped, sound.soundRestarted, затем в начале воспроизведения звука вы можете вызвать soundStarted, который мог бы захватить System.nanoTime или System.currentTimeMillis, а на soundStopped вы могли бы захватить его снова, взять разницу и добавить ее к totalTimeSongHasBeenPlaying, а при soundRestart вы можете установить totalTimeSongHasBeenPlaying в ноль. - person NESPowerGlove; 28.04.2014
comment
Класс Sound также может иметь такой метод, как currentWordBeingSung(), который просматривает totalTimeSongHasBeenPlaying и использует таблицу поиска, которую вы создали на основе файла текстов песен во время создания, и однозначно возвращает конкретное слово (могут быть дубликаты). Ваш графический интерфейс, когда вы его создаете, скажем, ваш JLyricsViewer, может содержать экземпляр вашего объекта Sound, и вы можете использовать SwingTimer для перерисовки его каждые 50 мс или около того, где в вашем методе paintComponent он смотрит на currentWordBeingSung(). - person NESPowerGlove; 28.04.2014
comment
Спасибо за вашу помощь! - person user3078608; 29.04.2014