0

I have a separate class in an Android Studio project that analyzes WAV files. I debugged the file originally in Eclipse and now have loaded it into Studio. Unsurprisingly, I'm having trouble reading in a WAV file in my project. First, this is the location of the WAV file in my project:

enter image description here

In my MainActivity.class, I call the function WAVRead:

 WavFile j = new WavFile("test.wav");

Which invokes the following FileInputStream as part of the instantiation:

      try {
        // Create a new file input stream for reading file data

        AssetFileDescriptor fileDescriptor = assetManager.openFd(filename);
        FileInputStream iStream = fileDescriptor.createInputStream();

        // Read the first 12 bytes of the file
        int bytesRead = iStream.read(innerBuffer, 0, 12);

This fails, with a NullPointerException refering to the assetManager.openFd method line.

   Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.AssetFileDescriptor android.content.res.AssetManager.openFd(java.lang.String)' on a null object reference

Part of my problem is I'm not so sure if I'm feeding the project the right path to the WAV file. Yet, in many of the examples I've seen here, just utilizing "test.wav" should feed the assetManager the correct file. Can someone suggest a way to get it to recognize the file?

EDIT: To provide more context, I'm adding the following code that constructs the WAVFile class:

public class WavFile {

private enum IOState {READING, WRITING, CLOSED}
private final static int BUFFER_SIZE = 4096;

private final static int FMT_CHUNK_ID = 0x20746D66;
private final static int DATA_CHUNK_ID = 0x61746164;
private final static int RIFF_CHUNK_ID = 0x46464952;
private final static int RIFF_TYPE_ID = 0x45564157;

private File file;                 // File that will be read from or written to
private IOState ioState;           // Specifies the IO State of the Wav File (used for sanity
                                   // checking)
private int bytesPerSample;        // Number of bytes required to store a single sample
private long numFrames;            // Number of frames within the data section
private FileOutputStream oStream;  // Output stream used for writing data
private FileInputStream iStream;   // Input stream used for reading data
private double floatScale;         // Scaling factor used for int <-> float conversion
private double floatOffset;        // Offset factor used for int <-> float conversion
private boolean wordAlignAdjust;   // Specify if an extra byte at the end of the data chunk is
                                   // required for word alignment

// Wav Header
private int numChannels;           // 2 bytes unsigned, 0x0001 (1) to 0xFFFF (65,535)
private long sampleRate;           // 4 bytes unsigned, 0x00000001 (1) to 0xFFFFFFFF
                                   // (4,294,967,295)
                                   // Although a java int is 4 bytes, it is signed, so need to
                                   // use a long
private int blockAlign;            // 2 bytes unsigned, 0x0001 (1) to 0xFFFF (65,535)
private int validBits;             // 2 bytes unsigned, 0x0002 (2) to 0xFFFF (65,535)

// Buffering
private byte[] innerBuffer;        // Local innerBuffer used for IO
private int bufferPointer;         // Points to the current position in innerBuffer
private int bytesRead;             // Bytes read after last read into innerBuffer
private long frameCounter;         // Current number of frames read or written
private Context context;


/**
 * This constructor should not be called directly.
 */
private WavFile() {
    innerBuffer = new byte[BUFFER_SIZE];
}

/**
 * Constructor for creating a WavFile object to be read from a file.
 * @param filename The filename of the file to be read into this object
 */
public WavFile(String filename, Context context) {
    this();
    this.context=context;
    AssetManager assetManager = this.context.getAssets();

The error on Line 113 that is currently cited in an NPE:

    if(this.file.length()!=chunkSize+8) {
        throw new RuntimeException("Header chunk size (" + chunkSize +
                ") does not match file size (" + this.file.length() + ")");
    }

And finally, how I am calling the method in MainActivity.java (which is also cited in the NPE:

WavFile j = new WavFile("test.wav", MainActivity.this);
wnjl
  • 162
  • 1
  • 10
  • 2
    The asset path and setup are correct. The issue is the null `assetManager`. Did you forget to assign that? I'm not sure how you mean to do that, though, since you're not passing an `AssetManager` in `WavFile`'s constructor call, nor are you passing a `Context`, which is necessary to obtain an `AssetManager`. – Mike M. Sep 18 '20 at 02:58
  • I gotcha. Thank you. To pass a context from the method call in the MainActivity.java file, would I use WavFile j = new WavFile("test.wav", this); ? When doing so, I get a NullPointerException referring to that particular line (no longer the AssetFileDescriptor line). – wnjl Sep 18 '20 at 03:10
  • Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'long java.io.File.length()' on a null object reference at com.example.covid19.WavFile.(WavFile.java:113) at com.example.covid19.MainActivity.onCreate(MainActivity.java:37) – wnjl Sep 18 '20 at 03:22
  • Line 113 in WAV file is: if(this.file.length()!=chunkSize+8) { throw new RuntimeException("Header chunk size (" + chunkSize + ") does not match file size (" + this.file.length() + ")"); } Which I'm unsure how that comes into play at all. Line 37 on MainActivity, however, is: WavFile j = new WavFile("test.wav", MainActivity.this); The constructor and initializers are: public WavFile(String filename, Context context) { this(); this.context=context; AssetManager assetManager = this.context.getAssets(); – wnjl Sep 18 '20 at 03:28
  • Sorry, will do. – wnjl Sep 18 '20 at 03:31
  • I see what happened with 113. I replaced File with InputStream but never removed that reference. I don't think that should affect my code. But I am still perplexed as to why the MainActivity method call is generating an exception. The snippet I posted originally immediately follows the AssetManager instantiation in WAVFile.java. Anyway, thanks for your help, I appreciate you going back and forth, I'm obviously a little in over my head with this. – wnjl Sep 18 '20 at 03:50
  • 1
    OK, if I've found the right source file, I've refactored it up until that current Exception line: https://drive.google.com/file/d/12aftc2DyLp38aBfLminoSpVqaBi6ZtK5/view?usp=sharing. Since you're not dealing with a `File` for input now, we had to adjust that whole constructor around that. Instead of using that `file` field for the length in the `if`, we first use the assets to get an `AssetFileDescriptor`, and then get the file length from that in the `try`. I didn't actually test run that, btw; just edited it. – Mike M. Sep 18 '20 at 04:06
  • Wow, thank you so much. I will test it shortly. – wnjl Sep 18 '20 at 04:15
  • It worked!! Bless your heart. Do you have a Venmo? I would like to send you something for taking the time to do this. (This is for a research project that took me an eternity just to find a working solution to properly read in WAV files, and I was deathly afraid that this class was not Android compatible and I'd be back to square one again...) – wnjl Sep 18 '20 at 05:15
  • 1
    Excellent! No need for payment, however. :-) It was nothing major; just a little rewiring. Thank you, though. I do really appreciate the offer. Glad it's working for you. Good luck on your project. Cheers! – Mike M. Sep 18 '20 at 05:22

0 Answers0