Create FileDescriptor on Android without first opening file

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

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

However, this process first causes ...

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

      

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

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

      

... to read it before calling:

mediaPlayer.setDataSource(fileDescriptor);

      

It seems to me that this is wasteful. Can I create a FileDescriptor directly from byteArray so that the MIDI stream can be played right away?


== 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 on creating a MIDI file on the fly, see kevinboone.net , skytopia and sonicspot

+3


source to share


2 answers


MediaPlayer will play either from a file or from an HTTP URL.

So the trick here is to play with a url that points to the localhost server where you are generating data on the fly, from memory or in any other way.



See my answer here for how to do it: Android ServerSocket Programming with jCIFS Streaming Files

0


source


There is no need to simulate FileDescriptor

.
You can implement your own MediaDataSource and configure it to call MediaPlayer ::. setDataSource (yourMediaDataSource)



0


source







All Articles