Сделайте аудио цикл быстрее - PullRequest
0 голосов
/ 05 июля 2019

Проще говоря, я использую файлы .ogg в своем приложении, и есть несколько фоновых звуковых дорожек, которые нужно зациклить.

Тем не менее, я пытаюсь зациклить аудиофайлы просто перезагружая аудиофайлы и воспроизводя их снова. Этот подход создает задержку между каждой игрой цикла, которая не подходит для плавного опыта, ожидаемого для игры.

Есть ли способ, которым мне не нужно каждый раз перезагружать файлы? Я открыт для хранения аудиофайлов в памяти, если это необходимо.

Вот мой класс Sound с ограниченными функциональными возможностями, чтобы получить суть проблемы:

<code>import static javax.sound.sampled.AudioFormat.Encoding.PCM_SIGNED;
import static javax.sound.sampled.AudioSystem.getAudioInputStream;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine.Info;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.UnsupportedAudioFileException;

/**
 * The {@code Sound} class plays audio from a wav, ogg, or mp3 file with wav working the best in a new thread
 * <p>
 * Here are some examples of how the {@code Sound} object can be initialized:
 * <blockquote><pre>
 *     Sound soundOne = new Sound("pathToFile/music.wav", true);
 *     Sound soundTwo = new Sound(new File("pathToFile/music.wav"), true);
 *     Sound soundThree = new Sound(ClassName.class.getResource(pathToFile/music.wav), true);
 * 
*

* Класс {@code Sound} включает в себя методы для воспроизведения аудио, остановки звука, изменения громкости, получения продолжительности, если WAV, получить ли * звук остановлен, узнать, закончен ли звук, и изменить входной файл * * @author Джиджи Байт 2 * / общественный класс Sound { / ** * Должна ли музыка воспроизводиться в цикле * / приватный логический loopable; / ** * Строковое имя файла * / private String fileName; / ** * Список экземпляров этого звука * / private ArrayList playingSounds = new ArrayList <> (); / ** * Инициализирует вновь созданный объект {@code Sound} с именем файла String. * * @param fileName Путь файла для воспроизведения * @param loopable Должен ли звук зацикливаться * / public Sound (строковое имя файла, логический цикл) { this.fileName = fileName; this.loopable = loopable; } / ** * Воспроизведение аудио с указанного источника * / публичный финал void play () { playingSounds.add (new PlayingSound ()); } / ** * Останавливает воспроизведение звука * / public final void stop () { для (PlayingSound PS: PlayingSounds) ps.stop (); } / ** * AudioFormat для указания соглашения для представления данных * * @param inFormat Формат аудио файла * @return Необходимый формат информации из inFormat * / закрытый AudioFormat getOutFormat (Аудиоформат inFormat) { final int ch = inFormat.getChannels (); конечная скорость с плавающей запятой = inFormat.getSampleRate (); вернуть новый AudioFormat (PCM_SIGNED, rate, 16, ch, ch * 2, rate, false); } / ** * Удаляет объект {@code PlayingSound} из {@code ArrayList} воспроизводимых аудиоклипов. * * @param ps Экземпляр {@code PlayingSound} для удаления * / private void removeInternalSound (PlayingSound ps) { playingSounds.remove (пс); } / ** * Класс {@code PlayingSound} воспроизводит аудиофайл и позволяет воспроизводить и останавливать несколько файлов. * / закрытый класс PlayingSound { приватная логическая остановка = ложь; PlayingSound () { Темы playingSound = новая тема (() -> { делать { пытаться { AudioInputStream in; in = getAudioInputStream (new File (fileName)); окончательный AudioFormat outFormat = getOutFormat (in.getFormat ()); окончательная информация info = новая информация (SourceDataLine.class, outFormat); try (final SourceDataLine line = (SourceDataLine) AudioSystem.getLine (info)) { if (line! = null) { line.open (outFormat); line.start (); AudioInputStream inputMystream = AudioSystem.getAudioInputStream (outFormat, in); поток (inputMystream, строка); line.drain (); line.stop (); } } } catch (UnsupportedAudioFileException | LineUnavailableException | IOException e) {бросить новое IllegalStateException (e); } } while (loopable &&! stop); removeInternalSound (это); }); playingSound.start (); } / ** * Потоковое аудио на микшер * * @param в поток ввода в аудио файл * @param line Где аудио данные могут быть записаны в * @throws IOException Брошенный, если у данного файла есть какие-либо проблемы * / закрытый поток void (в AudioInputStream, строка SourceDataLine) выдает IOException { byte [] buffer = new byte [32]; for (int n = 0; n! = -1 &&! stop; n = in.read (буфер, 0, buffer.length)) { byte [] bufferTemp = new byte [buffer.length]; for (int i = 0; i > 8); } buffer = bufferTemp; line.write (буфер, 0, n); } } void stop () { стоп = правда; } } }

Следующие библиотеки могут быть необходимы для воспроизведения файлов определенных типов и должны быть скомпилированы с указанным файлом: (ссылка)

Для будущих читателей, если срок действия вышеуказанной ссылки истекает, используются следующие библиотеки:

  • jl1.0.1.jar
  • jogg-0.0.7.jar
  • jorbis-0.0.17-1.jar
  • mp3spi1.9.5.jar
  • vorbisspi1.0.3.jar

Используя этот класс Sound и этот файл ogg (Копье Правосудия из Undertale), вот простой класс, который показывает проблему:

import javax.sound.sampled.UnsupportedAudioFileException;
import java.io.IOException;

public class Test {

    public static void main(String[] args) throws IOException, UnsupportedAudioFileException, InterruptedException {
        //Replace the path with the path to the downloaded soj.ogg file or another test file
        Sound spearOfJustice = new Sound("C:\\Users\\gigibayte\\Desktop\\soj.ogg", true);
        spearOfJustice.play();

        //Ensure that this is greater than or equal than the length of the audio file chosen above in seconds.
        int songSeconds = 240;

        //Song is played twice to show looping issue
        Thread.sleep(songSeconds * 2 * 1000);
    }

}

1 Ответ

0 голосов
/ 07 июля 2019

На самом деле, решение оказалось намного проще, чем я предполагал.Я просто переместил цикл do-while в метод stream и изменил его соответствующим образом.

        PlayingSound() {
            Thread playingSound = new Thread(() -> {

                //REMOVED THE DO WHILE LOOP HERE
                try {
                    AudioInputStream in;
                    in = getAudioInputStream(new File(fileName));
                    final AudioFormat outFormat = getOutFormat(in.getFormat());
                    final Info info = new Info(SourceDataLine.class, outFormat);
                    try(final SourceDataLine line = (SourceDataLine) AudioSystem.getLine(info)) {
                        if(line != null) {
                            line.open(outFormat);
                            line.start();
                            AudioInputStream inputMystream = AudioSystem.getAudioInputStream(outFormat, in);
                            stream(outFormat, inputMystream, line);
                            line.drain();
                            line.stop();
                        }
                    }
                }
                catch(UnsupportedAudioFileException | LineUnavailableException | IOException e) {
                    throw new IllegalStateException(e);
                }
                finally {
                    removeInternalSound(this);
                }
            });
            playingSound.start();
        }

        /**
         * Streams the audio to the mixer
         *
         * @param in   Input stream to audio file
         * @param line Where the audio data can be written to
         * @throws IOException Thrown if given file has any problems
         */
        private void stream(AudioFormat outFormat, AudioInputStream in, SourceDataLine line) throws IOException {
            byte[] buffer = new byte[32];
            do {
                for(int n = 0; n != -1 && !stop; n = in.read(buffer, 0, buffer.length)) {
                    byte[] bufferTemp = new byte[buffer.length];
                    for(int i = 0; i < bufferTemp.length; i += 2) {
                        short audioSample = (short) ((short) ((buffer[i + 1] & 0xff) << 8) | (buffer[i] & 0xff));
                        bufferTemp[i] = (byte) audioSample;
                        bufferTemp[i + 1] = (byte) (audioSample >> 8);
                    }
                    buffer = bufferTemp;
                    line.write(buffer, 0, n);
                }
                in = getAudioInputStream(new File(fileName));
                in = AudioSystem.getAudioInputStream(outFormat, in);
            } while(loopable && !stop);
        }
...