/*
* Copyright (C) 2013-2017 たんらる
*/
package fourthline.mabiicco.midi;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import javax.sound.midi.Instrument;
import javax.sound.midi.InvalidMidiDataException;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.Soundbank;
import com.sun.media.sound.DLSInstrument;
import com.sun.media.sound.DLSRegion;
import fourthline.mabiicco.MabiIccoProperties;
import fourthline.mmlTools.core.ResourceLoader;
import fourthline.mmlTools.parser.MMLEventParser;
/**
* 楽器に関する情報を扱います. (instrument.propertiesに対応)
*/
public final class InstClass {
private final String name;
private final int bank;
private final int program;
private final int lowerNote;
private final int upperNote;
private final InstType type;
private final Instrument inst;
private static final String RESOURCE_NAME = "instrument";
private static final ResourceBundle instResource = ResourceBundle.getBundle(RESOURCE_NAME, new ResourceLoader());
public static boolean debug = false;
public InstClass(String name, int bank, int program, Instrument inst) {
String str[] = name.split(",");
this.name = str[0];
this.inst = inst;
if (str.length > 1) {
this.type = InstType.getInstType(str[1]);
} else {
this.type = InstType.NORMAL;
}
KeyRegion region = regionFromTo(inst);
if (str.length > 2) {
region.from = Math.max(region.from, MMLEventParser.firstNoteNumber(str[2]));
}
if (str.length > 3) {
region.to = Math.min(region.to, MMLEventParser.firstNoteNumber(str[3]));
}
this.lowerNote = region.from;
this.upperNote = region.to;
this.bank = bank;
this.program = program;
}
private static final class KeyRegion {
int from;
int to;
KeyRegion() {
this.from = 0;
this.to = 1024;
}
KeyRegion(int from, int to) {
this.from = from;
this.to = to;
}
}
private KeyRegion regionFromTo(Instrument inst) {
if (inst == null) {
return new KeyRegion();
}
int max = Integer.MIN_VALUE;
int min = Integer.MAX_VALUE;
if (inst instanceof DLSInstrument) {
DLSInstrument dlsinst = (DLSInstrument) inst;
for (DLSRegion reg : dlsinst.getRegions()) {
min = Math.min(min, reg.getKeyfrom());
max = Math.max(max, reg.getKeyto());
}
}
if ( (max == Integer.MIN_VALUE) || (min == Integer.MAX_VALUE) ) {
return new KeyRegion();
}
min -= 12;
max -= 12;
return new KeyRegion(min, max);
}
@Override
public String toString() {
return this.name;
}
@Override
public boolean equals(Object o) {
if (o instanceof InstClass) {
InstClass obj = (InstClass) o;
return (bank == obj.bank) && (program == obj.program);
}
return false;
}
public int getBank() {
return this.bank;
}
public int getProgram() {
return this.program;
}
public int getLowerNote() {
return this.lowerNote;
}
public int getUpperNote() {
return this.upperNote;
}
public InstType getType() {
return this.type;
}
public Instrument getInstrument() {
return this.inst;
}
/**
* プログラム番号上で有効なパート情報を取得する.
* @param program
* @return
*/
public static boolean[] getEnablePartByProgram(int program) {
InstClass inst = MabiDLS.getInstance().getInstByProgram(program);
if (inst != null) {
return inst.getType().getEnablePart();
}
return InstType.NONE.getEnablePart();
}
/**
* プログラム番号上で有効な最初のパート番号を取得する.
* @param program
* @return パート番号
*/
public static int getFirstPartNumberOnProgram(int program) {
boolean b[] = getEnablePartByProgram(program);
for (int i = 0; i < b.length; i++) {
if (b[i]) {
return i;
}
}
throw new AssertionError("Invalid Inst Part Number.");
}
private static String instName(Instrument inst) {
try {
String name = instResource.getString(""+inst.getPatch().getProgram());
return name;
} catch (MissingResourceException e) {
return null;
}
}
public static List<InstClass> loadDLS(File dlsFile) throws InvalidMidiDataException, IOException {
Soundbank sb = null;
try {
sb = MidiSystem.getSoundbank(dlsFile);
} catch (Exception e) {
MabiIccoProperties.getInstance().setDlsFile(null);
throw new IOException("loadDLS: "+dlsFile.getName());
}
ArrayList<InstClass> instArray = new ArrayList<>();
for (Instrument inst : sb.getInstruments()) {
String name = instName(inst);
String originalName = inst.getName();
int bank = inst.getPatch().getBank();
int program = inst.getPatch().getProgram();
System.out.printf("%d,%d=%s \"%s\"\n", bank, program, originalName, name);
if (name != null) {
name = ""+program+": "+name;
instArray.add(new InstClass( name,
bank,
program,
inst));
}
if ( (debug) && (inst instanceof DLSInstrument) ) {
DLSInstrument dlsinst = (DLSInstrument) inst;
for (DLSRegion reg : dlsinst.getRegions()) {
double attenuation = reg.getSample().getSampleoptions().getAttenuation()/655360.0;
System.out.print(" >> "+reg.getSample().getName()+" ");
System.out.print(attenuation+" ");
System.out.print(Math.pow(10.0, attenuation/20.0)+" ");
System.out.print(reg.getKeyfrom()+" ");
System.out.print(reg.getKeyto()+" ");
System.out.print(reg.getVelfrom()+" ");
System.out.println(reg.getVelto()+" ");
}
}
}
return instArray;
}
}