4

CODE EDITED:

I am developing a dictionary app for Android. I have been succeeding in making the app pronounce each word being looked up. Here is the code:

btnPronounce.setOnClickListener(new View.OnClickListener() {            
        @Override
        public void onClick(View v) {                               
            // TODO Auto-generated method stub
            //Log.i(MAIN_TAG,"Start pronounciation ...");
            btnPronounce.setEnabled(false);
            String currentWord = edWord.getText().toString().toLowerCase();         

            try {
                ZipFile zip = new ZipFile("/sdcard/app_folder/sound/zip_test.zip");
                ZipEntry entry = zip.getEntry(currentWord);
                if (entry != null) {
                    InputStream in = zip.getInputStream(entry);
                    // see Note #3.
                    File tempFile = File.createTempFile("_AUDIO_", ".wav");
                    FileOutputStream out = new FileOutputStream(tempFile);
                    IOUtils.copy(in, out);

                    // do something with tempFile (like play it)
                    File f = tempFile;   
                    try {
                        if (f.exists())
                        {
                            Log.i(MAIN_TAG,"Audio file found!");
                            MediaPlayer mp = new MediaPlayer();

                            mp.prepare();
                            mp.setLooping(false);
                            mp.start();
                            while (mp.getCurrentPosition() < mp.getDuration());
                            mp.stop();
                            mp.release();
                            Log.i(MAIN_TAG,"Pronounciation finished!");
                        }   
                      else
                        {
                            Log.i(MAIN_TAG,"File doesn't exist!!");
                        }
                    }
                    catch (IOException e)
                    {
                        Log.i(MAIN_TAG,e.toString());
                    }
                    btnPronounce.setEnabled(true);  }

                else {
                    // no such entry in the zip
                }
            } catch (IOException e) {
                // handle your exception cases...
                e.printStackTrace();
            }       
     }      

    });

But the problem is that there are too many WAV files in one folder, and all these files are treated as music files by Android devices. As a result, it takes ages to index such files. In addition, indexing and user browsing sometimes force the app to crash.

Therefore, I just wonder if the following could be programmatically done:

  1. Can Android MediaPlayer play WAV/MP3 files zipped or wrapped in a single file? I mean I want to zip or wrap the audio files (or do something alike) so that they appear as one single file to Android devices but MediaPlayer can still play each individual WAV file inside.
  2. If the above is impossible, can you guys suggest a solution to the problem?

EDIT: Are there any other ways/solutions that allow audio files to be simply put into one big file (an image, zip or the like...) and then let MediaPlayer read individual files in it?

Thank you very much.

Niamh Doyle
  • 1,909
  • 7
  • 30
  • 42
  • 3
    Im not sure if the mediaplayer supports streams but if it does you can do this using the ZipInputStream (http://docs.oracle.com/javase/1.4.2/docs/api/java/util/zip/package-summary.html) – sherif Jan 17 '12 at 19:26
  • While this isn't necessarily optimal solution, it shouldn't be a problem to introduce one big mp3/wav file and use position/length to play only part of it. It might be better to use ``android.media.SoundPool`` if you take this approach though. Especially if SoundPool.load(..) method takes file positions as parameters (and not sound position within sample). – harism Jan 17 '12 at 19:34
  • ...is a Text-to-Speech library not an option here? – Chris Cashwell Jan 17 '12 at 19:58
  • Thank you very much for all your comments and suggestions. I want words actually pronounced by humans so a Text-to-Speech library may not be an option. **ZipInputStream** seems to be a solution. – Niamh Doyle Jan 18 '12 at 02:45

2 Answers2

6

You can use a combination of ZipFile or ZipInputStream and java.io file operations to read the necessary data from the zip, create temp files and play those using MediaPlayer.

Alternatively, you could just use a TTS engine and not pass out a 50-bagillion-byte APK.

Edit - Example by request:

try {
    ZipFile zip = new ZipFile("someZipFile.zip");
    ZipEntry entry = zip.getEntry(fileName);
    if (entry != null) {
        InputStream in = zip.getInputStream(entry);
        // see Note #3.
        File tempFile = File.createTempFile("_AUDIO_", ".wav");
        FileOutputStream out = new FileOutputStream(tempFile);
        IOUtils.copy(in, out);
        // do something with tempFile (like play it)
    } else {
        // no such entry in the zip
    }
} catch (IOException e) {
    // handle your exception cases...
    e.printStackTrace();
}

Notes:

  1. I didn't include any safe file handling practices here. That's up to you.

  2. This isn't the way to do it, only a way to do it. There are probably 100 other ways, some of which may be better suited to what you need. I didn't use ZipInputStream simply because there's a little more logic involved and I was going for brevity. You have to check every entry to see if it's what you're looking for with ZipInputStream, whereas ZipFile allows you to just ask for what you want by name. I'm not sure what (if any) performance implications using either over the other would have.

  3. By no means are you required to use temp files (or files at all, really), but Android's MediaPlayer doesn't really like streams, so this is probably the easiest solution.

Chris Cashwell
  • 22,308
  • 13
  • 63
  • 94
  • Thank you very much indeed. I'll try it now as you suggest. – Niamh Doyle Jan 18 '12 at 02:50
  • This is quite new to me. Thus, regarding my code above could you please make an example of using `ZipInputStream` and `java.io` to read audio files in the single zipped file. Thanks a lot. – Niamh Doyle Jan 18 '12 at 02:57
  • Thank you very much, @Chris Cashwell. I tried to applied what you had suggested but it does not pronounce the required word. No error message is shown in Eclipse LogCat. I edited my code to reflect the changes. Can you have a look to see what is wrong there. – Niamh Doyle Jan 18 '12 at 18:17
  • @user998032 Are you getting your output `Log.i(MAIN_TAG,"Audio file found!");`? – Chris Cashwell Jan 18 '12 at 18:33
  • Nope, Chris. I don't get any message. The only difference is the Pronounce button works just once now. – Niamh Doyle Jan 18 '12 at 18:36
  • Add `Log.i(MAIN_TAG,"IOException reading zip file");` to the section where `// handle your exception cases...` is – Chris Cashwell Jan 18 '12 at 18:45
  • @@Chris Cashwell: I guess something's missing here but can't figure it out. – Niamh Doyle Jan 18 '12 at 18:45
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/6829/discussion-between-chris-cashwell-and-user998032) – Chris Cashwell Jan 18 '12 at 18:47
  • "Audio file found!" now. Chris, are you free now? – Niamh Doyle Jan 19 '12 at 14:49
0

An alternative you should consider is to download the individual sound files when the user want to listen to a pronunciation. This should reduce the file size although it does mean that you can't listen to a pronunciation when there is no Internet.

Lie Ryan
  • 62,238
  • 13
  • 100
  • 144