Java-Gaming.org Hi !
Featured games (91)
games approved by the League of Dukes
Games in Showcase (804)
Games in Android Showcase (237)
games submitted by our members
Games in WIP (867)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  [SOLVED] LibGDX Loading Audio File  (Read 10444 times)
0 Members and 1 Guest are viewing this topic.
Offline Tekkerue

Senior Devvie


Medals: 7
Projects: 1



« Posted 2014-10-05 22:10:14 »

Hi all,

I’m trying to load an audio file and then get the audio data as an array using LibGDX, but it is not able to load the audio file. I’m currently using a wav file (I’d like to be able to use mp3’s as well) which is located in the Android assets folder where I have other files for creating text, buttons, etc. and these all work, so it is only the wav file that isn’t loading.

The wav file format is PCM, 44.1kHz, 16bit, mono, little endian.

Here is all the code I have added so far to see if it would pass the wav file to the AudioInputStream without crashing:

1  
2  
3  
4  
5  
6  
7  
try {
   FileHandle fileHandle = Gdx.files.internal("click.wav");        
   InputStream inputStream = fileHandle.read();
   AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(inputStream);
}
catch (UnsupportedAudioFileException e) { e.printStackTrace(); }
catch (IOException e) { e.printStackTrace(); }


I’ve debugged the program and after the line that should create the FileHandle, the handle’s status is “null”. The Gdx.files.internal() method is what I used to load my files for the graphics and they are working.

When I run the program it crashes on the line:
1  
AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(inputStream);


Here is the error message I get:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
java.io.IOException: mark/reset not supported
   at java.io.InputStream.reset(Unknown Source)
   at com.sun.media.sound.SoftMidiAudioFileReader.getAudioInputStream(Unknown Source)
   at javax.sound.sampled.AudioSystem.getAudioInputStream(Unknown Source)
   at com.tekker.audioanimation.SoundFile.readAudioFile(SoundFile.java:61)
   at com.tekker.audioanimation.SoundFile.<init>(SoundFile.java:33)
   at com.tekker.audioanimation.Event.<init>(Event.java:30)
   at com.tekker.audioanimation.AudioAnimation.initArrays(AudioAnimation.java:82)
   at com.tekker.audioanimation.AudioAnimation.create(AudioAnimation.java:67)
   at com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:136)
   at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:114)


Any ideas what I'm doing wrong? Thanks!
Offline kingroka123
« Reply #1 - Posted 2014-10-05 23:47:13 »

I got a sound to play like this:
1  
2  
Sound sound = Gdx.audio.newSound(Gdx.files
            .internal("res/Sound/ButtonClick.wav"));


Then played it using:
1  
sound.play();
Offline Tekkerue

Senior Devvie


Medals: 7
Projects: 1



« Reply #2 - Posted 2014-10-06 00:19:06 »

Hi kingroka123, thanks for the response.

That method works and it plays the sound file, so the Gdx.files.internal("click.wav") method is indeed working. I thought maybe that was the problem since the handle's status was "null" when I debugged and stepped through the program.

For my program I do need to be able to access the audio data from the wav/mp3 file and store the data in an array. I've looked at the LibGDX audio API but didn't see a way to load an audio file from disk and access the data directly. Currently my program generates its own sounds internally (just simple sine wave tones for testing) and stores them in double[]'s, so now I'm trying to load a file from disk and get it in the same format.

I know I can do that with Java's AudioInputStream, but it doesn't seem to work using the LibGDX file handle. Any ideas?

Thanks again!
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline philfrei
« Reply #3 - Posted 2014-10-06 19:04:02 »

Just bypass the InputStream step. The InputStream imposes the markability test on the file, and audio files often (usually?) fail this test.

There are two other ways to make an AudioInputStream, using either a File or a URL as the input parameter instead of the InputStream. Neither one of these subjects the audio file to the markability test.

Details can be found at the API for AudioSystem.getAudioInputStream.

A lot of us have run into this very problem, but fortunately the fix is simple.

