Save This Page
Home » openjdk-7 » com.sun.media » sound » [javadoc | source]
    1   /*
    2    * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   package com.sun.media.sound;
   26   
   27   import java.io.File;
   28   import java.io.FileInputStream;
   29   import java.io.IOException;
   30   import java.io.InputStream;
   31   import java.io.OutputStream;
   32   import java.net.URL;
   33   import java.util.ArrayList;
   34   import java.util.Arrays;
   35   import java.util.Iterator;
   36   import java.util.List;
   37   import java.util.Map;
   38   
   39   import javax.sound.midi.Instrument;
   40   import javax.sound.midi.Patch;
   41   import javax.sound.midi.Soundbank;
   42   import javax.sound.midi.SoundbankResource;
   43   
   44   /**
   45    * A SoundFont 2.04 soundbank reader.
   46    *
   47    * Based on SoundFont 2.04 specification from:
   48    * <p>  http://developer.creative.com <br>
   49    *      http://www.soundfont.com/ ;
   50    *
   51    * @author Karl Helgason
   52    */
   53   public class SF2Soundbank implements Soundbank {
   54   
   55       // version of the Sound Font RIFF file
   56       protected int major = 2;
   57       protected int minor = 1;
   58       // target Sound Engine
   59       protected String targetEngine = "EMU8000";
   60       // Sound Font Bank Name
   61       protected String name = "untitled";
   62       // Sound ROM Name
   63       protected String romName = null;
   64       // Sound ROM Version
   65       protected int romVersionMajor = -1;
   66       protected int romVersionMinor = -1;
   67       // Date of Creation of the Bank
   68       protected String creationDate = null;
   69       // Sound Designers and Engineers for the Bank
   70       protected String engineers = null;
   71       // Product for which the Bank was intended
   72       protected String product = null;
   73       // Copyright message
   74       protected String copyright = null;
   75       // Comments
   76       protected String comments = null;
   77       // The SoundFont tools used to create and alter the bank
   78       protected String tools = null;
   79       // The Sample Data loaded from the SoundFont
   80       private ModelByteBuffer sampleData = null;
   81       private ModelByteBuffer sampleData24 = null;
   82       private File sampleFile = null;
   83       private boolean largeFormat = false;
   84       private List<SF2Instrument> instruments = new ArrayList<SF2Instrument>();
   85       private List<SF2Layer> layers = new ArrayList<SF2Layer>();
   86       private List<SF2Sample> samples = new ArrayList<SF2Sample>();
   87   
   88       public SF2Soundbank() {
   89       }
   90   
   91       public SF2Soundbank(URL url) throws IOException {
   92   
   93           InputStream is = url.openStream();
   94           try {
   95               readSoundbank(is);
   96           } finally {
   97               is.close();
   98           }
   99       }
  100   
  101       public SF2Soundbank(File file) throws IOException {
  102           largeFormat = true;
  103           sampleFile = file;
  104           InputStream is = new FileInputStream(file);
  105           try {
  106               readSoundbank(is);
  107           } finally {
  108               is.close();
  109           }
  110       }
  111   
  112       public SF2Soundbank(InputStream inputstream) throws IOException {
  113           readSoundbank(inputstream);
  114       }
  115   
  116       private void readSoundbank(InputStream inputstream) throws IOException {
  117           RIFFReader riff = new RIFFReader(inputstream);
  118           if (!riff.getFormat().equals("RIFF")) {
  119               throw new RIFFInvalidFormatException(
  120                       "Input stream is not a valid RIFF stream!");
  121           }
  122           if (!riff.getType().equals("sfbk")) {
  123               throw new RIFFInvalidFormatException(
  124                       "Input stream is not a valid SoundFont!");
  125           }
  126           while (riff.hasNextChunk()) {
  127               RIFFReader chunk = riff.nextChunk();
  128               if (chunk.getFormat().equals("LIST")) {
  129                   if (chunk.getType().equals("INFO"))
  130                       readInfoChunk(chunk);
  131                   if (chunk.getType().equals("sdta"))
  132                       readSdtaChunk(chunk);
  133                   if (chunk.getType().equals("pdta"))
  134                       readPdtaChunk(chunk);
  135               }
  136           }
  137       }
  138   
  139       private void readInfoChunk(RIFFReader riff) throws IOException {
  140           while (riff.hasNextChunk()) {
  141               RIFFReader chunk = riff.nextChunk();
  142               String format = chunk.getFormat();
  143               if (format.equals("ifil")) {
  144                   major = chunk.readUnsignedShort();
  145                   minor = chunk.readUnsignedShort();
  146               } else if (format.equals("isng")) {
  147                   this.targetEngine = chunk.readString(chunk.available());
  148               } else if (format.equals("INAM")) {
  149                   this.name = chunk.readString(chunk.available());
  150               } else if (format.equals("irom")) {
  151                   this.romName = chunk.readString(chunk.available());
  152               } else if (format.equals("iver")) {
  153                   romVersionMajor = chunk.readUnsignedShort();
  154                   romVersionMinor = chunk.readUnsignedShort();
  155               } else if (format.equals("ICRD")) {
  156                   this.creationDate = chunk.readString(chunk.available());
  157               } else if (format.equals("IENG")) {
  158                   this.engineers = chunk.readString(chunk.available());
  159               } else if (format.equals("IPRD")) {
  160                   this.product = chunk.readString(chunk.available());
  161               } else if (format.equals("ICOP")) {
  162                   this.copyright = chunk.readString(chunk.available());
  163               } else if (format.equals("ICMT")) {
  164                   this.comments = chunk.readString(chunk.available());
  165               } else if (format.equals("ISFT")) {
  166                   this.tools = chunk.readString(chunk.available());
  167               }
  168   
  169           }
  170       }
  171   
  172       private void readSdtaChunk(RIFFReader riff) throws IOException {
  173           while (riff.hasNextChunk()) {
  174               RIFFReader chunk = riff.nextChunk();
  175               if (chunk.getFormat().equals("smpl")) {
  176                   if (!largeFormat) {
  177                       byte[] sampleData = new byte[chunk.available()];
  178   
  179                       int read = 0;
  180                       int avail = chunk.available();
  181                       while (read != avail) {
  182                           if (avail - read > 65536) {
  183                               chunk.readFully(sampleData, read, 65536);
  184                               read += 65536;
  185                           } else {
  186                               chunk.readFully(sampleData, read, avail - read);
  187                               read = avail;
  188                           }
  189   
  190                       }
  191                       this.sampleData = new ModelByteBuffer(sampleData);
  192                       //chunk.read(sampleData);
  193                   } else {
  194                       this.sampleData = new ModelByteBuffer(sampleFile,
  195                               chunk.getFilePointer(), chunk.available());
  196                   }
  197               }
  198               if (chunk.getFormat().equals("sm24")) {
  199                   if (!largeFormat) {
  200                       byte[] sampleData24 = new byte[chunk.available()];
  201                       //chunk.read(sampleData24);
  202   
  203                       int read = 0;
  204                       int avail = chunk.available();
  205                       while (read != avail) {
  206                           if (avail - read > 65536) {
  207                               chunk.readFully(sampleData24, read, 65536);
  208                               read += 65536;
  209                           } else {
  210                               chunk.readFully(sampleData24, read, avail - read);
  211                               read = avail;
  212                           }
  213   
  214                       }
  215                       this.sampleData24 = new ModelByteBuffer(sampleData24);
  216                   } else {
  217                       this.sampleData24 = new ModelByteBuffer(sampleFile,
  218                               chunk.getFilePointer(), chunk.available());
  219                   }
  220   
  221               }
  222           }
  223       }
  224   
  225       private void readPdtaChunk(RIFFReader riff) throws IOException {
  226   
  227           List<SF2Instrument> presets = new ArrayList<SF2Instrument>();
  228           List<Integer> presets_bagNdx = new ArrayList<Integer>();
  229           List<SF2InstrumentRegion> presets_splits_gen
  230                   = new ArrayList<SF2InstrumentRegion>();
  231           List<SF2InstrumentRegion> presets_splits_mod
  232                   = new ArrayList<SF2InstrumentRegion>();
  233   
  234           List<SF2Layer> instruments = new ArrayList<SF2Layer>();
  235           List<Integer> instruments_bagNdx = new ArrayList<Integer>();
  236           List<SF2LayerRegion> instruments_splits_gen
  237                   = new ArrayList<SF2LayerRegion>();
  238           List<SF2LayerRegion> instruments_splits_mod
  239                   = new ArrayList<SF2LayerRegion>();
  240   
  241           while (riff.hasNextChunk()) {
  242               RIFFReader chunk = riff.nextChunk();
  243               String format = chunk.getFormat();
  244               if (format.equals("phdr")) {
  245                   // Preset Header / Instrument
  246                   if (chunk.available() % 38 != 0)
  247                       throw new RIFFInvalidDataException();
  248                   int count = chunk.available() / 38;
  249                   for (int i = 0; i < count; i++) {
  250                       SF2Instrument preset = new SF2Instrument(this);
  251                       preset.name = chunk.readString(20);
  252                       preset.preset = chunk.readUnsignedShort();
  253                       preset.bank = chunk.readUnsignedShort();
  254                       presets_bagNdx.add(chunk.readUnsignedShort());
  255                       preset.library = chunk.readUnsignedInt();
  256                       preset.genre = chunk.readUnsignedInt();
  257                       preset.morphology = chunk.readUnsignedInt();
  258                       presets.add(preset);
  259                       if (i != count - 1)
  260                           this.instruments.add(preset);
  261                   }
  262               } else if (format.equals("pbag")) {
  263                   // Preset Zones / Instruments splits
  264                   if (chunk.available() % 4 != 0)
  265                       throw new RIFFInvalidDataException();
  266                   int count = chunk.available() / 4;
  267   
  268                   // Skip first record
  269                   {
  270                       int gencount = chunk.readUnsignedShort();
  271                       int modcount = chunk.readUnsignedShort();
  272                       while (presets_splits_gen.size() < gencount)
  273                           presets_splits_gen.add(null);
  274                       while (presets_splits_mod.size() < modcount)
  275                           presets_splits_mod.add(null);
  276                       count--;
  277                   }
  278   
  279                   int offset = presets_bagNdx.get(0);
  280                   // Offset should be 0 (but just case)
  281                   for (int i = 0; i < offset; i++) {
  282                       if (count == 0)
  283                           throw new RIFFInvalidDataException();
  284                       int gencount = chunk.readUnsignedShort();
  285                       int modcount = chunk.readUnsignedShort();
  286                       while (presets_splits_gen.size() < gencount)
  287                           presets_splits_gen.add(null);
  288                       while (presets_splits_mod.size() < modcount)
  289                           presets_splits_mod.add(null);
  290                       count--;
  291                   }
  292   
  293                   for (int i = 0; i < presets_bagNdx.size() - 1; i++) {
  294                       int zone_count = presets_bagNdx.get(i + 1)
  295                                        - presets_bagNdx.get(i);
  296                       SF2Instrument preset = presets.get(i);
  297                       for (int ii = 0; ii < zone_count; ii++) {
  298                           if (count == 0)
  299                               throw new RIFFInvalidDataException();
  300                           int gencount = chunk.readUnsignedShort();
  301                           int modcount = chunk.readUnsignedShort();
  302                           SF2InstrumentRegion split = new SF2InstrumentRegion();
  303                           preset.regions.add(split);
  304                           while (presets_splits_gen.size() < gencount)
  305                               presets_splits_gen.add(split);
  306                           while (presets_splits_mod.size() < modcount)
  307                               presets_splits_mod.add(split);
  308                           count--;
  309                       }
  310                   }
  311               } else if (format.equals("pmod")) {
  312                   // Preset Modulators / Split Modulators
  313                   for (int i = 0; i < presets_splits_mod.size(); i++) {
  314                       SF2Modulator modulator = new SF2Modulator();
  315                       modulator.sourceOperator = chunk.readUnsignedShort();
  316                       modulator.destinationOperator = chunk.readUnsignedShort();
  317                       modulator.amount = chunk.readShort();
  318                       modulator.amountSourceOperator = chunk.readUnsignedShort();
  319                       modulator.transportOperator = chunk.readUnsignedShort();
  320                       SF2InstrumentRegion split = presets_splits_mod.get(i);
  321                       if (split != null)
  322                           split.modulators.add(modulator);
  323                   }
  324               } else if (format.equals("pgen")) {
  325                   // Preset Generators / Split Generators
  326                   for (int i = 0; i < presets_splits_gen.size(); i++) {
  327                       int operator = chunk.readUnsignedShort();
  328                       short amount = chunk.readShort();
  329                       SF2InstrumentRegion split = presets_splits_gen.get(i);
  330                       if (split != null)
  331                           split.generators.put(operator, amount);
  332                   }
  333               } else if (format.equals("inst")) {
  334                   // Instrument Header / Layers
  335                   if (chunk.available() % 22 != 0)
  336                       throw new RIFFInvalidDataException();
  337                   int count = chunk.available() / 22;
  338                   for (int i = 0; i < count; i++) {
  339                       SF2Layer layer = new SF2Layer(this);
  340                       layer.name = chunk.readString(20);
  341                       instruments_bagNdx.add(chunk.readUnsignedShort());
  342                       instruments.add(layer);
  343                       if (i != count - 1)
  344                           this.layers.add(layer);
  345                   }
  346               } else if (format.equals("ibag")) {
  347                   // Instrument Zones / Layer splits
  348                   if (chunk.available() % 4 != 0)
  349                       throw new RIFFInvalidDataException();
  350                   int count = chunk.available() / 4;
  351   
  352                   // Skip first record
  353                   {
  354                       int gencount = chunk.readUnsignedShort();
  355                       int modcount = chunk.readUnsignedShort();
  356                       while (instruments_splits_gen.size() < gencount)
  357                           instruments_splits_gen.add(null);
  358                       while (instruments_splits_mod.size() < modcount)
  359                           instruments_splits_mod.add(null);
  360                       count--;
  361                   }
  362   
  363                   int offset = instruments_bagNdx.get(0);
  364                   // Offset should be 0 (but just case)
  365                   for (int i = 0; i < offset; i++) {
  366                       if (count == 0)
  367                           throw new RIFFInvalidDataException();
  368                       int gencount = chunk.readUnsignedShort();
  369                       int modcount = chunk.readUnsignedShort();
  370                       while (instruments_splits_gen.size() < gencount)
  371                           instruments_splits_gen.add(null);
  372                       while (instruments_splits_mod.size() < modcount)
  373                           instruments_splits_mod.add(null);
  374                       count--;
  375                   }
  376   
  377                   for (int i = 0; i < instruments_bagNdx.size() - 1; i++) {
  378                       int zone_count = instruments_bagNdx.get(i + 1) - instruments_bagNdx.get(i);
  379                       SF2Layer layer = layers.get(i);
  380                       for (int ii = 0; ii < zone_count; ii++) {
  381                           if (count == 0)
  382                               throw new RIFFInvalidDataException();
  383                           int gencount = chunk.readUnsignedShort();
  384                           int modcount = chunk.readUnsignedShort();
  385                           SF2LayerRegion split = new SF2LayerRegion();
  386                           layer.regions.add(split);
  387                           while (instruments_splits_gen.size() < gencount)
  388                               instruments_splits_gen.add(split);
  389                           while (instruments_splits_mod.size() < modcount)
  390                               instruments_splits_mod.add(split);
  391                           count--;
  392                       }
  393                   }
  394   
  395               } else if (format.equals("imod")) {
  396                   // Instrument Modulators / Split Modulators
  397                   for (int i = 0; i < instruments_splits_mod.size(); i++) {
  398                       SF2Modulator modulator = new SF2Modulator();
  399                       modulator.sourceOperator = chunk.readUnsignedShort();
  400                       modulator.destinationOperator = chunk.readUnsignedShort();
  401                       modulator.amount = chunk.readShort();
  402                       modulator.amountSourceOperator = chunk.readUnsignedShort();
  403                       modulator.transportOperator = chunk.readUnsignedShort();
  404                       SF2LayerRegion split = instruments_splits_gen.get(i);
  405                       if (split != null)
  406                           split.modulators.add(modulator);
  407                   }
  408               } else if (format.equals("igen")) {
  409                   // Instrument Generators / Split Generators
  410                   for (int i = 0; i < instruments_splits_gen.size(); i++) {
  411                       int operator = chunk.readUnsignedShort();
  412                       short amount = chunk.readShort();
  413                       SF2LayerRegion split = instruments_splits_gen.get(i);
  414                       if (split != null)
  415                           split.generators.put(operator, amount);
  416                   }
  417               } else if (format.equals("shdr")) {
  418                   // Sample Headers
  419                   if (chunk.available() % 46 != 0)
  420                       throw new RIFFInvalidDataException();
  421                   int count = chunk.available() / 46;
  422                   for (int i = 0; i < count; i++) {
  423                       SF2Sample sample = new SF2Sample(this);
  424                       sample.name = chunk.readString(20);
  425                       long start = chunk.readUnsignedInt();
  426                       long end = chunk.readUnsignedInt();
  427                       sample.data = sampleData.subbuffer(start * 2, end * 2, true);
  428                       if (sampleData24 != null)
  429                           sample.data24 = sampleData24.subbuffer(start, end, true);
  430                       /*
  431                       sample.data = new ModelByteBuffer(sampleData, (int)(start*2),
  432                               (int)((end - start)*2));
  433                       if (sampleData24 != null)
  434                           sample.data24 = new ModelByteBuffer(sampleData24,
  435                                   (int)start, (int)(end - start));
  436                        */
  437                       sample.startLoop = chunk.readUnsignedInt() - start;
  438                       sample.endLoop = chunk.readUnsignedInt() - start;
  439                       if (sample.startLoop < 0)
  440                           sample.startLoop = -1;
  441                       if (sample.endLoop < 0)
  442                           sample.endLoop = -1;
  443                       sample.sampleRate = chunk.readUnsignedInt();
  444                       sample.originalPitch = chunk.readUnsignedByte();
  445                       sample.pitchCorrection = chunk.readByte();
  446                       sample.sampleLink = chunk.readUnsignedShort();
  447                       sample.sampleType = chunk.readUnsignedShort();
  448                       if (i != count - 1)
  449                           this.samples.add(sample);
  450                   }
  451               }
  452           }
  453   
  454           Iterator<SF2Layer> liter = this.layers.iterator();
  455           while (liter.hasNext()) {
  456               SF2Layer layer = liter.next();
  457               Iterator<SF2LayerRegion> siter = layer.regions.iterator();
  458               SF2Region globalsplit = null;
  459               while (siter.hasNext()) {
  460                   SF2LayerRegion split = siter.next();
  461                   if (split.generators.get(SF2LayerRegion.GENERATOR_SAMPLEID) != null) {
  462                       int sampleid = split.generators.get(
  463                               SF2LayerRegion.GENERATOR_SAMPLEID);
  464                       split.generators.remove(SF2LayerRegion.GENERATOR_SAMPLEID);
  465                       split.sample = samples.get(sampleid);
  466                   } else {
  467                       globalsplit = split;
  468                   }
  469               }
  470               if (globalsplit != null) {
  471                   layer.getRegions().remove(globalsplit);
  472                   SF2GlobalRegion gsplit = new SF2GlobalRegion();
  473                   gsplit.generators = globalsplit.generators;
  474                   gsplit.modulators = globalsplit.modulators;
  475                   layer.setGlobalZone(gsplit);
  476               }
  477           }
  478   
  479   
  480           Iterator<SF2Instrument> iiter = this.instruments.iterator();
  481           while (iiter.hasNext()) {
  482               SF2Instrument instrument = iiter.next();
  483               Iterator<SF2InstrumentRegion> siter = instrument.regions.iterator();
  484               SF2Region globalsplit = null;
  485               while (siter.hasNext()) {
  486                   SF2InstrumentRegion split = siter.next();
  487                   if (split.generators.get(SF2LayerRegion.GENERATOR_INSTRUMENT) != null) {
  488                       int instrumentid = split.generators.get(
  489                               SF2InstrumentRegion.GENERATOR_INSTRUMENT);
  490                       split.generators.remove(SF2LayerRegion.GENERATOR_INSTRUMENT);
  491                       split.layer = layers.get(instrumentid);
  492                   } else {
  493                       globalsplit = split;
  494                   }
  495               }
  496   
  497               if (globalsplit != null) {
  498                   instrument.getRegions().remove(globalsplit);
  499                   SF2GlobalRegion gsplit = new SF2GlobalRegion();
  500                   gsplit.generators = globalsplit.generators;
  501                   gsplit.modulators = globalsplit.modulators;
  502                   instrument.setGlobalZone(gsplit);
  503               }
  504           }
  505   
  506       }
  507   
  508       public void save(String name) throws IOException {
  509           writeSoundbank(new RIFFWriter(name, "sfbk"));
  510       }
  511   
  512       public void save(File file) throws IOException {
  513           writeSoundbank(new RIFFWriter(file, "sfbk"));
  514       }
  515   
  516       public void save(OutputStream out) throws IOException {
  517           writeSoundbank(new RIFFWriter(out, "sfbk"));
  518       }
  519   
  520       private void writeSoundbank(RIFFWriter writer) throws IOException {
  521           writeInfo(writer.writeList("INFO"));
  522           writeSdtaChunk(writer.writeList("sdta"));
  523           writePdtaChunk(writer.writeList("pdta"));
  524           writer.close();
  525       }
  526   
  527       private void writeInfoStringChunk(RIFFWriter writer, String name,
  528               String value) throws IOException {
  529           if (value == null)
  530               return;
  531           RIFFWriter chunk = writer.writeChunk(name);
  532           chunk.writeString(value);
  533           int len = value.getBytes("ascii").length;
  534           chunk.write(0);
  535           len++;
  536           if (len % 2 != 0)
  537               chunk.write(0);
  538       }
  539   
  540       private void writeInfo(RIFFWriter writer) throws IOException {
  541           if (this.targetEngine == null)
  542               this.targetEngine = "EMU8000";
  543           if (this.name == null)
  544               this.name = "";
  545   
  546           RIFFWriter ifil_chunk = writer.writeChunk("ifil");
  547           ifil_chunk.writeUnsignedShort(this.major);
  548           ifil_chunk.writeUnsignedShort(this.minor);
  549           writeInfoStringChunk(writer, "isng", this.targetEngine);
  550           writeInfoStringChunk(writer, "INAM", this.name);
  551           writeInfoStringChunk(writer, "irom", this.romName);
  552           if (romVersionMajor != -1) {
  553               RIFFWriter iver_chunk = writer.writeChunk("iver");
  554               iver_chunk.writeUnsignedShort(this.romVersionMajor);
  555               iver_chunk.writeUnsignedShort(this.romVersionMinor);
  556           }
  557           writeInfoStringChunk(writer, "ICRD", this.creationDate);
  558           writeInfoStringChunk(writer, "IENG", this.engineers);
  559           writeInfoStringChunk(writer, "IPRD", this.product);
  560           writeInfoStringChunk(writer, "ICOP", this.copyright);
  561           writeInfoStringChunk(writer, "ICMT", this.comments);
  562           writeInfoStringChunk(writer, "ISFT", this.tools);
  563   
  564           writer.close();
  565       }
  566   
  567       private void writeSdtaChunk(RIFFWriter writer) throws IOException {
  568   
  569           byte[] pad = new byte[32];
  570   
  571           RIFFWriter smpl_chunk = writer.writeChunk("smpl");
  572           for (SF2Sample sample : samples) {
  573               ModelByteBuffer data = sample.getDataBuffer();
  574               data.writeTo(smpl_chunk);
  575               /*
  576               smpl_chunk.write(data.array(),
  577               data.arrayOffset(),
  578               data.capacity());
  579                */
  580               smpl_chunk.write(pad);
  581               smpl_chunk.write(pad);
  582           }
  583           if (major < 2)
  584               return;
  585           if (major == 2 && minor < 4)
  586               return;
  587   
  588   
  589           for (SF2Sample sample : samples) {
  590               ModelByteBuffer data24 = sample.getData24Buffer();
  591               if (data24 == null)
  592                   return;
  593           }
  594   
  595           RIFFWriter sm24_chunk = writer.writeChunk("sm24");
  596           for (SF2Sample sample : samples) {
  597               ModelByteBuffer data = sample.getData24Buffer();
  598               data.writeTo(sm24_chunk);
  599               /*
  600               sm24_chunk.write(data.array(),
  601               data.arrayOffset(),
  602               data.capacity());*/
  603               smpl_chunk.write(pad);
  604           }
  605       }
  606   
  607       private void writeModulators(RIFFWriter writer, List<SF2Modulator> modulators)
  608               throws IOException {
  609           for (SF2Modulator modulator : modulators) {
  610               writer.writeUnsignedShort(modulator.sourceOperator);
  611               writer.writeUnsignedShort(modulator.destinationOperator);
  612               writer.writeShort(modulator.amount);
  613               writer.writeUnsignedShort(modulator.amountSourceOperator);
  614               writer.writeUnsignedShort(modulator.transportOperator);
  615           }
  616       }
  617   
  618       private void writeGenerators(RIFFWriter writer, Map<Integer, Short> generators)
  619               throws IOException {
  620           Short keyrange = (Short) generators.get(SF2Region.GENERATOR_KEYRANGE);
  621           Short velrange = (Short) generators.get(SF2Region.GENERATOR_VELRANGE);
  622           if (keyrange != null) {
  623               writer.writeUnsignedShort(SF2Region.GENERATOR_KEYRANGE);
  624               writer.writeShort(keyrange);
  625           }
  626           if (velrange != null) {
  627               writer.writeUnsignedShort(SF2Region.GENERATOR_VELRANGE);
  628               writer.writeShort(velrange);
  629           }
  630           for (Map.Entry<Integer, Short> generator : generators.entrySet()) {
  631               if (generator.getKey() == SF2Region.GENERATOR_KEYRANGE)
  632                   continue;
  633               if (generator.getKey() == SF2Region.GENERATOR_VELRANGE)
  634                   continue;
  635               writer.writeUnsignedShort(generator.getKey());
  636               writer.writeShort(generator.getValue());
  637           }
  638       }
  639   
  640       private void writePdtaChunk(RIFFWriter writer) throws IOException {
  641   
  642           RIFFWriter phdr_chunk = writer.writeChunk("phdr");
  643           int phdr_zone_count = 0;
  644           for (SF2Instrument preset : this.instruments) {
  645               phdr_chunk.writeString(preset.name, 20);
  646               phdr_chunk.writeUnsignedShort(preset.preset);
  647               phdr_chunk.writeUnsignedShort(preset.bank);
  648               phdr_chunk.writeUnsignedShort(phdr_zone_count);
  649               if (preset.getGlobalRegion() != null)
  650                   phdr_zone_count += 1;
  651               phdr_zone_count += preset.getRegions().size();
  652               phdr_chunk.writeUnsignedInt(preset.library);
  653               phdr_chunk.writeUnsignedInt(preset.genre);
  654               phdr_chunk.writeUnsignedInt(preset.morphology);
  655           }
  656           phdr_chunk.writeString("EOP", 20);
  657           phdr_chunk.writeUnsignedShort(0);
  658           phdr_chunk.writeUnsignedShort(0);
  659           phdr_chunk.writeUnsignedShort(phdr_zone_count);
  660           phdr_chunk.writeUnsignedInt(0);
  661           phdr_chunk.writeUnsignedInt(0);
  662           phdr_chunk.writeUnsignedInt(0);
  663   
  664   
  665           RIFFWriter pbag_chunk = writer.writeChunk("pbag");
  666           int pbag_gencount = 0;
  667           int pbag_modcount = 0;
  668           for (SF2Instrument preset : this.instruments) {
  669               if (preset.getGlobalRegion() != null) {
  670                   pbag_chunk.writeUnsignedShort(pbag_gencount);
  671                   pbag_chunk.writeUnsignedShort(pbag_modcount);
  672                   pbag_gencount += preset.getGlobalRegion().getGenerators().size();
  673                   pbag_modcount += preset.getGlobalRegion().getModulators().size();
  674               }
  675               for (SF2InstrumentRegion region : preset.getRegions()) {
  676                   pbag_chunk.writeUnsignedShort(pbag_gencount);
  677                   pbag_chunk.writeUnsignedShort(pbag_modcount);
  678                   if (layers.indexOf(region.layer) != -1) {
  679                       // One generator is used to reference to instrument record
  680                       pbag_gencount += 1;
  681                   }
  682                   pbag_gencount += region.getGenerators().size();
  683                   pbag_modcount += region.getModulators().size();
  684   
  685               }
  686           }
  687           pbag_chunk.writeUnsignedShort(pbag_gencount);
  688           pbag_chunk.writeUnsignedShort(pbag_modcount);
  689   
  690           RIFFWriter pmod_chunk = writer.writeChunk("pmod");
  691           for (SF2Instrument preset : this.instruments) {
  692               if (preset.getGlobalRegion() != null) {
  693                   writeModulators(pmod_chunk,
  694                           preset.getGlobalRegion().getModulators());
  695               }
  696               for (SF2InstrumentRegion region : preset.getRegions())
  697                   writeModulators(pmod_chunk, region.getModulators());
  698           }
  699           pmod_chunk.write(new byte[10]);
  700   
  701           RIFFWriter pgen_chunk = writer.writeChunk("pgen");
  702           for (SF2Instrument preset : this.instruments) {
  703               if (preset.getGlobalRegion() != null) {
  704                   writeGenerators(pgen_chunk,
  705                           preset.getGlobalRegion().getGenerators());
  706               }
  707               for (SF2InstrumentRegion region : preset.getRegions()) {
  708                   writeGenerators(pgen_chunk, region.getGenerators());
  709                   int ix = (int) layers.indexOf(region.layer);
  710                   if (ix != -1) {
  711                       pgen_chunk.writeUnsignedShort(SF2Region.GENERATOR_INSTRUMENT);
  712                       pgen_chunk.writeShort((short) ix);
  713                   }
  714               }
  715           }
  716           pgen_chunk.write(new byte[4]);
  717   
  718           RIFFWriter inst_chunk = writer.writeChunk("inst");
  719           int inst_zone_count = 0;
  720           for (SF2Layer instrument : this.layers) {
  721               inst_chunk.writeString(instrument.name, 20);
  722               inst_chunk.writeUnsignedShort(inst_zone_count);
  723               if (instrument.getGlobalRegion() != null)
  724                   inst_zone_count += 1;
  725               inst_zone_count += instrument.getRegions().size();
  726           }
  727           inst_chunk.writeString("EOI", 20);
  728           inst_chunk.writeUnsignedShort(inst_zone_count);
  729   
  730   
  731           RIFFWriter ibag_chunk = writer.writeChunk("ibag");
  732           int ibag_gencount = 0;
  733           int ibag_modcount = 0;
  734           for (SF2Layer instrument : this.layers) {
  735               if (instrument.getGlobalRegion() != null) {
  736                   ibag_chunk.writeUnsignedShort(ibag_gencount);
  737                   ibag_chunk.writeUnsignedShort(ibag_modcount);
  738                   ibag_gencount
  739                           += instrument.getGlobalRegion().getGenerators().size();
  740                   ibag_modcount
  741                           += instrument.getGlobalRegion().getModulators().size();
  742               }
  743               for (SF2LayerRegion region : instrument.getRegions()) {
  744                   ibag_chunk.writeUnsignedShort(ibag_gencount);
  745                   ibag_chunk.writeUnsignedShort(ibag_modcount);
  746                   if (samples.indexOf(region.sample) != -1) {
  747                       // One generator is used to reference to instrument record
  748                       ibag_gencount += 1;
  749                   }
  750                   ibag_gencount += region.getGenerators().size();
  751                   ibag_modcount += region.getModulators().size();
  752   
  753               }
  754           }
  755           ibag_chunk.writeUnsignedShort(ibag_gencount);
  756           ibag_chunk.writeUnsignedShort(ibag_modcount);
  757   
  758   
  759           RIFFWriter imod_chunk = writer.writeChunk("imod");
  760           for (SF2Layer instrument : this.layers) {
  761               if (instrument.getGlobalRegion() != null) {
  762                   writeModulators(imod_chunk,
  763                           instrument.getGlobalRegion().getModulators());
  764               }
  765               for (SF2LayerRegion region : instrument.getRegions())
  766                   writeModulators(imod_chunk, region.getModulators());
  767           }
  768           imod_chunk.write(new byte[10]);
  769   
  770           RIFFWriter igen_chunk = writer.writeChunk("igen");
  771           for (SF2Layer instrument : this.layers) {
  772               if (instrument.getGlobalRegion() != null) {
  773                   writeGenerators(igen_chunk,
  774                           instrument.getGlobalRegion().getGenerators());
  775               }
  776               for (SF2LayerRegion region : instrument.getRegions()) {
  777                   writeGenerators(igen_chunk, region.getGenerators());
  778                   int ix = samples.indexOf(region.sample);
  779                   if (ix != -1) {
  780                       igen_chunk.writeUnsignedShort(SF2Region.GENERATOR_SAMPLEID);
  781                       igen_chunk.writeShort((short) ix);
  782                   }
  783               }
  784           }
  785           igen_chunk.write(new byte[4]);
  786   
  787   
  788           RIFFWriter shdr_chunk = writer.writeChunk("shdr");
  789           long sample_pos = 0;
  790           for (SF2Sample sample : samples) {
  791               shdr_chunk.writeString(sample.name, 20);
  792               long start = sample_pos;
  793               sample_pos += sample.data.capacity() / 2;
  794               long end = sample_pos;
  795               long startLoop = sample.startLoop + start;
  796               long endLoop = sample.endLoop + start;
  797               if (startLoop < start)
  798                   startLoop = start;
  799               if (endLoop > end)
  800                   endLoop = end;
  801               shdr_chunk.writeUnsignedInt(start);
  802               shdr_chunk.writeUnsignedInt(end);
  803               shdr_chunk.writeUnsignedInt(startLoop);
  804               shdr_chunk.writeUnsignedInt(endLoop);
  805               shdr_chunk.writeUnsignedInt(sample.sampleRate);
  806               shdr_chunk.writeUnsignedByte(sample.originalPitch);
  807               shdr_chunk.writeByte(sample.pitchCorrection);
  808               shdr_chunk.writeUnsignedShort(sample.sampleLink);
  809               shdr_chunk.writeUnsignedShort(sample.sampleType);
  810               sample_pos += 32;
  811           }
  812           shdr_chunk.writeString("EOS", 20);
  813           shdr_chunk.write(new byte[26]);
  814   
  815       }
  816   
  817       public String getName() {
  818           return name;
  819       }
  820   
  821       public String getVersion() {
  822           return major + "." + minor;
  823       }
  824   
  825       public String getVendor() {
  826           return engineers;
  827       }
  828   
  829       public String getDescription() {
  830           return comments;
  831       }
  832   
  833       public void setName(String s) {
  834           name = s;
  835       }
  836   
  837       public void setVendor(String s) {
  838           engineers = s;
  839       }
  840   
  841       public void setDescription(String s) {
  842           comments = s;
  843       }
  844   
  845       public SoundbankResource[] getResources() {
  846           SoundbankResource[] resources
  847                   = new SoundbankResource[layers.size() + samples.size()];
  848           int j = 0;
  849           for (int i = 0; i < layers.size(); i++)
  850               resources[j++] = layers.get(i);
  851           for (int i = 0; i < samples.size(); i++)
  852               resources[j++] = samples.get(i);
  853           return resources;
  854       }
  855   
  856       public SF2Instrument[] getInstruments() {
  857           SF2Instrument[] inslist_array
  858                   = instruments.toArray(new SF2Instrument[instruments.size()]);
  859           Arrays.sort(inslist_array, new ModelInstrumentComparator());
  860           return inslist_array;
  861       }
  862   
  863       public SF2Layer[] getLayers() {
  864           return layers.toArray(new SF2Layer[layers.size()]);
  865       }
  866   
  867       public SF2Sample[] getSamples() {
  868           return samples.toArray(new SF2Sample[samples.size()]);
  869       }
  870   
  871       public Instrument getInstrument(Patch patch) {
  872           int program = patch.getProgram();
  873           int bank = patch.getBank();
  874           boolean percussion = false;
  875           if (patch instanceof ModelPatch)
  876               percussion = ((ModelPatch)patch).isPercussion();
  877           for (Instrument instrument : instruments) {
  878               Patch patch2 = instrument.getPatch();
  879               int program2 = patch2.getProgram();
  880               int bank2 = patch2.getBank();
  881               if (program == program2 && bank == bank2) {
  882                   boolean percussion2 = false;
  883                   if (patch2 instanceof ModelPatch)
  884                       percussion2 = ((ModelPatch) patch2).isPercussion();
  885                   if (percussion == percussion2)
  886                       return instrument;
  887               }
  888           }
  889           return null;
  890       }
  891   
  892       public String getCreationDate() {
  893           return creationDate;
  894       }
  895   
  896       public void setCreationDate(String creationDate) {
  897           this.creationDate = creationDate;
  898       }
  899   
  900       public String getProduct() {
  901           return product;
  902       }
  903   
  904       public void setProduct(String product) {
  905           this.product = product;
  906       }
  907   
  908       public String getRomName() {
  909           return romName;
  910       }
  911   
  912       public void setRomName(String romName) {
  913           this.romName = romName;
  914       }
  915   
  916       public int getRomVersionMajor() {
  917           return romVersionMajor;
  918       }
  919   
  920       public void setRomVersionMajor(int romVersionMajor) {
  921           this.romVersionMajor = romVersionMajor;
  922       }
  923   
  924       public int getRomVersionMinor() {
  925           return romVersionMinor;
  926       }
  927   
  928       public void setRomVersionMinor(int romVersionMinor) {
  929           this.romVersionMinor = romVersionMinor;
  930       }
  931   
  932       public String getTargetEngine() {
  933           return targetEngine;
  934       }
  935   
  936       public void setTargetEngine(String targetEngine) {
  937           this.targetEngine = targetEngine;
  938       }
  939   
  940       public String getTools() {
  941           return tools;
  942       }
  943   
  944       public void setTools(String tools) {
  945           this.tools = tools;
  946       }
  947   
  948       public void addResource(SoundbankResource resource) {
  949           if (resource instanceof SF2Instrument)
  950               instruments.add((SF2Instrument)resource);
  951           if (resource instanceof SF2Layer)
  952               layers.add((SF2Layer)resource);
  953           if (resource instanceof SF2Sample)
  954               samples.add((SF2Sample)resource);
  955       }
  956   
  957       public void removeResource(SoundbankResource resource) {
  958           if (resource instanceof SF2Instrument)
  959               instruments.remove((SF2Instrument)resource);
  960           if (resource instanceof SF2Layer)
  961               layers.remove((SF2Layer)resource);
  962           if (resource instanceof SF2Sample)
  963               samples.remove((SF2Sample)resource);
  964       }
  965   
  966       public void addInstrument(SF2Instrument resource) {
  967           instruments.add(resource);
  968       }
  969   
  970       public void removeInstrument(SF2Instrument resource) {
  971           instruments.remove(resource);
  972       }
  973   }

Save This Page
Home » openjdk-7 » com.sun.media » sound » [javadoc | source]