Skip to content

Commit

Permalink
media: Rework custom midi implementation
Browse files Browse the repository at this point in the history
Now it only sets up the midi soundfont and synth a single time
inside Manager, with PlatformPlayer then re-using it on any
loaded midi streams. This should vastly reduce memory usage and
improve performance on jars that use a myriad of different midi.
  • Loading branch information
AShiningRay committed Oct 16, 2024
1 parent c073628 commit d050f7c
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 92 deletions.
52 changes: 52 additions & 0 deletions src/javax/microedition/media/Manager.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,32 @@
import java.io.InputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.OutputStream;
import java.security.MessageDigest;
import java.util.HashMap;
import java.util.Map;

import javax.sound.midi.MidiSystem;
import javax.sound.midi.Soundbank;
import javax.sound.midi.Synthesizer;

import org.recompile.mobile.Mobile;
import org.recompile.mobile.PlatformPlayer;

public final class Manager
{
public static final String TONE_DEVICE_LOCATOR = "device://tone";

/* Custom MIDI variables */
public static boolean useCustomMidi = false;
public static boolean hasLoadedCustomMidi = false;
public static File soundfontDir = new File("freej2me_system" + File.separatorChar + "customMIDI" + File.separatorChar);
private static Soundbank customSoundfont;
public static Synthesizer customSynth;


/* Default max amount of players in FreeJ2ME's config */
public static PlatformPlayer mediaPlayers[] = new PlatformPlayer[32];
public static byte mediaPlayersIndex = 0;
Expand All @@ -45,6 +58,8 @@ public final class Manager

public static Player createPlayer(InputStream stream, String type) throws IOException, MediaException
{
checkCustomMidi();

stream.mark(1024);
String streamMD5 = generateMD5Hash(stream, 1024);
stream.reset();
Expand Down Expand Up @@ -130,6 +145,7 @@ else if(mediaPlayersIndex == mediaPlayers.length-1)

public static Player createPlayer(String locator) throws MediaException
{
checkCustomMidi();
System.out.println("Create Player "+locator);
return new PlatformPlayer(locator);
}
Expand Down Expand Up @@ -176,4 +192,40 @@ private static String generateMD5Hash(InputStream stream, int byteCount)

return null;
}

private static final void checkCustomMidi()
{
/*
* Check if the user wants to run a custom MIDI soundfont. Also, there's no harm
* in checking if the directory exists again.
*/
if(!useCustomMidi || hasLoadedCustomMidi) { return; }

/* Get the first sf2 soundfont in the directory */
String[] fontfile = soundfontDir.list(new FilenameFilter()
{
@Override
public boolean accept(File f, String soundfont ) { return soundfont.toLowerCase().endsWith(".sf2"); }
});

/*
* Only really set the player to use a custom midi soundfont if there is
* at least one inside the directory.
*/
if(fontfile != null && fontfile.length > 0)
{
try
{
// Load the first .sf2 font available, if there's none that's valid, don't set any and use JVM's default
customSoundfont = MidiSystem.getSoundbank(new File(soundfontDir, fontfile[0]));
customSynth = MidiSystem.getSynthesizer();
customSynth.open();
customSynth.loadAllInstruments(customSoundfont);

hasLoadedCustomMidi = true; // We have now loaded the custom midi soundfont, mark as such so we don't waste time entering here again
}
catch (Exception e) { System.out.println("Manager -> Could not load soundfont: " + e.getMessage());}
}
else { System.out.println("PlatformPlayer: Custom MIDI enabled but there's no soundfont in" + (soundfontDir.getPath() + File.separatorChar)); }
}
}
12 changes: 7 additions & 5 deletions src/org/recompile/freej2me/Anbu.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
import java.io.OutputStream;
import java.lang.ProcessBuilder;

import javax.microedition.media.Manager;