music and music apps: http://adonax.com
Offline Tekkerue

Senior Devvie


Medals: 7
Projects: 1



« Reply #4 - Posted 2014-10-07 00:29:09 »

Thanks philfrei, bypassing the InputStream and getting a File from the LibGDX FileHandle did the trick. Smiley

One last problem I'm having now is when the file plays it just plays a blast of white noise, so I think I'm converting the data from the wav file incorrectly.

The AudioInputStream reads bytes from file and I'm trying to store that into an array of doubles. To do the conversion, I'm storing two bytes into a ByteBuffer and then getting a short back out since a short is 2 bytes, and then I'm casting that to a double to put into the array...it seems like this should work, but maybe this is the wrong way to convert it?

I've also tried reversing the order of putting the bytes into the ByteBuffer (in case I had them backwards), but no change.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
   private void readAudioFile(){
      FileHandle fileHandle = Gdx.files.internal("click.wav");        
      File file = fileHandle.file();
      int byteLength = (int)fileHandle.length();
     
      byte[] audioFileBytes = new byte[byteLength];
      audioFile = new double[(byteLength/2)];
     
      try {
         audioInputStream = AudioSystem.getAudioInputStream(file);
         audioInputStream.read(audioFileBytes);
      } catch (UnsupportedAudioFileException e) { e.printStackTrace(); }
        catch (IOException e) { e.printStackTrace(); }
     
      int j=0;
      for (int i=0; i<audioFileBytes.length;){
         audioFile[j++] = bytesToDouble(audioFileBytes[i++], audioFileBytes[i++]);
      }
   }
   
   public double bytesToDouble(byte firstByte, byte secondByte){
      ByteBuffer bb = ByteBuffer.allocate(2);
      bb.order(ByteOrder.LITTLE_ENDIAN);
      bb.put(firstByte);
      bb.put(secondByte);
      return (double)bb.getShort(0);
   }
Offline BurntPizza

« JGO Bitwise Duke »


Medals: 486
Exp: 7 years



« Reply #5 - Posted 2014-10-07 00:44:38 »

Might want to normalize those shorts Tongue

short[] audio; // amplitude range: [32767, -32768]
double[] audio; // amplitude range: [1, -1]
Offline Tekkerue

Senior Devvie


Medals: 7
Projects: 1



« Reply #6 - Posted 2014-10-07 00:59:15 »

Thanks BurntPizza, that was it! Smiley Divided by Short.MAX_VALUE and it is working perfectly now!

Problem officially solved! Thanks everyone, you all are beyond amazing!! Smiley
Offline BurntPizza

« JGO Bitwise Duke »


Medals: 486
Exp: 7 years



« Reply #7 - Posted 2014-10-07 01:02:29 »

Just a nitpick:

1  
ShortBuffer shorts = ByteBuffer.wrap(data).asShortBuffer();


More idiomatic (and efficient, no allocations!), as long as endianness is correct.
Offline Tekkerue

Senior Devvie


Medals: 7
Projects: 1



« Reply #8 - Posted 2014-10-07 01:14:50 »

Niiiiice that is slick! Smiley Thanks BurntPizza, I will give that a go.

Also, it looks like ByteBuffer also has asDoubleBuffer(), so I may even be able to go directly from the byte buffer to the double buffer and bypass the shorts all together:

ByteBuffer.wrap(data).asDoubleBuffer();
Offline BurntPizza

« JGO Bitwise Duke »


Medals: 486
Exp: 7 years



« Reply #9 - Posted 2014-10-07 01:24:47 »

Nope, sorry, asDoubleBuffer() knows nothing about audio:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
ByteBuffer bb = ByteBuffer.wrap(new byte[] {48,-46,56,2,67,33,50,50});
DoubleBuffer db = bb.asDoubleBuffer();
double[] da = new double[db.limit()];
db.get(da);
     
System.out.println(Arrays.toString(da));
     
