Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/com/sun/media/sound/DLSSoundbank.java
38924 views
/*1* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/24package com.sun.media.sound;2526import java.io.File;27import java.io.FileInputStream;28import java.io.IOException;29import java.io.InputStream;30import java.io.OutputStream;31import java.net.URL;32import java.util.ArrayList;33import java.util.Arrays;34import java.util.HashMap;35import java.util.List;36import java.util.Map;37import java.util.Stack;3839import javax.sound.midi.Instrument;40import javax.sound.midi.Patch;41import javax.sound.midi.Soundbank;42import javax.sound.midi.SoundbankResource;43import javax.sound.sampled.AudioFormat;44import javax.sound.sampled.AudioInputStream;45import javax.sound.sampled.AudioSystem;46import javax.sound.sampled.AudioFormat.Encoding;4748/**49* A DLS Level 1 and Level 2 soundbank reader (from files/url/streams).50*51* @author Karl Helgason52*/53public final class DLSSoundbank implements Soundbank {5455static private class DLSID {56long i1;57int s1;58int s2;59int x1;60int x2;61int x3;62int x4;63int x5;64int x6;65int x7;66int x8;6768private DLSID() {69}7071DLSID(long i1, int s1, int s2, int x1, int x2, int x3, int x4,72int x5, int x6, int x7, int x8) {73this.i1 = i1;74this.s1 = s1;75this.s2 = s2;76this.x1 = x1;77this.x2 = x2;78this.x3 = x3;79this.x4 = x4;80this.x5 = x5;81this.x6 = x6;82this.x7 = x7;83this.x8 = x8;84}8586public static DLSID read(RIFFReader riff) throws IOException {87DLSID d = new DLSID();88d.i1 = riff.readUnsignedInt();89d.s1 = riff.readUnsignedShort();90d.s2 = riff.readUnsignedShort();91d.x1 = riff.readUnsignedByte();92d.x2 = riff.readUnsignedByte();93d.x3 = riff.readUnsignedByte();94d.x4 = riff.readUnsignedByte();95d.x5 = riff.readUnsignedByte();96d.x6 = riff.readUnsignedByte();97d.x7 = riff.readUnsignedByte();98d.x8 = riff.readUnsignedByte();99return d;100}101102public int hashCode() {103return (int)i1;104}105106public boolean equals(Object obj) {107if (!(obj instanceof DLSID)) {108return false;109}110DLSID t = (DLSID) obj;111return i1 == t.i1 && s1 == t.s1 && s2 == t.s2112&& x1 == t.x1 && x2 == t.x2 && x3 == t.x3 && x4 == t.x4113&& x5 == t.x5 && x6 == t.x6 && x7 == t.x7 && x8 == t.x8;114}115}116117/** X = X & Y */118private static final int DLS_CDL_AND = 0x0001;119/** X = X | Y */120private static final int DLS_CDL_OR = 0x0002;121/** X = X ^ Y */122private static final int DLS_CDL_XOR = 0x0003;123/** X = X + Y */124private static final int DLS_CDL_ADD = 0x0004;125/** X = X - Y */126private static final int DLS_CDL_SUBTRACT = 0x0005;127/** X = X * Y */128private static final int DLS_CDL_MULTIPLY = 0x0006;129/** X = X / Y */130private static final int DLS_CDL_DIVIDE = 0x0007;131/** X = X && Y */132private static final int DLS_CDL_LOGICAL_AND = 0x0008;133/** X = X || Y */134private static final int DLS_CDL_LOGICAL_OR = 0x0009;135/** X = (X < Y) */136private static final int DLS_CDL_LT = 0x000A;137/** X = (X <= Y) */138private static final int DLS_CDL_LE = 0x000B;139/** X = (X > Y) */140private static final int DLS_CDL_GT = 0x000C;141/** X = (X >= Y) */142private static final int DLS_CDL_GE = 0x000D;143/** X = (X == Y) */144private static final int DLS_CDL_EQ = 0x000E;145/** X = !X */146private static final int DLS_CDL_NOT = 0x000F;147/** 32-bit constant */148private static final int DLS_CDL_CONST = 0x0010;149/** 32-bit value returned from query */150private static final int DLS_CDL_QUERY = 0x0011;151/** 32-bit value returned from query */152private static final int DLS_CDL_QUERYSUPPORTED = 0x0012;153154private static final DLSID DLSID_GMInHardware = new DLSID(0x178f2f24,1550xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12);156private static final DLSID DLSID_GSInHardware = new DLSID(0x178f2f25,1570xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12);158private static final DLSID DLSID_XGInHardware = new DLSID(0x178f2f26,1590xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12);160private static final DLSID DLSID_SupportsDLS1 = new DLSID(0x178f2f27,1610xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12);162private static final DLSID DLSID_SupportsDLS2 = new DLSID(0xf14599e5,1630x4689, 0x11d2, 0xaf, 0xa6, 0x0, 0xaa, 0x0, 0x24, 0xd8, 0xb6);164private static final DLSID DLSID_SampleMemorySize = new DLSID(0x178f2f28,1650xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12);166private static final DLSID DLSID_ManufacturersID = new DLSID(0xb03e1181,1670x8095, 0x11d2, 0xa1, 0xef, 0x0, 0x60, 0x8, 0x33, 0xdb, 0xd8);168private static final DLSID DLSID_ProductID = new DLSID(0xb03e1182,1690x8095, 0x11d2, 0xa1, 0xef, 0x0, 0x60, 0x8, 0x33, 0xdb, 0xd8);170private static final DLSID DLSID_SamplePlaybackRate = new DLSID(0x2a91f713,1710xa4bf, 0x11d2, 0xbb, 0xdf, 0x0, 0x60, 0x8, 0x33, 0xdb, 0xd8);172173private long major = -1;174private long minor = -1;175176private final DLSInfo info = new DLSInfo();177178private final List<DLSInstrument> instruments = new ArrayList<DLSInstrument>();179private final List<DLSSample> samples = new ArrayList<DLSSample>();180181private boolean largeFormat = false;182private File sampleFile;183184public DLSSoundbank() {185}186187public DLSSoundbank(URL url) throws IOException {188InputStream is = url.openStream();189try {190readSoundbank(is);191} finally {192is.close();193}194}195196public DLSSoundbank(File file) throws IOException {197largeFormat = true;198sampleFile = file;199InputStream is = new FileInputStream(file);200try {201readSoundbank(is);202} finally {203is.close();204}205}206207public DLSSoundbank(InputStream inputstream) throws IOException {208readSoundbank(inputstream);209}210211private void readSoundbank(InputStream inputstream) throws IOException {212RIFFReader riff = new RIFFReader(inputstream);213if (!riff.getFormat().equals("RIFF")) {214throw new RIFFInvalidFormatException(215"Input stream is not a valid RIFF stream!");216}217if (!riff.getType().equals("DLS ")) {218throw new RIFFInvalidFormatException(219"Input stream is not a valid DLS soundbank!");220}221while (riff.hasNextChunk()) {222RIFFReader chunk = riff.nextChunk();223if (chunk.getFormat().equals("LIST")) {224if (chunk.getType().equals("INFO"))225readInfoChunk(chunk);226if (chunk.getType().equals("lins"))227readLinsChunk(chunk);228if (chunk.getType().equals("wvpl"))229readWvplChunk(chunk);230} else {231if (chunk.getFormat().equals("cdl ")) {232if (!readCdlChunk(chunk)) {233throw new RIFFInvalidFormatException(234"DLS file isn't supported!");235}236}237if (chunk.getFormat().equals("colh")) {238// skipped because we will load the entire bank into memory239// long instrumentcount = chunk.readUnsignedInt();240// System.out.println("instrumentcount = "+ instrumentcount);241}242if (chunk.getFormat().equals("ptbl")) {243// Pool Table Chunk244// skipped because we will load the entire bank into memory245}246if (chunk.getFormat().equals("vers")) {247major = chunk.readUnsignedInt();248minor = chunk.readUnsignedInt();249}250}251}252253for (Map.Entry<DLSRegion, Long> entry : temp_rgnassign.entrySet()) {254entry.getKey().sample = samples.get((int)entry.getValue().longValue());255}256257temp_rgnassign = null;258}259260private boolean cdlIsQuerySupported(DLSID uuid) {261return uuid.equals(DLSID_GMInHardware)262|| uuid.equals(DLSID_GSInHardware)263|| uuid.equals(DLSID_XGInHardware)264|| uuid.equals(DLSID_SupportsDLS1)265|| uuid.equals(DLSID_SupportsDLS2)266|| uuid.equals(DLSID_SampleMemorySize)267|| uuid.equals(DLSID_ManufacturersID)268|| uuid.equals(DLSID_ProductID)269|| uuid.equals(DLSID_SamplePlaybackRate);270}271272private long cdlQuery(DLSID uuid) {273if (uuid.equals(DLSID_GMInHardware))274return 1;275if (uuid.equals(DLSID_GSInHardware))276return 0;277if (uuid.equals(DLSID_XGInHardware))278return 0;279if (uuid.equals(DLSID_SupportsDLS1))280return 1;281if (uuid.equals(DLSID_SupportsDLS2))282return 1;283if (uuid.equals(DLSID_SampleMemorySize))284return Runtime.getRuntime().totalMemory();285if (uuid.equals(DLSID_ManufacturersID))286return 0;287if (uuid.equals(DLSID_ProductID))288return 0;289if (uuid.equals(DLSID_SamplePlaybackRate))290return 44100;291return 0;292}293294295// Reading cdl-ck Chunk296// "cdl " chunk can only appear inside : DLS,lart,lar2,rgn,rgn2297private boolean readCdlChunk(RIFFReader riff) throws IOException {298299DLSID uuid;300long x;301long y;302Stack<Long> stack = new Stack<Long>();303304while (riff.available() != 0) {305int opcode = riff.readUnsignedShort();306switch (opcode) {307case DLS_CDL_AND:308x = stack.pop();309y = stack.pop();310stack.push(Long.valueOf(((x != 0) && (y != 0)) ? 1 : 0));311break;312case DLS_CDL_OR:313x = stack.pop();314y = stack.pop();315stack.push(Long.valueOf(((x != 0) || (y != 0)) ? 1 : 0));316break;317case DLS_CDL_XOR:318x = stack.pop();319y = stack.pop();320stack.push(Long.valueOf(((x != 0) ^ (y != 0)) ? 1 : 0));321break;322case DLS_CDL_ADD:323x = stack.pop();324y = stack.pop();325stack.push(Long.valueOf(x + y));326break;327case DLS_CDL_SUBTRACT:328x = stack.pop();329y = stack.pop();330stack.push(Long.valueOf(x - y));331break;332case DLS_CDL_MULTIPLY:333x = stack.pop();334y = stack.pop();335stack.push(Long.valueOf(x * y));336break;337case DLS_CDL_DIVIDE:338x = stack.pop();339y = stack.pop();340stack.push(Long.valueOf(x / y));341break;342case DLS_CDL_LOGICAL_AND:343x = stack.pop();344y = stack.pop();345stack.push(Long.valueOf(((x != 0) && (y != 0)) ? 1 : 0));346break;347case DLS_CDL_LOGICAL_OR:348x = stack.pop();349y = stack.pop();350stack.push(Long.valueOf(((x != 0) || (y != 0)) ? 1 : 0));351break;352case DLS_CDL_LT:353x = stack.pop();354y = stack.pop();355stack.push(Long.valueOf((x < y) ? 1 : 0));356break;357case DLS_CDL_LE:358x = stack.pop();359y = stack.pop();360stack.push(Long.valueOf((x <= y) ? 1 : 0));361break;362case DLS_CDL_GT:363x = stack.pop();364y = stack.pop();365stack.push(Long.valueOf((x > y) ? 1 : 0));366break;367case DLS_CDL_GE:368x = stack.pop();369y = stack.pop();370stack.push(Long.valueOf((x >= y) ? 1 : 0));371break;372case DLS_CDL_EQ:373x = stack.pop();374y = stack.pop();375stack.push(Long.valueOf((x == y) ? 1 : 0));376break;377case DLS_CDL_NOT:378x = stack.pop();379y = stack.pop();380stack.push(Long.valueOf((x == 0) ? 1 : 0));381break;382case DLS_CDL_CONST:383stack.push(Long.valueOf(riff.readUnsignedInt()));384break;385case DLS_CDL_QUERY:386uuid = DLSID.read(riff);387stack.push(cdlQuery(uuid));388break;389case DLS_CDL_QUERYSUPPORTED:390uuid = DLSID.read(riff);391stack.push(Long.valueOf(cdlIsQuerySupported(uuid) ? 1 : 0));392break;393default:394break;395}396}397if (stack.isEmpty())398return false;399400return stack.pop() == 1;401}402403private void readInfoChunk(RIFFReader riff) throws IOException {404info.name = null;405while (riff.hasNextChunk()) {406RIFFReader chunk = riff.nextChunk();407String format = chunk.getFormat();408if (format.equals("INAM"))409info.name = chunk.readString(chunk.available());410else if (format.equals("ICRD"))411info.creationDate = chunk.readString(chunk.available());412else if (format.equals("IENG"))413info.engineers = chunk.readString(chunk.available());414else if (format.equals("IPRD"))415info.product = chunk.readString(chunk.available());416else if (format.equals("ICOP"))417info.copyright = chunk.readString(chunk.available());418else if (format.equals("ICMT"))419info.comments = chunk.readString(chunk.available());420else if (format.equals("ISFT"))421info.tools = chunk.readString(chunk.available());422else if (format.equals("IARL"))423info.archival_location = chunk.readString(chunk.available());424else if (format.equals("IART"))425info.artist = chunk.readString(chunk.available());426else if (format.equals("ICMS"))427info.commissioned = chunk.readString(chunk.available());428else if (format.equals("IGNR"))429info.genre = chunk.readString(chunk.available());430else if (format.equals("IKEY"))431info.keywords = chunk.readString(chunk.available());432else if (format.equals("IMED"))433info.medium = chunk.readString(chunk.available());434else if (format.equals("ISBJ"))435info.subject = chunk.readString(chunk.available());436else if (format.equals("ISRC"))437info.source = chunk.readString(chunk.available());438else if (format.equals("ISRF"))439info.source_form = chunk.readString(chunk.available());440else if (format.equals("ITCH"))441info.technician = chunk.readString(chunk.available());442}443}444445private void readLinsChunk(RIFFReader riff) throws IOException {446while (riff.hasNextChunk()) {447RIFFReader chunk = riff.nextChunk();448if (chunk.getFormat().equals("LIST")) {449if (chunk.getType().equals("ins "))450readInsChunk(chunk);451}452}453}454455private void readInsChunk(RIFFReader riff) throws IOException {456DLSInstrument instrument = new DLSInstrument(this);457458while (riff.hasNextChunk()) {459RIFFReader chunk = riff.nextChunk();460String format = chunk.getFormat();461if (format.equals("LIST")) {462if (chunk.getType().equals("INFO")) {463readInsInfoChunk(instrument, chunk);464}465if (chunk.getType().equals("lrgn")) {466while (chunk.hasNextChunk()) {467RIFFReader subchunk = chunk.nextChunk();468if (subchunk.getFormat().equals("LIST")) {469if (subchunk.getType().equals("rgn ")) {470DLSRegion split = new DLSRegion();471if (readRgnChunk(split, subchunk))472instrument.getRegions().add(split);473}474if (subchunk.getType().equals("rgn2")) {475// support for DLS level 2 regions476DLSRegion split = new DLSRegion();477if (readRgnChunk(split, subchunk))478instrument.getRegions().add(split);479}480}481}482}483if (chunk.getType().equals("lart")) {484List<DLSModulator> modlist = new ArrayList<DLSModulator>();485while (chunk.hasNextChunk()) {486RIFFReader subchunk = chunk.nextChunk();487if (chunk.getFormat().equals("cdl ")) {488if (!readCdlChunk(chunk)) {489modlist.clear();490break;491}492}493if (subchunk.getFormat().equals("art1"))494readArt1Chunk(modlist, subchunk);495}496instrument.getModulators().addAll(modlist);497}498if (chunk.getType().equals("lar2")) {499// support for DLS level 2 ART500List<DLSModulator> modlist = new ArrayList<DLSModulator>();501while (chunk.hasNextChunk()) {502RIFFReader subchunk = chunk.nextChunk();503if (chunk.getFormat().equals("cdl ")) {504if (!readCdlChunk(chunk)) {505modlist.clear();506break;507}508}509if (subchunk.getFormat().equals("art2"))510readArt2Chunk(modlist, subchunk);511}512instrument.getModulators().addAll(modlist);513}514} else {515if (format.equals("dlid")) {516instrument.guid = new byte[16];517chunk.readFully(instrument.guid);518}519if (format.equals("insh")) {520chunk.readUnsignedInt(); // Read Region Count - ignored521522int bank = chunk.read(); // LSB523bank += (chunk.read() & 127) << 7; // MSB524chunk.read(); // Read Reserved byte525int drumins = chunk.read(); // Drum Instrument526527int id = chunk.read() & 127; // Read only first 7 bits528chunk.read(); // Read Reserved byte529chunk.read(); // Read Reserved byte530chunk.read(); // Read Reserved byte531532instrument.bank = bank;533instrument.preset = (int) id;534instrument.druminstrument = (drumins & 128) > 0;535//System.out.println("bank="+bank+" drumkit="+drumkit536// +" id="+id);537}538539}540}541instruments.add(instrument);542}543544private void readArt1Chunk(List<DLSModulator> modulators, RIFFReader riff)545throws IOException {546long size = riff.readUnsignedInt();547long count = riff.readUnsignedInt();548549if (size - 8 != 0)550riff.skip(size - 8);551552for (int i = 0; i < count; i++) {553DLSModulator modulator = new DLSModulator();554modulator.version = 1;555modulator.source = riff.readUnsignedShort();556modulator.control = riff.readUnsignedShort();557modulator.destination = riff.readUnsignedShort();558modulator.transform = riff.readUnsignedShort();559modulator.scale = riff.readInt();560modulators.add(modulator);561}562}563564private void readArt2Chunk(List<DLSModulator> modulators, RIFFReader riff)565throws IOException {566long size = riff.readUnsignedInt();567long count = riff.readUnsignedInt();568569if (size - 8 != 0)570riff.skip(size - 8);571572for (int i = 0; i < count; i++) {573DLSModulator modulator = new DLSModulator();574modulator.version = 2;575modulator.source = riff.readUnsignedShort();576modulator.control = riff.readUnsignedShort();577modulator.destination = riff.readUnsignedShort();578modulator.transform = riff.readUnsignedShort();579modulator.scale = riff.readInt();580modulators.add(modulator);581}582}583584private Map<DLSRegion, Long> temp_rgnassign = new HashMap<DLSRegion, Long>();585586private boolean readRgnChunk(DLSRegion split, RIFFReader riff)587throws IOException {588while (riff.hasNextChunk()) {589RIFFReader chunk = riff.nextChunk();590String format = chunk.getFormat();591if (format.equals("LIST")) {592if (chunk.getType().equals("lart")) {593List<DLSModulator> modlist = new ArrayList<DLSModulator>();594while (chunk.hasNextChunk()) {595RIFFReader subchunk = chunk.nextChunk();596if (chunk.getFormat().equals("cdl ")) {597if (!readCdlChunk(chunk)) {598modlist.clear();599break;600}601}602if (subchunk.getFormat().equals("art1"))603readArt1Chunk(modlist, subchunk);604}605split.getModulators().addAll(modlist);606}607if (chunk.getType().equals("lar2")) {608// support for DLS level 2 ART609List<DLSModulator> modlist = new ArrayList<DLSModulator>();610while (chunk.hasNextChunk()) {611RIFFReader subchunk = chunk.nextChunk();612if (chunk.getFormat().equals("cdl ")) {613if (!readCdlChunk(chunk)) {614modlist.clear();615break;616}617}618if (subchunk.getFormat().equals("art2"))619readArt2Chunk(modlist, subchunk);620}621split.getModulators().addAll(modlist);622}623} else {624625if (format.equals("cdl ")) {626if (!readCdlChunk(chunk))627return false;628}629if (format.equals("rgnh")) {630split.keyfrom = chunk.readUnsignedShort();631split.keyto = chunk.readUnsignedShort();632split.velfrom = chunk.readUnsignedShort();633split.velto = chunk.readUnsignedShort();634split.options = chunk.readUnsignedShort();635split.exclusiveClass = chunk.readUnsignedShort();636}637if (format.equals("wlnk")) {638split.fusoptions = chunk.readUnsignedShort();639split.phasegroup = chunk.readUnsignedShort();640split.channel = chunk.readUnsignedInt();641long sampleid = chunk.readUnsignedInt();642temp_rgnassign.put(split, sampleid);643}644if (format.equals("wsmp")) {645split.sampleoptions = new DLSSampleOptions();646readWsmpChunk(split.sampleoptions, chunk);647}648}649}650return true;651}652653private void readWsmpChunk(DLSSampleOptions sampleOptions, RIFFReader riff)654throws IOException {655long size = riff.readUnsignedInt();656sampleOptions.unitynote = riff.readUnsignedShort();657sampleOptions.finetune = riff.readShort();658sampleOptions.attenuation = riff.readInt();659sampleOptions.options = riff.readUnsignedInt();660long loops = riff.readInt();661662if (size > 20)663riff.skip(size - 20);664665for (int i = 0; i < loops; i++) {666DLSSampleLoop loop = new DLSSampleLoop();667long size2 = riff.readUnsignedInt();668loop.type = riff.readUnsignedInt();669loop.start = riff.readUnsignedInt();670loop.length = riff.readUnsignedInt();671sampleOptions.loops.add(loop);672if (size2 > 16)673riff.skip(size2 - 16);674}675}676677private void readInsInfoChunk(DLSInstrument dlsinstrument, RIFFReader riff)678throws IOException {679dlsinstrument.info.name = null;680while (riff.hasNextChunk()) {681RIFFReader chunk = riff.nextChunk();682String format = chunk.getFormat();683if (format.equals("INAM")) {684dlsinstrument.info.name = chunk.readString(chunk.available());685} else if (format.equals("ICRD")) {686dlsinstrument.info.creationDate =687chunk.readString(chunk.available());688} else if (format.equals("IENG")) {689dlsinstrument.info.engineers =690chunk.readString(chunk.available());691} else if (format.equals("IPRD")) {692dlsinstrument.info.product = chunk.readString(chunk.available());693} else if (format.equals("ICOP")) {694dlsinstrument.info.copyright =695chunk.readString(chunk.available());696} else if (format.equals("ICMT")) {697dlsinstrument.info.comments =698chunk.readString(chunk.available());699} else if (format.equals("ISFT")) {700dlsinstrument.info.tools = chunk.readString(chunk.available());701} else if (format.equals("IARL")) {702dlsinstrument.info.archival_location =703chunk.readString(chunk.available());704} else if (format.equals("IART")) {705dlsinstrument.info.artist = chunk.readString(chunk.available());706} else if (format.equals("ICMS")) {707dlsinstrument.info.commissioned =708chunk.readString(chunk.available());709} else if (format.equals("IGNR")) {710dlsinstrument.info.genre = chunk.readString(chunk.available());711} else if (format.equals("IKEY")) {712dlsinstrument.info.keywords =713chunk.readString(chunk.available());714} else if (format.equals("IMED")) {715dlsinstrument.info.medium = chunk.readString(chunk.available());716} else if (format.equals("ISBJ")) {717dlsinstrument.info.subject = chunk.readString(chunk.available());718} else if (format.equals("ISRC")) {719dlsinstrument.info.source = chunk.readString(chunk.available());720} else if (format.equals("ISRF")) {721dlsinstrument.info.source_form =722chunk.readString(chunk.available());723} else if (format.equals("ITCH")) {724dlsinstrument.info.technician =725chunk.readString(chunk.available());726}727}728}729730private void readWvplChunk(RIFFReader riff) throws IOException {731while (riff.hasNextChunk()) {732RIFFReader chunk = riff.nextChunk();733if (chunk.getFormat().equals("LIST")) {734if (chunk.getType().equals("wave"))735readWaveChunk(chunk);736}737}738}739740private void readWaveChunk(RIFFReader riff) throws IOException {741DLSSample sample = new DLSSample(this);742743while (riff.hasNextChunk()) {744RIFFReader chunk = riff.nextChunk();745String format = chunk.getFormat();746if (format.equals("LIST")) {747if (chunk.getType().equals("INFO")) {748readWaveInfoChunk(sample, chunk);749}750} else {751if (format.equals("dlid")) {752sample.guid = new byte[16];753chunk.readFully(sample.guid);754}755756if (format.equals("fmt ")) {757int sampleformat = chunk.readUnsignedShort();758if (sampleformat != 1 && sampleformat != 3) {759throw new RIFFInvalidDataException(760"Only PCM samples are supported!");761}762int channels = chunk.readUnsignedShort();763long samplerate = chunk.readUnsignedInt();764// bytes per sec765/* long framerate = */ chunk.readUnsignedInt();766// block align, framesize767int framesize = chunk.readUnsignedShort();768int bits = chunk.readUnsignedShort();769AudioFormat audioformat = null;770if (sampleformat == 1) {771if (bits == 8) {772audioformat = new AudioFormat(773Encoding.PCM_UNSIGNED, samplerate, bits,774channels, framesize, samplerate, false);775} else {776audioformat = new AudioFormat(777Encoding.PCM_SIGNED, samplerate, bits,778channels, framesize, samplerate, false);779}780}781if (sampleformat == 3) {782audioformat = new AudioFormat(783Encoding.PCM_FLOAT, samplerate, bits,784channels, framesize, samplerate, false);785}786787sample.format = audioformat;788}789790if (format.equals("data")) {791if (largeFormat) {792sample.setData(new ModelByteBuffer(sampleFile,793chunk.getFilePointer(), chunk.available()));794} else {795byte[] buffer = new byte[chunk.available()];796// chunk.read(buffer);797sample.setData(buffer);798799int read = 0;800int avail = chunk.available();801while (read != avail) {802if (avail - read > 65536) {803chunk.readFully(buffer, read, 65536);804read += 65536;805} else {806chunk.readFully(buffer, read, avail - read);807read = avail;808}809}810}811}812813if (format.equals("wsmp")) {814sample.sampleoptions = new DLSSampleOptions();815readWsmpChunk(sample.sampleoptions, chunk);816}817}818}819820samples.add(sample);821822}823824private void readWaveInfoChunk(DLSSample dlssample, RIFFReader riff)825throws IOException {826dlssample.info.name = null;827while (riff.hasNextChunk()) {828RIFFReader chunk = riff.nextChunk();829String format = chunk.getFormat();830if (format.equals("INAM")) {831dlssample.info.name = chunk.readString(chunk.available());832} else if (format.equals("ICRD")) {833dlssample.info.creationDate =834chunk.readString(chunk.available());835} else if (format.equals("IENG")) {836dlssample.info.engineers = chunk.readString(chunk.available());837} else if (format.equals("IPRD")) {838dlssample.info.product = chunk.readString(chunk.available());839} else if (format.equals("ICOP")) {840dlssample.info.copyright = chunk.readString(chunk.available());841} else if (format.equals("ICMT")) {842dlssample.info.comments = chunk.readString(chunk.available());843} else if (format.equals("ISFT")) {844dlssample.info.tools = chunk.readString(chunk.available());845} else if (format.equals("IARL")) {846dlssample.info.archival_location =847chunk.readString(chunk.available());848} else if (format.equals("IART")) {849dlssample.info.artist = chunk.readString(chunk.available());850} else if (format.equals("ICMS")) {851dlssample.info.commissioned =852chunk.readString(chunk.available());853} else if (format.equals("IGNR")) {854dlssample.info.genre = chunk.readString(chunk.available());855} else if (format.equals("IKEY")) {856dlssample.info.keywords = chunk.readString(chunk.available());857} else if (format.equals("IMED")) {858dlssample.info.medium = chunk.readString(chunk.available());859} else if (format.equals("ISBJ")) {860dlssample.info.subject = chunk.readString(chunk.available());861} else if (format.equals("ISRC")) {862dlssample.info.source = chunk.readString(chunk.available());863} else if (format.equals("ISRF")) {864dlssample.info.source_form = chunk.readString(chunk.available());865} else if (format.equals("ITCH")) {866dlssample.info.technician = chunk.readString(chunk.available());867}868}869}870871public void save(String name) throws IOException {872writeSoundbank(new RIFFWriter(name, "DLS "));873}874875public void save(File file) throws IOException {876writeSoundbank(new RIFFWriter(file, "DLS "));877}878879public void save(OutputStream out) throws IOException {880writeSoundbank(new RIFFWriter(out, "DLS "));881}882883private void writeSoundbank(RIFFWriter writer) throws IOException {884RIFFWriter colh_chunk = writer.writeChunk("colh");885colh_chunk.writeUnsignedInt(instruments.size());886887if (major != -1 && minor != -1) {888RIFFWriter vers_chunk = writer.writeChunk("vers");889vers_chunk.writeUnsignedInt(major);890vers_chunk.writeUnsignedInt(minor);891}892893writeInstruments(writer.writeList("lins"));894895RIFFWriter ptbl = writer.writeChunk("ptbl");896ptbl.writeUnsignedInt(8);897ptbl.writeUnsignedInt(samples.size());898long ptbl_offset = writer.getFilePointer();899for (int i = 0; i < samples.size(); i++)900ptbl.writeUnsignedInt(0);901902RIFFWriter wvpl = writer.writeList("wvpl");903long off = wvpl.getFilePointer();904List<Long> offsettable = new ArrayList<Long>();905for (DLSSample sample : samples) {906offsettable.add(Long.valueOf(wvpl.getFilePointer() - off));907writeSample(wvpl.writeList("wave"), sample);908}909910// small cheat, we are going to rewrite data back in wvpl911long bak = writer.getFilePointer();912writer.seek(ptbl_offset);913writer.setWriteOverride(true);914for (Long offset : offsettable)915writer.writeUnsignedInt(offset.longValue());916writer.setWriteOverride(false);917writer.seek(bak);918919writeInfo(writer.writeList("INFO"), info);920921writer.close();922}923924private void writeSample(RIFFWriter writer, DLSSample sample)925throws IOException {926927AudioFormat audioformat = sample.getFormat();928929Encoding encoding = audioformat.getEncoding();930float sampleRate = audioformat.getSampleRate();931int sampleSizeInBits = audioformat.getSampleSizeInBits();932int channels = audioformat.getChannels();933int frameSize = audioformat.getFrameSize();934float frameRate = audioformat.getFrameRate();935boolean bigEndian = audioformat.isBigEndian();936937boolean convert_needed = false;938939if (audioformat.getSampleSizeInBits() == 8) {940if (!encoding.equals(Encoding.PCM_UNSIGNED)) {941encoding = Encoding.PCM_UNSIGNED;942convert_needed = true;943}944} else {945if (!encoding.equals(Encoding.PCM_SIGNED)) {946encoding = Encoding.PCM_SIGNED;947convert_needed = true;948}949if (bigEndian) {950bigEndian = false;951convert_needed = true;952}953}954955if (convert_needed) {956audioformat = new AudioFormat(encoding, sampleRate,957sampleSizeInBits, channels, frameSize, frameRate, bigEndian);958}959960// fmt961RIFFWriter fmt_chunk = writer.writeChunk("fmt ");962int sampleformat = 0;963if (audioformat.getEncoding().equals(Encoding.PCM_UNSIGNED))964sampleformat = 1;965else if (audioformat.getEncoding().equals(Encoding.PCM_SIGNED))966sampleformat = 1;967else if (audioformat.getEncoding().equals(Encoding.PCM_FLOAT))968sampleformat = 3;969970fmt_chunk.writeUnsignedShort(sampleformat);971fmt_chunk.writeUnsignedShort(audioformat.getChannels());972fmt_chunk.writeUnsignedInt((long) audioformat.getSampleRate());973long srate = ((long)audioformat.getFrameRate())*audioformat.getFrameSize();974fmt_chunk.writeUnsignedInt(srate);975fmt_chunk.writeUnsignedShort(audioformat.getFrameSize());976fmt_chunk.writeUnsignedShort(audioformat.getSampleSizeInBits());977fmt_chunk.write(0);978fmt_chunk.write(0);979980writeSampleOptions(writer.writeChunk("wsmp"), sample.sampleoptions);981982if (convert_needed) {983RIFFWriter data_chunk = writer.writeChunk("data");984AudioInputStream stream = AudioSystem.getAudioInputStream(985audioformat, (AudioInputStream)sample.getData());986byte[] buff = new byte[1024];987int ret;988while ((ret = stream.read(buff)) != -1) {989data_chunk.write(buff, 0, ret);990}991} else {992RIFFWriter data_chunk = writer.writeChunk("data");993ModelByteBuffer databuff = sample.getDataBuffer();994databuff.writeTo(data_chunk);995/*996data_chunk.write(databuff.array(),997databuff.arrayOffset(),998databuff.capacity());999*/1000}10011002writeInfo(writer.writeList("INFO"), sample.info);1003}10041005private void writeInstruments(RIFFWriter writer) throws IOException {1006for (DLSInstrument instrument : instruments) {1007writeInstrument(writer.writeList("ins "), instrument);1008}1009}10101011private void writeInstrument(RIFFWriter writer, DLSInstrument instrument)1012throws IOException {10131014int art1_count = 0;1015int art2_count = 0;1016for (DLSModulator modulator : instrument.getModulators()) {1017if (modulator.version == 1)1018art1_count++;1019if (modulator.version == 2)1020art2_count++;1021}1022for (DLSRegion region : instrument.regions) {1023for (DLSModulator modulator : region.getModulators()) {1024if (modulator.version == 1)1025art1_count++;1026if (modulator.version == 2)1027art2_count++;1028}1029}10301031int version = 1;1032if (art2_count > 0)1033version = 2;10341035RIFFWriter insh_chunk = writer.writeChunk("insh");1036insh_chunk.writeUnsignedInt(instrument.getRegions().size());1037insh_chunk.writeUnsignedInt(instrument.bank +1038(instrument.druminstrument ? 2147483648L : 0));1039insh_chunk.writeUnsignedInt(instrument.preset);10401041RIFFWriter lrgn = writer.writeList("lrgn");1042for (DLSRegion region: instrument.regions)1043writeRegion(lrgn, region, version);10441045writeArticulators(writer, instrument.getModulators());10461047writeInfo(writer.writeList("INFO"), instrument.info);10481049}10501051private void writeArticulators(RIFFWriter writer,1052List<DLSModulator> modulators) throws IOException {1053int art1_count = 0;1054int art2_count = 0;1055for (DLSModulator modulator : modulators) {1056if (modulator.version == 1)1057art1_count++;1058if (modulator.version == 2)1059art2_count++;1060}1061if (art1_count > 0) {1062RIFFWriter lar1 = writer.writeList("lart");1063RIFFWriter art1 = lar1.writeChunk("art1");1064art1.writeUnsignedInt(8);1065art1.writeUnsignedInt(art1_count);1066for (DLSModulator modulator : modulators) {1067if (modulator.version == 1) {1068art1.writeUnsignedShort(modulator.source);1069art1.writeUnsignedShort(modulator.control);1070art1.writeUnsignedShort(modulator.destination);1071art1.writeUnsignedShort(modulator.transform);1072art1.writeInt(modulator.scale);1073}1074}1075}1076if (art2_count > 0) {1077RIFFWriter lar2 = writer.writeList("lar2");1078RIFFWriter art2 = lar2.writeChunk("art2");1079art2.writeUnsignedInt(8);1080art2.writeUnsignedInt(art2_count);1081for (DLSModulator modulator : modulators) {1082if (modulator.version == 2) {1083art2.writeUnsignedShort(modulator.source);1084art2.writeUnsignedShort(modulator.control);1085art2.writeUnsignedShort(modulator.destination);1086art2.writeUnsignedShort(modulator.transform);1087art2.writeInt(modulator.scale);1088}1089}1090}1091}10921093private void writeRegion(RIFFWriter writer, DLSRegion region, int version)1094throws IOException {1095RIFFWriter rgns = null;1096if (version == 1)1097rgns = writer.writeList("rgn ");1098if (version == 2)1099rgns = writer.writeList("rgn2");1100if (rgns == null)1101return;11021103RIFFWriter rgnh = rgns.writeChunk("rgnh");1104rgnh.writeUnsignedShort(region.keyfrom);1105rgnh.writeUnsignedShort(region.keyto);1106rgnh.writeUnsignedShort(region.velfrom);1107rgnh.writeUnsignedShort(region.velto);1108rgnh.writeUnsignedShort(region.options);1109rgnh.writeUnsignedShort(region.exclusiveClass);11101111if (region.sampleoptions != null)1112writeSampleOptions(rgns.writeChunk("wsmp"), region.sampleoptions);11131114if (region.sample != null) {1115if (samples.indexOf(region.sample) != -1) {1116RIFFWriter wlnk = rgns.writeChunk("wlnk");1117wlnk.writeUnsignedShort(region.fusoptions);1118wlnk.writeUnsignedShort(region.phasegroup);1119wlnk.writeUnsignedInt(region.channel);1120wlnk.writeUnsignedInt(samples.indexOf(region.sample));1121}1122}1123writeArticulators(rgns, region.getModulators());1124rgns.close();1125}11261127private void writeSampleOptions(RIFFWriter wsmp,1128DLSSampleOptions sampleoptions) throws IOException {1129wsmp.writeUnsignedInt(20);1130wsmp.writeUnsignedShort(sampleoptions.unitynote);1131wsmp.writeShort(sampleoptions.finetune);1132wsmp.writeInt(sampleoptions.attenuation);1133wsmp.writeUnsignedInt(sampleoptions.options);1134wsmp.writeInt(sampleoptions.loops.size());11351136for (DLSSampleLoop loop : sampleoptions.loops) {1137wsmp.writeUnsignedInt(16);1138wsmp.writeUnsignedInt(loop.type);1139wsmp.writeUnsignedInt(loop.start);1140wsmp.writeUnsignedInt(loop.length);1141}1142}11431144private void writeInfoStringChunk(RIFFWriter writer,1145String name, String value) throws IOException {1146if (value == null)1147return;1148RIFFWriter chunk = writer.writeChunk(name);1149chunk.writeString(value);1150int len = value.getBytes("ascii").length;1151chunk.write(0);1152len++;1153if (len % 2 != 0)1154chunk.write(0);1155}11561157private void writeInfo(RIFFWriter writer, DLSInfo info) throws IOException {1158writeInfoStringChunk(writer, "INAM", info.name);1159writeInfoStringChunk(writer, "ICRD", info.creationDate);1160writeInfoStringChunk(writer, "IENG", info.engineers);1161writeInfoStringChunk(writer, "IPRD", info.product);1162writeInfoStringChunk(writer, "ICOP", info.copyright);1163writeInfoStringChunk(writer, "ICMT", info.comments);1164writeInfoStringChunk(writer, "ISFT", info.tools);1165writeInfoStringChunk(writer, "IARL", info.archival_location);1166writeInfoStringChunk(writer, "IART", info.artist);1167writeInfoStringChunk(writer, "ICMS", info.commissioned);1168writeInfoStringChunk(writer, "IGNR", info.genre);1169writeInfoStringChunk(writer, "IKEY", info.keywords);1170writeInfoStringChunk(writer, "IMED", info.medium);1171writeInfoStringChunk(writer, "ISBJ", info.subject);1172writeInfoStringChunk(writer, "ISRC", info.source);1173writeInfoStringChunk(writer, "ISRF", info.source_form);1174writeInfoStringChunk(writer, "ITCH", info.technician);1175}11761177public DLSInfo getInfo() {1178return info;1179}11801181public String getName() {1182return info.name;1183}11841185public String getVersion() {1186return major + "." + minor;1187}11881189public String getVendor() {1190return info.engineers;1191}11921193public String getDescription() {1194return info.comments;1195}11961197public void setName(String s) {1198info.name = s;1199}12001201public void setVendor(String s) {1202info.engineers = s;1203}12041205public void setDescription(String s) {1206info.comments = s;1207}12081209public SoundbankResource[] getResources() {1210SoundbankResource[] resources = new SoundbankResource[samples.size()];1211int j = 0;1212for (int i = 0; i < samples.size(); i++)1213resources[j++] = samples.get(i);1214return resources;1215}12161217public DLSInstrument[] getInstruments() {1218DLSInstrument[] inslist_array =1219instruments.toArray(new DLSInstrument[instruments.size()]);1220Arrays.sort(inslist_array, new ModelInstrumentComparator());1221return inslist_array;1222}12231224public DLSSample[] getSamples() {1225return samples.toArray(new DLSSample[samples.size()]);1226}12271228public Instrument getInstrument(Patch patch) {1229int program = patch.getProgram();1230int bank = patch.getBank();1231boolean percussion = false;1232if (patch instanceof ModelPatch)1233percussion = ((ModelPatch) patch).isPercussion();1234for (Instrument instrument : instruments) {1235Patch patch2 = instrument.getPatch();1236int program2 = patch2.getProgram();1237int bank2 = patch2.getBank();1238if (program == program2 && bank == bank2) {1239boolean percussion2 = false;1240if (patch2 instanceof ModelPatch)1241percussion2 = ((ModelPatch) patch2).isPercussion();1242if (percussion == percussion2)1243return instrument;1244}1245}1246return null;1247}12481249public void addResource(SoundbankResource resource) {1250if (resource instanceof DLSInstrument)1251instruments.add((DLSInstrument) resource);1252if (resource instanceof DLSSample)1253samples.add((DLSSample) resource);1254}12551256public void removeResource(SoundbankResource resource) {1257if (resource instanceof DLSInstrument)1258instruments.remove((DLSInstrument) resource);1259if (resource instanceof DLSSample)1260samples.remove((DLSSample) resource);1261}12621263public void addInstrument(DLSInstrument resource) {1264instruments.add(resource);1265}12661267public void removeInstrument(DLSInstrument resource) {1268instruments.remove(resource);1269}12701271public long getMajor() {1272return major;1273}12741275public void setMajor(long major) {1276this.major = major;1277}12781279public long getMinor() {1280return minor;1281}12821283public void setMinor(long minor) {1284this.minor = minor;1285}1286}128712881289