Generating a FileDescriptor on Android without first opening a file

10,736

It is not necessary to simulate FileDescriptor.
You can implement your own MediaDataSource and set it invoking MediaPlayer::setDataSource(yourMediaDataSource).

Share:
10,736
James Newton
Author by

James Newton

merge keep

Updated on July 06, 2022

Comments

  • James Newton
    James Newton almost 2 years

    In Android, is it possible to generate a FileDescriptor directly from a byte array, without having to open a file first?

    In Android 2.2, I am generating a MIDI file on the fly, and then playing it back using MediaPlayer. I've included the text of the Main.java file that does this successfully below. So far so good.

    However, this process first calls...

    FileOutputStream outputStream = openFileOutput(file, MODE_PRIVATE);
    outputStream.write(byteStream);
    outputStream.close();
    

    ... to write out the file, and then calls...

    FileInputStream inputStream = new FileInputStream(midifile);
    FileDescriptor fileDescriptor = inputStream.getFD();
    

    ... to read it back in, before calling:

    mediaPlayer.setDataSource(fileDescriptor);
    

    This seems to me to be wasteful. Can I create the FileDescriptor directly from the byteArray, so that the MIDI stream can be played immediately?


    == Working code ==

    package com.example.midi;
    
    import java.io.File;
    import java.io.FileDescriptor;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    
    import android.app.Activity;
    import android.media.AudioManager;
    import android.media.MediaPlayer;
    import android.os.Bundle;
    import android.view.View;
    
    public class Main extends Activity {
    
      private String file = "midi.mid";
      private MediaPlayer mediaPlayer;
    
      @Override
      protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mediaPlayer = new MediaPlayer();
        mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
    
        createNewMIDIFile();
        playNewMIDIFile();
      }
    
      public void createNewMIDIFile() {
        Integer[] stream = new Integer[]{
            //
            0x4d, 0x54, 0x68, 0x64, // MThd = MIDI file designator
            0x00, 0x00, 0x00, 0x06, // Standard MIDI File (SMF)
            0x00, 0x01, 0x00, 0x02, // multiple-track format: 2 tracks
            0x00, 0x40, // 64 ticks per beat (quarter note)
            0x4D, 0x54, 0x72, 0x6B, // Header for track 1
            0x00, 0x00, 0x00, 0x0B, // 11  bytes to describe the track
            0x00, 0xFF, 0x51, 0x03, // set tempo:
            0x0F, 0x42, 0x40, //  1,000,000 microseconds / beat: 60 bpm
            0x00, 0xFF, 0x2F, 0x00, // End of track 1
            0x4D, 0x54, 0x72, 0x6B, // Header for track 2
            0x00, 0x00, 0x00, 0x0F, // 15 bytes to describe the track
            0x00, // Immediately
            0xC1, 0x01, // change instrument for track 2 to piano
            0x00, // Immediately
            0x91, 0x3C, 0x7F, // play middle C with a velocity of 127
            0x30, // 48 ticks later (dotted eighth note)
            0x81, 0x3C, 0x00, // stop playing the middle C
            0x00, 0xFF, 0x2F, 0x00 // End of track 2
        };
    
        int length = stream.length;
        byte[] byteStream = new byte[length];
        for (int ii = 0; ii < length; ii++) {
          byteStream[ii] = (byte) (stream[ii] % 256);
        }
    
        try {
          FileOutputStream outputStream = openFileOutput(file, MODE_PRIVATE);
          outputStream.write(byteStream);
          outputStream.close();
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    
      public void play(View view) {
      /* Triggered by a button defined in activity_main.xml as 
      <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="play"
        android:text="Play MIDI" />
      */
        playNewMIDIFile();
      }
    
      public void playNewMIDIFile() {
        try {
          String filename = getFilesDir() + "/" + file;
          File midifile = new File(filename);
          FileInputStream inputStream = new FileInputStream(midifile);
          FileDescriptor fileDescriptor = inputStream.getFD();
          mediaPlayer.reset();
          mediaPlayer.setDataSource(fileDescriptor);
          inputStream.close();
          mediaPlayer.prepare();
          mediaPlayer.start();
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    }
    

    For more information on building a MIDI file on the fly, see kevinboone.net, skytopia and sonicspot