ShortBuffer sb = bb.asShortBuffer();
double[] da2 = new double[sb.limit()]; // 16-bit mono
for(int i=0;i<da2.length;i++)
   da2[i] = sb.get() / (double)Short.MAX_VALUE;
     
System.out.println(Arrays.toString(da2));


Quote
[1.611166658288239E-73]
[0.3814203314310129, 0.43757438886684774, 0.5244605853450117, 0.39216284676656393]
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Tekkerue

Senior Devvie


Medals: 7
Projects: 1



« Reply #10 - Posted 2014-10-07 02:04:48 »

Oh wow...that's interesting. Thanks for the heads up BurntPizza, I definitely won't be using asDoubleBuffer() then. Wink
Offline Tekkerue

Senior Devvie


Medals: 7
Projects: 1



« Reply #11 - Posted 2014-10-07 07:22:55 »

Well....after having it work so fantastically on my desktop I tried running it on my Android phone and it crashed and burned!

After some debugging and then some googling I found that Android does not support Java's AudioInputStream! Grrrrrr! That sucks! Huh

I didn't see any kind of LibGDX equivalent to AudioInputStream, so am I going to have to code this separately for each device (android, iOS, blackberry, ect) using native code or is there something else I can do? Thanks!
Offline BurntPizza

« JGO Bitwise Duke »


Medals: 486
Exp: 7 years



« Reply #12 - Posted 2014-10-07 23:47:29 »

musicg is advertised as Android-compatible and can read WAVs: https://code.google.com/p/musicg/

Just a quick google of "java wav decoder" or similar.
Maybe include "android" to be sure.
Offline Tekkerue

Senior Devvie


Medals: 7
Projects: 1



« Reply #13 - Posted 2014-10-09 07:33:24 »

Thanks BurntPizza!

I'm also hoping to support iOS devices (assuming the LibGDX conversion process works well), so am I safe in assuming that a 3rd party library like musicg wouldn't be able to be converted to iOS via LibGDX?

If so, then would it be a good idea to just read the bytes straight from the wav file (since wav files aren't compressed) using a byte reader for files that android also supports (have to look more into this as apparently android doesn't support java.nio.Files either....go figure! Roll Eyes)? This gives a good description of the layout inside the wav file:
https://ccrma.stanford.edu/courses/422/projects/WaveFormat/
Offline Tekkerue

Senior Devvie


Medals: 7
Projects: 1



« Reply #14 - Posted 2014-10-10 16:04:13 »

Just a quick update: I was able to read in all the bytes from the wav file with the LibGDX FileHandle and then maneuver through the header bytes to extract just the audio bytes (using the document from standford I posted before). It works perfectly on both desktop and android, so I can now officially mark this problem solved!

Thanks again for all the help everyone! Smiley
Pages: [1]
  ignore  |  Print  
 
 

 
Riven (463 views)
2019-09-04 15:33:17

hadezbladez (5319 views)
2018-11-16 13:46:03

hadezbladez (2247 views)
2018-11-16 13:41:33

hadezbladez (5595 views)
2018-11-16 13:35:35

hadezbladez (1164 views)
2018-11-16 13:32:03

EgonOlsen (4600 views)
2018-06-10 19:43:48

EgonOlsen (5474 views)
2018-06-10 19:43:44

EgonOlsen (3138 views)
2018-06-10 19:43:20

DesertCoockie (4033 views)
2018-05-13 18:23:11

nelsongames (4782 views)
2018-04-24 18:15:36
A NON-ideal modular configuration for Eclipse with JavaFX
by philfrei
2019-12-19 19:35:12

Java Gaming Resources
by philfrei
2019-05-14 16:15:13

Deployment and Packaging
by philfrei
2019-05-08 15:15:36

Deployment and Packaging
by philfrei
2019-05-08 15:13:34

Deployment and Packaging
by philfrei
2019-02-17 20:25:53

Deployment and Packaging
by mudlee
2018-08-22 18:09:50

Java Gaming Resources
by gouessej
2018-08-22 08:19:41

Deployment and Packaging
by gouessej
2018-08-22 08:04:08
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!