某些ogg文件未在Java中播放(可能与大小有关?)

时间:2018-10-19 18:51:32

标签: java arrays audio ogg

我有一个播放音频文件的声音类。但是,某些ogg文件在播放时不起作用。我不确定这是由于文件格式还是文件大小引起的。

文件较小似乎是问题所在,因为可以正常工作的文件大于或等于6.7 kb,而不能工作的文件小于或等于6 kb。

但是,我尝试在具有Audacity功能的oggs之一的末尾添加生成的音调,将文件增加到7.5 kb,但仍然无法正常工作。

这是我用来播放文件的Sound类:

  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.net.URL;
  import java.util.ArrayList;
  import java.util.Arrays;

  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);
   * </pre></blockquote>
   * <p>
   * The class {@code Sound} includes methods for playing audio, stopping audio, changing
   * the volume, getting the duration if a wav, get whether the audio is stopped, get
   * whether the audio is finished, and changing the input file
   *
   */
  public class Sound {
      /**
       * Whether or not the music should be playing in a loop
       */
      private boolean loopable;
      /**
       * Whether or not a URL was given
       */
      private boolean isUrl;

      /**
       * The String name of the file
       */
      private String fileName;

      /**
       * The URL location of the file
       */
      private URL fileUrl;

      /**
       * The volume at which the sound plays at
       */
      private double volume = 1.0;
      /**
       * The duration of the audio file in milliseconds
       */
      private double durationInMilliseconds;

      private ArrayList<PlayingSound> playingSounds = new ArrayList<>();

      /**
       * Initializes a newly created {@code Sound} object given a String file name
       * @param fileName    Path of the file to be played
       * @param loopable    Whether or not the audio should loop
       * @throws UnsupportedAudioFileException    Thrown if the file is not supported
       * @throws IOException  Thrown if there is a problem with the given file
       */
      public Sound(String fileName, boolean loopable) throws UnsupportedAudioFileException, IOException {
          isUrl = false;
          this.fileName = fileName;
          this.loopable = loopable;
          if(fileName.endsWith(".wav")) {
              final File file = new File(fileName);
              AudioInputStream stream = AudioSystem.getAudioInputStream(file);
              AudioFormat format = stream.getFormat();
              long frames = stream.getFrameLength();
              durationInMilliseconds = 1000 * ((double) frames/format.getFrameRate());
          }
      }

      /**
       * Initializes a newly created {@code Sound} object given a File object
       * @param inputFile    File to be played
       * @param loopable     Whether or not the audio should loop
       * @throws UnsupportedAudioFileException    Thrown if the file is not supported
       * @throws IOException  Thrown if there is a problem with the given file
       */
      public Sound(File inputFile, boolean loopable) throws UnsupportedAudioFileException, IOException {
          isUrl = false;
          this.fileName = inputFile.toString();
          this.loopable = loopable;
          if(fileName.endsWith(".wav")) {
              AudioInputStream stream = AudioSystem.getAudioInputStream(inputFile);
              AudioFormat format = stream.getFormat();
              long frames = stream.getFrameLength();
              durationInMilliseconds = 1000 * ((double) frames/format.getFrameRate());
          }
      }

      /**
       * Initializes a newly created {@code Sound} object given a URL object
       * @param url          URL to audio file
       * @param loopable     Whether or not the audio should loop
       * @throws UnsupportedAudioFileException    Thrown if the file is not supported
       * @throws IOException  Thrown if there is a problem with the given file
       */
      public Sound(URL url, boolean loopable) throws UnsupportedAudioFileException, IOException {
          isUrl = true;
          fileUrl = url;
          String urlString = url.toString();
          fileName = urlString.substring(Math.max(urlString.lastIndexOf('\\'), urlString.lastIndexOf('/')) + 1);
          this.loopable = loopable;
          if(fileUrl.getFile().endsWith(".wav")) {
              AudioInputStream stream = AudioSystem.getAudioInputStream(fileUrl);
              AudioFormat format = stream.getFormat();
              long frames = stream.getFrameLength();
              durationInMilliseconds = 1000 * ((double) frames/format.getFrameRate());
          }
      }

      /**
       * Plays the audio from the given source
       */
      public final void play() {
          playingSounds.add(new PlayingSound());
      }

      /**
       * Stops the audio from playing
       */
      public final void stop() {
          for(PlayingSound ps : playingSounds)
              ps.stop();
      }

      /**
       * Changes the volume of the audio
       * @param volume    Volume to change to
       */
      public final void changeVolume(double volume) {
          if(volume > 1 || volume < 0)
              throw new IllegalArgumentException("Error: Volume must be between 0 and 1");
          this.volume = volume;
      }

      /**
       * The AudioFormat to specify the convention to represent the data
       * @param inFormat  The format of the audio file
       * @return          The necessary format information from the inFormat
       */
      private AudioFormat getOutFormat(AudioFormat inFormat) {
          final int ch = inFormat.getChannels();
          final float rate = inFormat.getSampleRate();
          return new AudioFormat(PCM_SIGNED, rate, 16, ch, ch * 2, rate, false);
      }

      /**
       * Gives duration in milliseconds if .wav file
       * @return  Duration in milliseconds if .wav file
       * @throws Exception    Thrown if file is not .wav
       */
      public double getDuration() throws Exception {
          if(!isUrl && fileName.endsWith(".wav") || isUrl && fileUrl.getFile().endsWith(".wav"))
              return durationInMilliseconds;
          throw new Exception("Error: Length can only be determined for .wav files");
      }

      /**
       * Returns whether or not the audio is playing
       * @return Whether or not the audio is playing
       */
      public final boolean isStopped() {
          for(PlayingSound ps : playingSounds)
              if(!ps.isStopped())
                  return false;
          return true;
      }

      /**
       * Returns whether or not the audio has finished playing (has exited loop)
       * @return Whether or not the audio has finished playing (has exited loop)
       */
      public final boolean isFinished() {
          for(PlayingSound ps : playingSounds)
              if(!ps.isFinished())
                  return false;
          return true;
      }

      /**
       * Changes the input location for the audio
       * @param url   The URL to replace the audio source
       * @throws UnsupportedAudioFileException    Thrown if the file is not supported
       * @throws IOException  Thrown if there is a problem with the given file
       */
      public final void changeInput(URL url) throws UnsupportedAudioFileException, IOException {
          isUrl = true;
          fileUrl = url;
          if(fileUrl.getFile().endsWith(".wav")) {
              AudioInputStream stream = AudioSystem.getAudioInputStream(fileUrl);
              AudioFormat format = stream.getFormat();
              long frames = stream.getFrameLength();
              durationInMilliseconds = 1000 * ((double) frames/format.getFrameRate());
          }
      }

      private void removeInternalSound(PlayingSound ps) {
          playingSounds.remove(ps);
      }

      /**
       * Returns the volume the sound is currently set to
       * @return The volume of the audio
       */
      public final double getVolume() {
          return volume;
      }

      @Override
      public String toString() {
          return String.format("String[name: %s, loopable: %b]", fileName, loopable);
      }

      private class PlayingSound {
          private boolean stop = false;
          private boolean finished = false;
          private Thread playingSound;

          PlayingSound() {
              playingSound = new Thread(() -> {
                  do {
                      try {
                          AudioInputStream in;
                          if(!isUrl)
                              in = getAudioInputStream(new File(fileName));
                          else
                              in = getAudioInputStream(fileUrl);
                          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(inputMystream, line);
                                  line.drain();
                                  line.stop();
                              }
                          }
                      }
                      catch(UnsupportedAudioFileException | LineUnavailableException | IOException e) {
                          throw new IllegalStateException(e);
                      }
                  } while(loopable && !stop);
                  finished = true;
                  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(AudioInputStream in, SourceDataLine line) throws IOException {
              byte[] buffer = new byte[4];
              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));
                      audioSample = (short) (audioSample * volume);
                      bufferTemp[i] = (byte) audioSample;
                      bufferTemp[i + 1] = (byte) (audioSample >> 8);
                  }
                  buffer = bufferTemp;
                  line.write(buffer, 0, n);
              }
          }

          void stop() {
              stop = true;
          }

          boolean isStopped() {
              return stop;
          }

          boolean isFinished() {
              return finished;
          }

      }

  }

