|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
package com.sun.media.sound; |
|
|
|
import java.io.File; |
|
import java.io.FileInputStream; |
|
import java.io.IOException; |
|
import java.io.InputStream; |
|
import java.io.OutputStream; |
|
import java.net.URL; |
|
import java.util.ArrayList; |
|
import java.util.Arrays; |
|
import java.util.Iterator; |
|
import java.util.List; |
|
import java.util.Map; |
|
|
|
import javax.sound.midi.Instrument; |
|
import javax.sound.midi.Patch; |
|
import javax.sound.midi.Soundbank; |
|
import javax.sound.midi.SoundbankResource; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public final class SF2Soundbank implements Soundbank { |
|
|
|
|
|
int major = 2; |
|
int minor = 1; |
|
|
|
String targetEngine = "EMU8000"; |
|
|
|
String name = "untitled"; |
|
|
|
String romName = null; |
|
|
|
int romVersionMajor = -1; |
|
int romVersionMinor = -1; |
|
|
|
String creationDate = null; |
|
|
|
String engineers = null; |
|
|
|
String product = null; |
|
|
|
String copyright = null; |
|
|
|
String comments = null; |
|
|
|
String tools = null; |
|
|
|
private ModelByteBuffer sampleData = null; |
|
private ModelByteBuffer sampleData24 = null; |
|
private File sampleFile = null; |
|
private boolean largeFormat = false; |
|
private final List<SF2Instrument> instruments = new ArrayList<SF2Instrument>(); |
|
private final List<SF2Layer> layers = new ArrayList<SF2Layer>(); |
|
private final List<SF2Sample> samples = new ArrayList<SF2Sample>(); |
|
|
|
public SF2Soundbank() { |
|
} |
|
|
|
public SF2Soundbank(URL url) throws IOException { |
|
|
|
InputStream is = url.openStream(); |
|
try { |
|
readSoundbank(is); |
|
} finally { |
|
is.close(); |
|
} |
|
} |
|
|
|
public SF2Soundbank(File file) throws IOException { |
|
largeFormat = true; |
|
sampleFile = file; |
|
InputStream is = new FileInputStream(file); |
|
try { |
|
readSoundbank(is); |
|
} finally { |
|
is.close(); |
|
} |
|
} |
|
|
|
public SF2Soundbank(InputStream inputstream) throws IOException { |
|
readSoundbank(inputstream); |
|
} |
|
|
|
private void readSoundbank(InputStream inputstream) throws IOException { |
|
RIFFReader riff = new RIFFReader(inputstream); |
|
if (!riff.getFormat().equals("RIFF")) { |
|
throw new RIFFInvalidFormatException( |
|
"Input stream is not a valid RIFF stream!"); |
|
} |
|
if (!riff.getType().equals("sfbk")) { |
|
throw new RIFFInvalidFormatException( |
|
"Input stream is not a valid SoundFont!"); |
|
} |
|
while (riff.hasNextChunk()) { |
|
RIFFReader chunk = riff.nextChunk(); |
|
if (chunk.getFormat().equals("LIST")) { |
|
if (chunk.getType().equals("INFO")) |
|
readInfoChunk(chunk); |
|
if (chunk.getType().equals("sdta")) |
|
readSdtaChunk(chunk); |
|
if (chunk.getType().equals("pdta")) |
|
readPdtaChunk(chunk); |
|
} |
|
} |
|
} |
|
|
|
private void readInfoChunk(RIFFReader riff) throws IOException { |
|
while (riff.hasNextChunk()) { |
|
RIFFReader chunk = riff.nextChunk(); |
|
String format = chunk.getFormat(); |
|
if (format.equals("ifil")) { |
|
major = chunk.readUnsignedShort(); |
|
minor = chunk.readUnsignedShort(); |
|
} else if (format.equals("isng")) { |
|
this.targetEngine = chunk.readString(chunk.available()); |
|
} else if (format.equals("INAM")) { |
|
this.name = chunk.readString(chunk.available()); |
|
} else if (format.equals("irom")) { |
|
this.romName = chunk.readString(chunk.available()); |
|
} else if (format.equals("iver")) { |
|
romVersionMajor = chunk.readUnsignedShort(); |
|
romVersionMinor = chunk.readUnsignedShort(); |
|
} else if (format.equals("ICRD")) { |
|
this.creationDate = chunk.readString(chunk.available()); |
|
} else if (format.equals("IENG")) { |
|
this.engineers = chunk.readString(chunk.available()); |
|
} else if (format.equals("IPRD")) { |
|
this.product = chunk.readString(chunk.available()); |
|
} else if (format.equals("ICOP")) { |
|
this.copyright = chunk.readString(chunk.available()); |
|
} else if (format.equals("ICMT")) { |
|
this.comments = chunk.readString(chunk.available()); |
|
} else if (format.equals("ISFT")) { |
|
this.tools = chunk.readString(chunk.available()); |
|
} |
|
|
|
} |
|
} |
|
|
|
private void readSdtaChunk(RIFFReader riff) throws IOException { |
|
while (riff.hasNextChunk()) { |
|
RIFFReader chunk = riff.nextChunk(); |
|
if (chunk.getFormat().equals("smpl")) { |
|
if (!largeFormat) { |
|
byte[] sampleData = new byte[chunk.available()]; |
|
|
|
int read = 0; |
|
int avail = chunk.available(); |
|
while (read != avail) { |
|
if (avail - read > 65536) { |
|
chunk.readFully(sampleData, read, 65536); |
|
read += 65536; |
|
} else { |
|
chunk.readFully(sampleData, read, avail - read); |
|
read = avail; |
|
} |
|
|
|
} |
|
this.sampleData = new ModelByteBuffer(sampleData); |
|
//chunk.read(sampleData); |
|
} else { |
|
this.sampleData = new ModelByteBuffer(sampleFile, |
|
chunk.getFilePointer(), chunk.available()); |
|
} |
|
} |
|
if (chunk.getFormat().equals("sm24")) { |
|
if (!largeFormat) { |
|
byte[] sampleData24 = new byte[chunk.available()]; |
|
//chunk.read(sampleData24); |
|
|
|
int read = 0; |
|
int avail = chunk.available(); |
|
while (read != avail) { |
|
if (avail - read > 65536) { |
|
chunk.readFully(sampleData24, read, 65536); |
|
read += 65536; |
|
} else { |
|
chunk.readFully(sampleData24, read, avail - read); |
|
read = avail; |
|
} |
|
|
|
} |
|
this.sampleData24 = new ModelByteBuffer(sampleData24); |
|
} else { |
|
this.sampleData24 = new ModelByteBuffer(sampleFile, |
|
chunk.getFilePointer(), chunk.available()); |
|
} |
|
|
|
} |
|
} |
|
} |
|
|
|
private void readPdtaChunk(RIFFReader riff) throws IOException { |
|
|
|
List<SF2Instrument> presets = new ArrayList<SF2Instrument>(); |
|
List<Integer> presets_bagNdx = new ArrayList<Integer>(); |
|
List<SF2InstrumentRegion> presets_splits_gen |
|
= new ArrayList<SF2InstrumentRegion>(); |
|
List<SF2InstrumentRegion> presets_splits_mod |
|
= new ArrayList<SF2InstrumentRegion>(); |
|
|
|
List<SF2Layer> instruments = new ArrayList<SF2Layer>(); |
|
List<Integer> instruments_bagNdx = new ArrayList<Integer>(); |
|
List<SF2LayerRegion> instruments_splits_gen |
|
= new ArrayList<SF2LayerRegion>(); |
|
List<SF2LayerRegion> instruments_splits_mod |
|
= new ArrayList<SF2LayerRegion>(); |
|
|
|
while (riff.hasNextChunk()) { |
|
RIFFReader chunk = riff.nextChunk(); |
|
String format = chunk.getFormat(); |
|
if (format.equals("phdr")) { |
|
|
|
if (chunk.available() % 38 != 0) |
|
throw new RIFFInvalidDataException(); |
|
int count = chunk.available() / 38; |
|
for (int i = 0; i < count; i++) { |
|
SF2Instrument preset = new SF2Instrument(this); |
|
preset.name = chunk.readString(20); |
|
preset.preset = chunk.readUnsignedShort(); |
|
preset.bank = chunk.readUnsignedShort(); |
|
presets_bagNdx.add(chunk.readUnsignedShort()); |
|
preset.library = chunk.readUnsignedInt(); |
|
preset.genre = chunk.readUnsignedInt(); |
|
preset.morphology = chunk.readUnsignedInt(); |
|
presets.add(preset); |
|
if (i != count - 1) |
|
this.instruments.add(preset); |
|
} |
|
} else if (format.equals("pbag")) { |
|
|
|
if (chunk.available() % 4 != 0) |
|
throw new RIFFInvalidDataException(); |
|
int count = chunk.available() / 4; |
|
|
|
|
|
{ |
|
int gencount = chunk.readUnsignedShort(); |
|
int modcount = chunk.readUnsignedShort(); |
|
while (presets_splits_gen.size() < gencount) |
|
presets_splits_gen.add(null); |
|
while (presets_splits_mod.size() < modcount) |
|
presets_splits_mod.add(null); |
|
count--; |
|
} |
|
|
|
if (presets_bagNdx.isEmpty()) { |
|
throw new RIFFInvalidDataException(); |
|
} |
|
int offset = presets_bagNdx.get(0); |
|
|
|
for (int i = 0; i < offset; i++) { |
|
if (count == 0) |
|
throw new RIFFInvalidDataException(); |
|
int gencount = chunk.readUnsignedShort(); |
|
int modcount = chunk.readUnsignedShort(); |
|
while (presets_splits_gen.size() < gencount) |
|
presets_splits_gen.add(null); |
|
while (presets_splits_mod.size() < modcount) |
|
presets_splits_mod.add(null); |
|
count--; |
|
} |
|
|
|
for (int i = 0; i < presets_bagNdx.size() - 1; i++) { |
|
int zone_count = presets_bagNdx.get(i + 1) |
|
- presets_bagNdx.get(i); |
|
SF2Instrument preset = presets.get(i); |
|
for (int ii = 0; ii < zone_count; ii++) { |
|
if (count == 0) |
|
throw new RIFFInvalidDataException(); |
|
int gencount = chunk.readUnsignedShort(); |
|
int modcount = chunk.readUnsignedShort(); |
|
SF2InstrumentRegion split = new SF2InstrumentRegion(); |
|
preset.regions.add(split); |
|
while (presets_splits_gen.size() < gencount) |
|
presets_splits_gen.add(split); |
|
while (presets_splits_mod.size() < modcount) |
|
presets_splits_mod.add(split); |
|
count--; |
|
} |
|
} |
|
} else if (format.equals("pmod")) { |
|
|
|
for (int i = 0; i < presets_splits_mod.size(); i++) { |
|
SF2Modulator modulator = new SF2Modulator(); |
|
modulator.sourceOperator = chunk.readUnsignedShort(); |
|
modulator.destinationOperator = chunk.readUnsignedShort(); |
|
modulator.amount = chunk.readShort(); |
|
modulator.amountSourceOperator = chunk.readUnsignedShort(); |
|
modulator.transportOperator = chunk.readUnsignedShort(); |
|
SF2InstrumentRegion split = presets_splits_mod.get(i); |
|
if (split != null) |
|
split.modulators.add(modulator); |
|
} |
|
} else if (format.equals("pgen")) { |
|
|
|
for (int i = 0; i < presets_splits_gen.size(); i++) { |
|
int operator = chunk.readUnsignedShort(); |
|
short amount = chunk.readShort(); |
|
SF2InstrumentRegion split = presets_splits_gen.get(i); |
|
if (split != null) |
|
split.generators.put(operator, amount); |
|
} |
|
} else if (format.equals("inst")) { |
|
|
|
if (chunk.available() % 22 != 0) |
|
throw new RIFFInvalidDataException(); |
|
int count = chunk.available() / 22; |
|
for (int i = 0; i < count; i++) { |
|
SF2Layer layer = new SF2Layer(this); |
|
layer.name = chunk.readString(20); |
|
instruments_bagNdx.add(chunk.readUnsignedShort()); |
|
instruments.add(layer); |
|
if (i != count - 1) |
|
this.layers.add(layer); |
|
} |
|
} else if (format.equals("ibag")) { |
|
|
|
if (chunk.available() % 4 != 0) |
|
throw new RIFFInvalidDataException(); |
|
int count = chunk.available() / 4; |
|
|
|
|
|
{ |
|
int gencount = chunk.readUnsignedShort(); |
|
int modcount = chunk.readUnsignedShort(); |
|
while (instruments_splits_gen.size() < gencount) |
|
instruments_splits_gen.add(null); |
|
while (instruments_splits_mod.size() < modcount) |
|
instruments_splits_mod.add(null); |
|
count--; |
|
} |
|
|
|
if (instruments_bagNdx.isEmpty()) { |
|
throw new RIFFInvalidDataException(); |
|
} |
|
int offset = instruments_bagNdx.get(0); |
|
|
|
for (int i = 0; i < offset; i++) { |
|
if (count == 0) |
|
throw new RIFFInvalidDataException(); |
|
int gencount = chunk.readUnsignedShort(); |
|
int modcount = chunk.readUnsignedShort(); |
|
while (instruments_splits_gen.size() < gencount) |
|
instruments_splits_gen.add(null); |
|
while (instruments_splits_mod.size() < modcount) |
|
instruments_splits_mod.add(null); |
|
count--; |
|
} |
|
|
|
for (int i = 0; i < instruments_bagNdx.size() - 1; i++) { |
|
int zone_count = instruments_bagNdx.get(i + 1) - instruments_bagNdx.get(i); |
|
SF2Layer layer = layers.get(i); |
|
for (int ii = 0; ii < zone_count; ii++) { |
|
if (count == 0) |
|
throw new RIFFInvalidDataException(); |
|
int gencount = chunk.readUnsignedShort(); |
|
int modcount = chunk.readUnsignedShort(); |
|
SF2LayerRegion split = new SF2LayerRegion(); |
|
layer.regions.add(split); |
|
while (instruments_splits_gen.size() < gencount) |
|
instruments_splits_gen.add(split); |
|
while (instruments_splits_mod.size() < modcount) |
|
instruments_splits_mod.add(split); |
|
count--; |
|
} |
|
} |
|
|
|
} else if (format.equals("imod")) { |
|
|
|
for (int i = 0; i < instruments_splits_mod.size(); i++) { |
|
SF2Modulator modulator = new SF2Modulator(); |
|
modulator.sourceOperator = chunk.readUnsignedShort(); |
|
modulator.destinationOperator = chunk.readUnsignedShort(); |
|
modulator.amount = chunk.readShort(); |
|
modulator.amountSourceOperator = chunk.readUnsignedShort(); |
|
modulator.transportOperator = chunk.readUnsignedShort(); |
|
if (i < 0 || i >= instruments_splits_gen.size()) { |
|
throw new RIFFInvalidDataException(); |
|
} |
|
SF2LayerRegion split = instruments_splits_gen.get(i); |
|
if (split != null) |
|
split.modulators.add(modulator); |
|
} |
|
} else if (format.equals("igen")) { |
|
|
|
for (int i = 0; i < instruments_splits_gen.size(); i++) { |
|
int operator = chunk.readUnsignedShort(); |
|
short amount = chunk.readShort(); |
|
SF2LayerRegion split = instruments_splits_gen.get(i); |
|
if (split != null) |
|
split.generators.put(operator, amount); |
|
} |
|
} else if (format.equals("shdr")) { |
|
|
|
if (chunk.available() % 46 != 0) |
|
throw new RIFFInvalidDataException(); |
|
int count = chunk.available() / 46; |
|
for (int i = 0; i < count; i++) { |
|
SF2Sample sample = new SF2Sample(this); |
|
sample.name = chunk.readString(20); |
|
long start = chunk.readUnsignedInt(); |
|
long end = chunk.readUnsignedInt(); |
|
if (sampleData != null) |
|
sample.data = sampleData.subbuffer(start * 2, end * 2, true); |
|
if (sampleData24 != null) |
|
sample.data24 = sampleData24.subbuffer(start, end, true); |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
sample.startLoop = chunk.readUnsignedInt() - start; |
|
sample.endLoop = chunk.readUnsignedInt() - start; |
|
if (sample.startLoop < 0) |
|
sample.startLoop = -1; |
|
if (sample.endLoop < 0) |
|
sample.endLoop = -1; |
|
sample.sampleRate = chunk.readUnsignedInt(); |
|
sample.originalPitch = chunk.readUnsignedByte(); |
|
sample.pitchCorrection = chunk.readByte(); |
|
sample.sampleLink = chunk.readUnsignedShort(); |
|
sample.sampleType = chunk.readUnsignedShort(); |
|
if (i != count - 1) |
|
this.samples.add(sample); |
|
} |
|
} |
|
} |
|
|
|
Iterator<SF2Layer> liter = this.layers.iterator(); |
|
while (liter.hasNext()) { |
|
SF2Layer layer = liter.next(); |
|
Iterator<SF2LayerRegion> siter = layer.regions.iterator(); |
|
SF2Region globalsplit = null; |
|
while (siter.hasNext()) { |
|
SF2LayerRegion split = siter.next(); |
|
if (split.generators.get(SF2LayerRegion.GENERATOR_SAMPLEID) != null) { |
|
int sampleid = split.generators.get( |
|
SF2LayerRegion.GENERATOR_SAMPLEID); |
|
split.generators.remove(SF2LayerRegion.GENERATOR_SAMPLEID); |
|
if (sampleid < 0 || sampleid >= samples.size()) { |
|
throw new RIFFInvalidDataException(); |
|
} |
|
split.sample = samples.get(sampleid); |
|
} else { |
|
globalsplit = split; |
|
} |
|
} |
|
if (globalsplit != null) { |
|
layer.getRegions().remove(globalsplit); |
|
SF2GlobalRegion gsplit = new SF2GlobalRegion(); |
|
gsplit.generators = globalsplit.generators; |
|
gsplit.modulators = globalsplit.modulators; |
|
layer.setGlobalZone(gsplit); |
|
} |
|
} |
|
|
|
|
|
Iterator<SF2Instrument> iiter = this.instruments.iterator(); |
|
while (iiter.hasNext()) { |
|
SF2Instrument instrument = iiter.next(); |
|
Iterator<SF2InstrumentRegion> siter = instrument.regions.iterator(); |
|
SF2Region globalsplit = null; |
|
while (siter.hasNext()) { |
|
SF2InstrumentRegion split = siter.next(); |
|
if (split.generators.get(SF2LayerRegion.GENERATOR_INSTRUMENT) != null) { |
|
int instrumentid = split.generators.get( |
|
SF2InstrumentRegion.GENERATOR_INSTRUMENT); |
|
split.generators.remove(SF2LayerRegion.GENERATOR_INSTRUMENT); |
|
if (instrumentid < 0 || instrumentid >= layers.size()) { |
|
throw new RIFFInvalidDataException(); |
|
} |
|
split.layer = layers.get(instrumentid); |
|
} else { |
|
globalsplit = split; |
|
} |
|
} |
|
|
|
if (globalsplit != null) { |
|
instrument.getRegions().remove(globalsplit); |
|
SF2GlobalRegion gsplit = new SF2GlobalRegion(); |
|
gsplit.generators = globalsplit.generators; |
|
gsplit.modulators = globalsplit.modulators; |
|
instrument.setGlobalZone(gsplit); |
|
} |
|
} |
|
|
|
} |
|
|
|
public void save(String name) throws IOException { |
|
writeSoundbank(new RIFFWriter(name, "sfbk")); |
|
} |
|
|
|
public void save(File file) throws IOException { |
|
writeSoundbank(new RIFFWriter(file, "sfbk")); |
|
} |
|
|
|
public void save(OutputStream out) throws IOException { |
|
writeSoundbank(new RIFFWriter(out, "sfbk")); |
|
} |
|
|
|
private void writeSoundbank(RIFFWriter writer) throws IOException { |
|
writeInfo(writer.writeList("INFO")); |
|
writeSdtaChunk(writer.writeList("sdta")); |
|
writePdtaChunk(writer.writeList("pdta")); |
|
writer.close(); |
|
} |
|
|
|
private void writeInfoStringChunk(RIFFWriter writer, String name, |
|
String value) throws IOException { |
|
if (value == null) |
|
return; |
|
RIFFWriter chunk = writer.writeChunk(name); |
|
chunk.writeString(value); |
|
int len = value.getBytes("ascii").length; |
|
chunk.write(0); |
|
len++; |
|
if (len % 2 != 0) |
|
chunk.write(0); |
|
} |
|
|
|
private void writeInfo(RIFFWriter writer) throws IOException { |
|
if (this.targetEngine == null) |
|
this.targetEngine = "EMU8000"; |
|
if (this.name == null) |
|
this.name = ""; |
|
|
|
RIFFWriter ifil_chunk = writer.writeChunk("ifil"); |
|
ifil_chunk.writeUnsignedShort(this.major); |
|
ifil_chunk.writeUnsignedShort(this.minor); |
|
writeInfoStringChunk(writer, "isng", this.targetEngine); |
|
writeInfoStringChunk(writer, "INAM", this.name); |
|
writeInfoStringChunk(writer, "irom", this.romName); |
|
if (romVersionMajor != -1) { |
|
RIFFWriter iver_chunk = writer.writeChunk("iver"); |
|
iver_chunk.writeUnsignedShort(this.romVersionMajor); |
|
iver_chunk.writeUnsignedShort(this.romVersionMinor); |
|
} |
|
writeInfoStringChunk(writer, "ICRD", this.creationDate); |
|
writeInfoStringChunk(writer, "IENG", this.engineers); |
|
writeInfoStringChunk(writer, "IPRD", this.product); |
|
writeInfoStringChunk(writer, "ICOP", this.copyright); |
|
writeInfoStringChunk(writer, "ICMT", this.comments); |
|
writeInfoStringChunk(writer, "ISFT", this.tools); |
|
|
|
writer.close(); |
|
} |
|
|
|
private void writeSdtaChunk(RIFFWriter writer) throws IOException { |
|
|
|
byte[] pad = new byte[32]; |
|
|
|
RIFFWriter smpl_chunk = writer.writeChunk("smpl"); |
|
for (SF2Sample sample : samples) { |
|
ModelByteBuffer data = sample.getDataBuffer(); |
|
data.writeTo(smpl_chunk); |
|
|
|
|
|
|
|
|
|
*/ |
|
smpl_chunk.write(pad); |
|
smpl_chunk.write(pad); |
|
} |
|
if (major < 2) |
|
return; |
|
if (major == 2 && minor < 4) |
|
return; |
|
|
|
|
|
for (SF2Sample sample : samples) { |
|
ModelByteBuffer data24 = sample.getData24Buffer(); |
|
if (data24 == null) |
|
return; |
|
} |
|
|
|
RIFFWriter sm24_chunk = writer.writeChunk("sm24"); |
|
for (SF2Sample sample : samples) { |
|
ModelByteBuffer data = sample.getData24Buffer(); |
|
data.writeTo(sm24_chunk); |
|
|
|
|
|
|
|
data.capacity());*/ |
|
smpl_chunk.write(pad); |
|
} |
|
} |
|
|
|
private void writeModulators(RIFFWriter writer, List<SF2Modulator> modulators) |
|
throws IOException { |
|
for (SF2Modulator modulator : modulators) { |
|
writer.writeUnsignedShort(modulator.sourceOperator); |
|
writer.writeUnsignedShort(modulator.destinationOperator); |
|
writer.writeShort(modulator.amount); |
|
writer.writeUnsignedShort(modulator.amountSourceOperator); |
|
writer.writeUnsignedShort(modulator.transportOperator); |
|
} |
|
} |
|
|
|
private void writeGenerators(RIFFWriter writer, Map<Integer, Short> generators) |
|
throws IOException { |
|
Short keyrange = (Short) generators.get(SF2Region.GENERATOR_KEYRANGE); |
|
Short velrange = (Short) generators.get(SF2Region.GENERATOR_VELRANGE); |
|
if (keyrange != null) { |
|
writer.writeUnsignedShort(SF2Region.GENERATOR_KEYRANGE); |
|
writer.writeShort(keyrange); |
|
} |
|
if (velrange != null) { |
|
writer.writeUnsignedShort(SF2Region.GENERATOR_VELRANGE); |
|
writer.writeShort(velrange); |
|
} |
|
for (Map.Entry<Integer, Short> generator : generators.entrySet()) { |
|
if (generator.getKey() == SF2Region.GENERATOR_KEYRANGE) |
|
continue; |
|
if (generator.getKey() == SF2Region.GENERATOR_VELRANGE) |
|
continue; |
|
writer.writeUnsignedShort(generator.getKey()); |
|
writer.writeShort(generator.getValue()); |
|
} |
|
} |
|
|
|
private void writePdtaChunk(RIFFWriter writer) throws IOException { |
|
|
|
RIFFWriter phdr_chunk = writer.writeChunk("phdr"); |
|
int phdr_zone_count = 0; |
|
for (SF2Instrument preset : this.instruments) { |
|
phdr_chunk.writeString(preset.name, 20); |
|
phdr_chunk.writeUnsignedShort(preset.preset); |
|
phdr_chunk.writeUnsignedShort(preset.bank); |
|
phdr_chunk.writeUnsignedShort(phdr_zone_count); |
|
if (preset.getGlobalRegion() != null) |
|
phdr_zone_count += 1; |
|
phdr_zone_count += preset.getRegions().size(); |
|
phdr_chunk.writeUnsignedInt(preset.library); |
|
phdr_chunk.writeUnsignedInt(preset.genre); |
|
phdr_chunk.writeUnsignedInt(preset.morphology); |
|
} |
|
phdr_chunk.writeString("EOP", 20); |
|
phdr_chunk.writeUnsignedShort(0); |
|
phdr_chunk.writeUnsignedShort(0); |
|
phdr_chunk.writeUnsignedShort(phdr_zone_count); |
|
phdr_chunk.writeUnsignedInt(0); |
|
phdr_chunk.writeUnsignedInt(0); |
|
phdr_chunk.writeUnsignedInt(0); |
|
|
|
|
|
RIFFWriter pbag_chunk = writer.writeChunk("pbag"); |
|
int pbag_gencount = 0; |
|
int pbag_modcount = 0; |
|
for (SF2Instrument preset : this.instruments) { |
|
if (preset.getGlobalRegion() != null) { |
|
pbag_chunk.writeUnsignedShort(pbag_gencount); |
|
pbag_chunk.writeUnsignedShort(pbag_modcount); |
|
pbag_gencount += preset.getGlobalRegion().getGenerators().size(); |
|
pbag_modcount += preset.getGlobalRegion().getModulators().size(); |
|
} |
|
for (SF2InstrumentRegion region : preset.getRegions()) { |
|
pbag_chunk.writeUnsignedShort(pbag_gencount); |
|
pbag_chunk.writeUnsignedShort(pbag_modcount); |
|
if (layers.indexOf(region.layer) != -1) { |
|
|
|
pbag_gencount += 1; |
|
} |
|
pbag_gencount += region.getGenerators().size(); |
|
pbag_modcount += region.getModulators().size(); |
|
|
|
} |
|
} |
|
pbag_chunk.writeUnsignedShort(pbag_gencount); |
|
pbag_chunk.writeUnsignedShort(pbag_modcount); |
|
|
|
RIFFWriter pmod_chunk = writer.writeChunk("pmod"); |
|
for (SF2Instrument preset : this.instruments) { |
|
if (preset.getGlobalRegion() != null) { |
|
writeModulators(pmod_chunk, |
|
preset.getGlobalRegion().getModulators()); |
|
} |
|
for (SF2InstrumentRegion region : preset.getRegions()) |
|
writeModulators(pmod_chunk, region.getModulators()); |
|
} |
|
pmod_chunk.write(new byte[10]); |
|
|
|
RIFFWriter pgen_chunk = writer.writeChunk("pgen"); |
|
for (SF2Instrument preset : this.instruments) { |
|
if (preset.getGlobalRegion() != null) { |
|
writeGenerators(pgen_chunk, |
|
preset.getGlobalRegion().getGenerators()); |
|
} |
|
for (SF2InstrumentRegion region : preset.getRegions()) { |
|
writeGenerators(pgen_chunk, region.getGenerators()); |
|
int ix = (int) layers.indexOf(region.layer); |
|
if (ix != -1) { |
|
pgen_chunk.writeUnsignedShort(SF2Region.GENERATOR_INSTRUMENT); |
|
pgen_chunk.writeShort((short) ix); |
|
} |
|
} |
|
} |
|
pgen_chunk.write(new byte[4]); |
|
|
|
RIFFWriter inst_chunk = writer.writeChunk("inst"); |
|
int inst_zone_count = 0; |
|
for (SF2Layer instrument : this.layers) { |
|
inst_chunk.writeString(instrument.name, 20); |
|
inst_chunk.writeUnsignedShort(inst_zone_count); |
|
if (instrument.getGlobalRegion() != null) |
|
inst_zone_count += 1; |
|
inst_zone_count += instrument.getRegions().size(); |
|
} |
|
inst_chunk.writeString("EOI", 20); |
|
inst_chunk.writeUnsignedShort(inst_zone_count); |
|
|
|
|
|
RIFFWriter ibag_chunk = writer.writeChunk("ibag"); |
|
int ibag_gencount = 0; |
|
int ibag_modcount = 0; |
|
for (SF2Layer instrument : this.layers) { |
|
if (instrument.getGlobalRegion() != null) { |
|
ibag_chunk.writeUnsignedShort(ibag_gencount); |
|
ibag_chunk.writeUnsignedShort(ibag_modcount); |
|
ibag_gencount |
|
+= instrument.getGlobalRegion().getGenerators().size(); |
|
ibag_modcount |
|
+= instrument.getGlobalRegion().getModulators().size(); |
|
} |
|
for (SF2LayerRegion region : instrument.getRegions()) { |
|
ibag_chunk.writeUnsignedShort(ibag_gencount); |
|
ibag_chunk.writeUnsignedShort(ibag_modcount); |
|
if (samples.indexOf(region.sample) != -1) { |
|
|
|
ibag_gencount += 1; |
|
} |
|
ibag_gencount += region.getGenerators().size(); |
|
ibag_modcount += region.getModulators().size(); |
|
|
|
} |
|
} |
|
ibag_chunk.writeUnsignedShort(ibag_gencount); |
|
ibag_chunk.writeUnsignedShort(ibag_modcount); |
|
|
|
|
|
RIFFWriter imod_chunk = writer.writeChunk("imod"); |
|
for (SF2Layer instrument : this.layers) { |
|
if (instrument.getGlobalRegion() != null) { |
|
writeModulators(imod_chunk, |
|
instrument.getGlobalRegion().getModulators()); |
|
} |
|
for (SF2LayerRegion region : instrument.getRegions()) |
|
writeModulators(imod_chunk, region.getModulators()); |
|
} |
|
imod_chunk.write(new byte[10]); |
|
|
|
RIFFWriter igen_chunk = writer.writeChunk("igen"); |
|
for (SF2Layer instrument : this.layers) { |
|
if (instrument.getGlobalRegion() != null) { |
|
writeGenerators(igen_chunk, |
|
instrument.getGlobalRegion().getGenerators()); |
|
} |
|
for (SF2LayerRegion region : instrument.getRegions()) { |
|
writeGenerators(igen_chunk, region.getGenerators()); |
|
int ix = samples.indexOf(region.sample); |
|
if (ix != -1) { |
|
igen_chunk.writeUnsignedShort(SF2Region.GENERATOR_SAMPLEID); |
|
igen_chunk.writeShort((short) ix); |
|
} |
|
} |
|
} |
|
igen_chunk.write(new byte[4]); |
|
|
|
|
|
RIFFWriter shdr_chunk = writer.writeChunk("shdr"); |
|
long sample_pos = 0; |
|
for (SF2Sample sample : samples) { |
|
shdr_chunk.writeString(sample.name, 20); |
|
long start = sample_pos; |
|
sample_pos += sample.data.capacity() / 2; |
|
long end = sample_pos; |
|
long startLoop = sample.startLoop + start; |
|
long endLoop = sample.endLoop + start; |
|
if (startLoop < start) |
|
startLoop = start; |
|
if (endLoop > end) |
|
endLoop = end; |
|
shdr_chunk.writeUnsignedInt(start); |
|
shdr_chunk.writeUnsignedInt(end); |
|
shdr_chunk.writeUnsignedInt(startLoop); |
|
shdr_chunk.writeUnsignedInt(endLoop); |
|
shdr_chunk.writeUnsignedInt(sample.sampleRate); |
|
shdr_chunk.writeUnsignedByte(sample.originalPitch); |
|
shdr_chunk.writeByte(sample.pitchCorrection); |
|
shdr_chunk.writeUnsignedShort(sample.sampleLink); |
|
shdr_chunk.writeUnsignedShort(sample.sampleType); |
|
sample_pos += 32; |
|
} |
|
shdr_chunk.writeString("EOS", 20); |
|
shdr_chunk.write(new byte[26]); |
|
|
|
} |
|
|
|
public String getName() { |
|
return name; |
|
} |
|
|
|
public String getVersion() { |
|
return major + "." + minor; |
|
} |
|
|
|
public String getVendor() { |
|
return engineers; |
|
} |
|
|
|
public String getDescription() { |
|
return comments; |
|
} |
|
|
|
public void setName(String s) { |
|
name = s; |
|
} |
|
|
|
public void setVendor(String s) { |
|
engineers = s; |
|
} |
|
|
|
public void setDescription(String s) { |
|
comments = s; |
|
} |
|
|
|
public SoundbankResource[] getResources() { |
|
SoundbankResource[] resources |
|
= new SoundbankResource[layers.size() + samples.size()]; |
|
int j = 0; |
|
for (int i = 0; i < layers.size(); i++) |
|
resources[j++] = layers.get(i); |
|
for (int i = 0; i < samples.size(); i++) |
|
resources[j++] = samples.get(i); |
|
return resources; |
|
} |
|
|
|
public SF2Instrument[] getInstruments() { |
|
SF2Instrument[] inslist_array |
|
= instruments.toArray(new SF2Instrument[instruments.size()]); |
|
Arrays.sort(inslist_array, new ModelInstrumentComparator()); |
|
return inslist_array; |
|
} |
|
|
|
public SF2Layer[] getLayers() { |
|
return layers.toArray(new SF2Layer[layers.size()]); |
|
} |
|
|
|
public SF2Sample[] getSamples() { |
|
return samples.toArray(new SF2Sample[samples.size()]); |
|
} |
|
|
|
public Instrument getInstrument(Patch patch) { |
|
int program = patch.getProgram(); |
|
int bank = patch.getBank(); |
|
boolean percussion = false; |
|
if (patch instanceof ModelPatch) |
|
percussion = ((ModelPatch)patch).isPercussion(); |
|
for (Instrument instrument : instruments) { |
|
Patch patch2 = instrument.getPatch(); |
|
int program2 = patch2.getProgram(); |
|
int bank2 = patch2.getBank(); |
|
if (program == program2 && bank == bank2) { |
|
boolean percussion2 = false; |
|
if (patch2 instanceof ModelPatch) |
|
percussion2 = ((ModelPatch) patch2).isPercussion(); |
|
if (percussion == percussion2) |
|
return instrument; |
|
} |
|
} |
|
return null; |
|
} |
|
|
|
public String getCreationDate() { |
|
return creationDate; |
|
} |
|
|
|
public void setCreationDate(String creationDate) { |
|
this.creationDate = creationDate; |
|
} |
|
|
|
public String getProduct() { |
|
return product; |
|
} |
|
|
|
public void setProduct(String product) { |
|
this.product = product; |
|
} |
|
|
|
public String getRomName() { |
|
return romName; |
|
} |
|
|
|
public void setRomName(String romName) { |
|
this.romName = romName; |
|
} |
|
|
|
public int getRomVersionMajor() { |
|
return romVersionMajor; |
|
} |
|
|
|
public void setRomVersionMajor(int romVersionMajor) { |
|
this.romVersionMajor = romVersionMajor; |
|
} |
|
|
|
public int getRomVersionMinor() { |
|
return romVersionMinor; |
|
} |
|
|
|
public void setRomVersionMinor(int romVersionMinor) { |
|
this.romVersionMinor = romVersionMinor; |
|
} |
|
|
|
public String getTargetEngine() { |
|
return targetEngine; |
|
} |
|
|
|
public void setTargetEngine(String targetEngine) { |
|
this.targetEngine = targetEngine; |
|
} |
|
|
|
public String getTools() { |
|
return tools; |
|
} |
|
|
|
public void setTools(String tools) { |
|
this.tools = tools; |
|
} |
|
|
|
public void addResource(SoundbankResource resource) { |
|
if (resource instanceof SF2Instrument) |
|
instruments.add((SF2Instrument)resource); |
|
if (resource instanceof SF2Layer) |
|
layers.add((SF2Layer)resource); |
|
if (resource instanceof SF2Sample) |
|
samples.add((SF2Sample)resource); |
|
} |
|
|
|
public void removeResource(SoundbankResource resource) { |
|
if (resource instanceof SF2Instrument) |
|
instruments.remove((SF2Instrument)resource); |
|
if (resource instanceof SF2Layer) |
|
layers.remove((SF2Layer)resource); |
|
if (resource instanceof SF2Sample) |
|
samples.remove((SF2Sample)resource); |
|
} |
|
|
|
public void addInstrument(SF2Instrument resource) { |
|
instruments.add(resource); |
|
} |
|
|
|
public void removeInstrument(SF2Instrument resource) { |
|
instruments.remove(resource); |
|
} |
|
} |