public class Anbu
{

Expand Down Expand Up @@ -78,10 +80,10 @@ public Anbu(String args[])
*/
try
{
if(!PlatformPlayer.soundfontDir.isDirectory())
if(!Manager.soundfontDir.isDirectory())
{
PlatformPlayer.soundfontDir.mkdirs();
File dummyFile = new File(PlatformPlayer.soundfontDir.getPath() + File.separatorChar + "Put your sf2 bank here");
Manager.soundfontDir.mkdirs();
File dummyFile = new File(Manager.soundfontDir.getPath() + File.separatorChar + "Put your sf2 bank here");
dummyFile.createNewFile();
}
}
Expand Down Expand Up @@ -419,8 +421,8 @@ void settingsChanged()
if(rotate.equals("off")) { rotateDisplay = false; }

String midiSoundfont = config.settings.get("soundfont");
if(midiSoundfont.equals("Custom")) { PlatformPlayer.customMidi = true; }
else if(midiSoundfont.equals("Default")) { PlatformPlayer.customMidi = false; }
if(midiSoundfont.equals("Custom")) { Manager.useCustomMidi = true; }
else if(midiSoundfont.equals("Default")) { Manager.useCustomMidi = false; }

if (Mobile.nokia) { System.setProperty("microedition.platform", "Nokia6233/05.10"); }
else if (Mobile.sonyEricsson)
Expand Down
10 changes: 5 additions & 5 deletions src/org/recompile/freej2me/FreeJ2ME.java
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,10 @@ public void windowClosing(WindowEvent e)
*/
try
{
if(!PlatformPlayer.soundfontDir.isDirectory())
if(!Manager.soundfontDir.isDirectory())
{
PlatformPlayer.soundfontDir.mkdirs();
File dummyFile = new File(PlatformPlayer.soundfontDir.getPath() + File.separatorChar + "Put your sf2 bank here");
Manager.soundfontDir.mkdirs();
File dummyFile = new File(Manager.soundfontDir.getPath() + File.separatorChar + "Put your sf2 bank here");
dummyFile.createNewFile();
}
}
Expand Down Expand Up @@ -410,8 +410,8 @@ private void settingsChanged()
if(rotate.equals("off")) { rotateDisplay = false; }

String midiSoundfont = config.settings.get("soundfont");
if(midiSoundfont.equals("Custom")) { PlatformPlayer.customMidi = true; }
else if(midiSoundfont.equals("Default")) { PlatformPlayer.customMidi = false; }
if(midiSoundfont.equals("Custom")) { Manager.useCustomMidi = true; }
else if(midiSoundfont.equals("Default")) { Manager.useCustomMidi = false; }

if(config.settings.get("halveCanvasRes").equals("on")) { w /= 2; h /= 2; }

Expand Down
65 changes: 32 additions & 33 deletions src/org/recompile/freej2me/Libretro.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,17 @@
import java.awt.Canvas;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferByte;

import java.util.Timer;
import java.util.TimerTask;

import javax.microedition.midlet.MIDlet;

import java.io.File;
import java.io.IOException;
import java.net.URL;

import javax.microedition.media.Manager;
import javax.microedition.midlet.MIDlet;

public class Libretro
{
Expand Down Expand Up @@ -65,7 +64,7 @@ public class Libretro
private boolean[] pressedKeys = new boolean[128];

private byte[] frameBuffer = new byte[800*800*3];
private byte[] RGBframeBuffer = new byte[800*800*3];
private byte[] RGBframeBuffer = new byte[800*800*3];
private byte[] frameHeader = new byte[]{(byte)0xFE, 0, 0, 0, 0, 0};

private int mousex;
Expand Down Expand Up @@ -103,10 +102,10 @@ public Libretro(String args[])
*/
try
{
if(!PlatformPlayer.soundfontDir.isDirectory())
if(!Manager.soundfontDir.isDirectory())
{
PlatformPlayer.soundfontDir.mkdirs();
File dummyFile = new File(PlatformPlayer.soundfontDir.getPath() + File.separatorChar + "Put your sf2 bank here");
Manager.soundfontDir.mkdirs();
File dummyFile = new File(Manager.soundfontDir.getPath() + File.separatorChar + "Put your sf2 bank here");
dummyFile.createNewFile();
}
}
Expand Down Expand Up @@ -135,7 +134,7 @@ public Libretro(String args[])

if(Integer.parseInt(args[6]) == 0) { soundEnabled = false; }

if(Integer.parseInt(args[7]) == 1) { PlatformPlayer.customMidi = true; }
if(Integer.parseInt(args[7]) == 1) { Manager.useCustomMidi = true; }

maxmidistreams = Integer.parseInt(args[8]);
Manager.updatePlayerNum((byte) maxmidistreams);
Expand All @@ -145,7 +144,7 @@ public Libretro(String args[])

/* Once it finishes parsing all arguments, it's time to set up freej2me-lr */

surface = new BufferedImage(lcdWidth, lcdHeight, BufferedImage.TYPE_3BYTE_BGR); // libretro display
surface = new BufferedImage(lcdWidth, lcdHeight, BufferedImage.TYPE_3BYTE_BGR); // libretro display
gc = (Graphics2D)surface.getGraphics();

Mobile.setPlatform(new MobilePlatform(lcdWidth, lcdHeight));
Expand Down Expand Up @@ -328,7 +327,7 @@ public void run()

config.settings.put("fps", ""+limitFPS);

if(!PlatformPlayer.customMidi) { config.settings.put("soundfont", "Default"); }
if(!Manager.useCustomMidi) { config.settings.put("soundfont", "Default"); }
else { config.settings.put("soundfont", "Custom"); }

config.settings.put("maxmidistreams", ""+maxmidistreams);
Expand Down Expand Up @@ -413,37 +412,37 @@ public void run()
break;

case 15:
/* Send Frame to Libretro */
/* Send Frame to Libretro */
try
{
frameBuffer = ((DataBufferByte) surface.getRaster().getDataBuffer()).getData();

final int bufferLength = frameBuffer.length;

/*
* Convert BGR into RGB. Has a negligible performance impact compared to not doing this at all
* and sending the BGR array straight to libretro... and is faster than using getRGB().
*
* Copying from the original BGR array to a separate RGB array uses a bit more memory, but
* works correctly compared to just swapping the channels on the orignal array, where they
* still unknowingly end up incorrect from time to time. Runtime performance is pretty much
* the same for both methods.
*/
for(int i=0; i<bufferLength; i+=3)
frameBuffer = ((DataBufferByte) surface.getRaster().getDataBuffer()).getData();

final int bufferLength = frameBuffer.length;

/*
* Convert BGR into RGB. Has a negligible performance impact compared to not doing this at all
* and sending the BGR array straight to libretro... and is faster than using getRGB().
*
* Copying from the original BGR array to a separate RGB array uses a bit more memory, but
* works correctly compared to just swapping the channels on the orignal array, where they
* still unknowingly end up incorrect from time to time. Runtime performance is pretty much
* the same for both methods.
*/
for(int i=0; i<bufferLength; i+=3)
{
RGBframeBuffer[i] = frameBuffer[i+2]; // [R]GB = BG[R]
RGBframeBuffer[i+1] = frameBuffer[i+1];
RGBframeBuffer[i+2] = frameBuffer[i]; // RG[B] = [B]GR
RGBframeBuffer[i] = frameBuffer[i+2]; // [R]GB = BG[R]
RGBframeBuffer[i+1] = frameBuffer[i+1];
RGBframeBuffer[i+2] = frameBuffer[i]; // RG[B] = [B]GR
}


//frameHeader[0] = (byte)0xFE;
frameHeader[1] = (byte)((lcdWidth>>8)&0xFF);
frameHeader[2] = (byte)((lcdWidth)&0xFF);
frameHeader[3] = (byte)((lcdHeight>>8)&0xFF);
frameHeader[4] = (byte)((lcdHeight)&0xFF);

System.out.write(frameHeader, 0, 6);
System.out.write(RGBframeBuffer, 0, bufferLength);
System.out.write(RGBframeBuffer, 0, bufferLength);
System.out.flush();
}
catch (Exception e)
Expand Down Expand Up @@ -492,8 +491,8 @@ private void settingsChanged()
if(rotate.equals("off")) { rotateDisplay = false; frameHeader[5] = (byte)0; }

String midiSoundfont = config.settings.get("soundfont");
if(midiSoundfont.equals("Custom")) { PlatformPlayer.customMidi = true; }
else if(midiSoundfont.equals("Default")) { PlatformPlayer.customMidi = false; }
if(midiSoundfont.equals("Custom")) { Manager.useCustomMidi = true; }
else if(midiSoundfont.equals("Default")) { Manager.useCustomMidi = false; }

halveCanvasRes = false;
if(config.settings.get("halveCanvasRes").equals("on"))
Expand All @@ -508,7 +507,7 @@ private void settingsChanged()
lcdWidth = w;
lcdHeight = h;
Mobile.getPlatform().resizeLCD(w, h);
surface = new BufferedImage(lcdWidth, lcdHeight, BufferedImage.TYPE_3BYTE_BGR); // libretro display
surface = new BufferedImage(lcdWidth, lcdHeight, BufferedImage.TYPE_3BYTE_BGR); // libretro display
gc = (Graphics2D)surface.getGraphics();
}

Expand Down
Loading

0 comments on commit d050f7c

Please sign in to comment.