如果将pathToFile替换为文件的路径,则该类可用于测试上述Sound类:

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

public class Test {

    public static void main(String[] args) throws IOException, UnsupportedAudioFileException, InterruptedException {
        Sound test = new Sound("pathToFile", false);
        test.play();
        Thread.sleep(1000);
    }

}

这是三个可运行的ogg文件:

文件a:

https://dl.dropboxusercontent.com/s/hwgor2xk0ief7ui/workingOne.ogg

文件b:

https://dl.dropboxusercontent.com/s/4n14lxpvmw0ezpd/workingTwo.ogg

文件c:

https://dl.dropboxusercontent.com/s/749zrcglz1jpfow/workingThree.ogg

以下是三个失败的ogg文件:

文件d:

https://dl.dropboxusercontent.com/s/bwsu4ouwu06rfao/failedFile.ogg

文件d加上额外的生成色调,以使大小超出上述工作文件的大小:

https://dl.dropboxusercontent.com/s/t7q4wmh4ljqvz3a/failedFile2.ogg

文件e:

https://dl.dropboxusercontent.com/s/tddn22crdkvwawl/click.ogg

可能需要一些库才能使ogg文件与给定类一起使用。如果没有文件可用,请使用给定程序(可能使用IDE)编译给定zip中的库:

包含的(java jar)库是JLayer 1.0.1,Jogg 0.0.7,Jorbis 0.0.17-1,MP3 SPI 1.9.5,Tritonus-share 0.3.7.4和Ogg Vorbis SPI 1.0.3。 / p>

https://dl.dropboxusercontent.com/s/tqrj5w4vs32a3h8/lib.zip

更新:

我在文件d中添加了很多我之前在文件d中添加的音调(价值30秒),以查看它是否会改变任何东西,并且奏效。

因此,我决定开始剪切音频,直到音频无法播放为止。

奇怪的是,我剪切的长度小于文件d的长度,并且一直有效,直到剪切到一定程度为止。

我们称文件d的短版本为文件f,而文件d的短版本为文件g,而不是文件g。

此外,如果我在执行此操作的软件Audacity中将导出质量设置从10/10更改为5/10,则无法播放。我们称这个文件为h。

以下是每个上述文件:

文件f:

https://dl.dropboxusercontent.com/s/ore4bfgb0va2gw7/fileF.ogg

文件g:

https://dl.dropboxusercontent.com/s/zq000zhlup9hiu1/fileG.ogg

文件h:

https://dl.dropboxusercontent.com/s/4ojj7gv9x92z9mi/fileH.ogg

0 个答案:

没有答案