1 /*
   2  * Copyright (c) 2007, 2013, 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.util.ArrayList;
  28 import java.util.Arrays;
  29 import java.util.HashMap;
  30 import java.util.List;
  31 import java.util.Map;
  32 
  33 import javax.sound.midi.Patch;
  34 
  35 /**
  36  * This class is used to store information to describe instrument.
  37  * It contains list of regions and modulators.
  38  * It is stored inside a "ins " List Chunk inside DLS files.
  39  * In the DLS documentation a modulator is called articulator.
  40  *
  41  * @author Karl Helgason
  42  */
  43 public final class DLSInstrument extends ModelInstrument {
  44 
  45     int preset = 0;
  46     int bank = 0;
  47     boolean druminstrument = false;
  48     byte[] guid = null;
  49     DLSInfo info = new DLSInfo();
  50     List<DLSRegion> regions = new ArrayList<DLSRegion>();
  51     List<DLSModulator> modulators = new ArrayList<DLSModulator>();
  52 
  53     public DLSInstrument() {
  54         super(null, null, null, null);
  55     }
  56 
  57     public DLSInstrument(DLSSoundbank soundbank) {
  58         super(soundbank, null, null, null);
  59     }
  60 
  61     public DLSInfo getInfo() {
  62         return info;
  63     }
  64 
  65     public String getName() {
  66         return info.name;
  67     }
  68 
  69     public void setName(String name) {
  70         info.name = name;
  71     }
  72 
  73     public ModelPatch getPatch() {
  74         return new ModelPatch(bank, preset, druminstrument);
  75     }
  76 
  77     public void setPatch(Patch patch) {
  78         if (patch instanceof ModelPatch && ((ModelPatch)patch).isPercussion()) {
  79             druminstrument = true;
  80             bank = patch.getBank();
  81             preset = patch.getProgram();
  82         } else {
  83             druminstrument = false;
  84             bank = patch.getBank();
  85             preset = patch.getProgram();
  86         }
  87     }
  88 
  89     public Object getData() {
  90         return null;
  91     }
  92 
  93     public List<DLSRegion> getRegions() {
  94         return regions;
  95     }
  96 
  97     public List<DLSModulator> getModulators() {
  98         return modulators;
  99     }
 100 
 101     public String toString() {
 102         if (druminstrument)
 103             return "Drumkit: " + info.name
 104                     + " bank #" + bank + " preset #" + preset;
 105         else
 106             return "Instrument: " + info.name
 107                     + " bank #" + bank + " preset #" + preset;
 108     }
 109 
 110     private ModelIdentifier convertToModelDest(int dest) {
 111         if (dest == DLSModulator.CONN_DST_NONE)
 112             return null;
 113         if (dest == DLSModulator.CONN_DST_GAIN)
 114             return ModelDestination.DESTINATION_GAIN;
 115         if (dest == DLSModulator.CONN_DST_PITCH)
 116             return ModelDestination.DESTINATION_PITCH;
 117         if (dest == DLSModulator.CONN_DST_PAN)
 118             return ModelDestination.DESTINATION_PAN;
 119 
 120         if (dest == DLSModulator.CONN_DST_LFO_FREQUENCY)
 121             return ModelDestination.DESTINATION_LFO1_FREQ;
 122         if (dest == DLSModulator.CONN_DST_LFO_STARTDELAY)
 123             return ModelDestination.DESTINATION_LFO1_DELAY;
 124 
 125         if (dest == DLSModulator.CONN_DST_EG1_ATTACKTIME)
 126             return ModelDestination.DESTINATION_EG1_ATTACK;
 127         if (dest == DLSModulator.CONN_DST_EG1_DECAYTIME)
 128             return ModelDestination.DESTINATION_EG1_DECAY;
 129         if (dest == DLSModulator.CONN_DST_EG1_RELEASETIME)
 130             return ModelDestination.DESTINATION_EG1_RELEASE;
 131         if (dest == DLSModulator.CONN_DST_EG1_SUSTAINLEVEL)
 132             return ModelDestination.DESTINATION_EG1_SUSTAIN;
 133 
 134         if (dest == DLSModulator.CONN_DST_EG2_ATTACKTIME)
 135             return ModelDestination.DESTINATION_EG2_ATTACK;
 136         if (dest == DLSModulator.CONN_DST_EG2_DECAYTIME)
 137             return ModelDestination.DESTINATION_EG2_DECAY;
 138         if (dest == DLSModulator.CONN_DST_EG2_RELEASETIME)
 139             return ModelDestination.DESTINATION_EG2_RELEASE;
 140         if (dest == DLSModulator.CONN_DST_EG2_SUSTAINLEVEL)
 141             return ModelDestination.DESTINATION_EG2_SUSTAIN;
 142 
 143         // DLS2 Destinations
 144         if (dest == DLSModulator.CONN_DST_KEYNUMBER)
 145             return ModelDestination.DESTINATION_KEYNUMBER;
 146 
 147         if (dest == DLSModulator.CONN_DST_CHORUS)
 148             return ModelDestination.DESTINATION_CHORUS;
 149         if (dest == DLSModulator.CONN_DST_REVERB)
 150             return ModelDestination.DESTINATION_REVERB;
 151 
 152         if (dest == DLSModulator.CONN_DST_VIB_FREQUENCY)
 153             return ModelDestination.DESTINATION_LFO2_FREQ;
 154         if (dest == DLSModulator.CONN_DST_VIB_STARTDELAY)
 155             return ModelDestination.DESTINATION_LFO2_DELAY;
 156 
 157         if (dest == DLSModulator.CONN_DST_EG1_DELAYTIME)
 158             return ModelDestination.DESTINATION_EG1_DELAY;
 159         if (dest == DLSModulator.CONN_DST_EG1_HOLDTIME)
 160             return ModelDestination.DESTINATION_EG1_HOLD;
 161         if (dest == DLSModulator.CONN_DST_EG1_SHUTDOWNTIME)
 162             return ModelDestination.DESTINATION_EG1_SHUTDOWN;
 163 
 164         if (dest == DLSModulator.CONN_DST_EG2_DELAYTIME)
 165             return ModelDestination.DESTINATION_EG2_DELAY;
 166         if (dest == DLSModulator.CONN_DST_EG2_HOLDTIME)
 167             return ModelDestination.DESTINATION_EG2_HOLD;
 168 
 169         if (dest == DLSModulator.CONN_DST_FILTER_CUTOFF)
 170             return ModelDestination.DESTINATION_FILTER_FREQ;
 171         if (dest == DLSModulator.CONN_DST_FILTER_Q)
 172             return ModelDestination.DESTINATION_FILTER_Q;
 173 
 174         return null;
 175     }
 176 
 177     private ModelIdentifier convertToModelSrc(int src) {
 178         if (src == DLSModulator.CONN_SRC_NONE)
 179             return null;
 180 
 181         if (src == DLSModulator.CONN_SRC_LFO)
 182             return ModelSource.SOURCE_LFO1;
 183         if (src == DLSModulator.CONN_SRC_KEYONVELOCITY)
 184             return ModelSource.SOURCE_NOTEON_VELOCITY;
 185         if (src == DLSModulator.CONN_SRC_KEYNUMBER)
 186             return ModelSource.SOURCE_NOTEON_KEYNUMBER;
 187         if (src == DLSModulator.CONN_SRC_EG1)
 188             return ModelSource.SOURCE_EG1;
 189         if (src == DLSModulator.CONN_SRC_EG2)
 190             return ModelSource.SOURCE_EG2;
 191         if (src == DLSModulator.CONN_SRC_PITCHWHEEL)
 192             return ModelSource.SOURCE_MIDI_PITCH;
 193         if (src == DLSModulator.CONN_SRC_CC1)
 194             return new ModelIdentifier("midi_cc", "1", 0);
 195         if (src == DLSModulator.CONN_SRC_CC7)
 196             return new ModelIdentifier("midi_cc", "7", 0);
 197         if (src == DLSModulator.CONN_SRC_CC10)
 198             return new ModelIdentifier("midi_cc", "10", 0);
 199         if (src == DLSModulator.CONN_SRC_CC11)
 200             return new ModelIdentifier("midi_cc", "11", 0);
 201         if (src == DLSModulator.CONN_SRC_RPN0)
 202             return new ModelIdentifier("midi_rpn", "0", 0);
 203         if (src == DLSModulator.CONN_SRC_RPN1)
 204             return new ModelIdentifier("midi_rpn", "1", 0);
 205 
 206         if (src == DLSModulator.CONN_SRC_POLYPRESSURE)
 207             return ModelSource.SOURCE_MIDI_POLY_PRESSURE;
 208         if (src == DLSModulator.CONN_SRC_CHANNELPRESSURE)
 209             return ModelSource.SOURCE_MIDI_CHANNEL_PRESSURE;
 210         if (src == DLSModulator.CONN_SRC_VIBRATO)
 211             return ModelSource.SOURCE_LFO2;
 212         if (src == DLSModulator.CONN_SRC_MONOPRESSURE)
 213             return ModelSource.SOURCE_MIDI_CHANNEL_PRESSURE;
 214 
 215         if (src == DLSModulator.CONN_SRC_CC91)
 216             return new ModelIdentifier("midi_cc", "91", 0);
 217         if (src == DLSModulator.CONN_SRC_CC93)
 218             return new ModelIdentifier("midi_cc", "93", 0);
 219 
 220         return null;
 221     }
 222 
 223     private ModelConnectionBlock convertToModel(DLSModulator mod) {
 224         ModelIdentifier source = convertToModelSrc(mod.getSource());
 225         ModelIdentifier control = convertToModelSrc(mod.getControl());
 226         ModelIdentifier destination_id =
 227                 convertToModelDest(mod.getDestination());
 228 
 229         int scale = mod.getScale();
 230         double f_scale;
 231         if (scale == Integer.MIN_VALUE)
 232             f_scale = Double.NEGATIVE_INFINITY;
 233         else
 234             f_scale = scale / 65536.0;
 235 
 236         if (destination_id != null) {
 237             ModelSource src = null;
 238             ModelSource ctrl = null;
 239             ModelConnectionBlock block = new ModelConnectionBlock();
 240             if (control != null) {
 241                 ModelSource s = new ModelSource();
 242                 if (control == ModelSource.SOURCE_MIDI_PITCH) {
 243                     ((ModelStandardTransform)s.getTransform()).setPolarity(
 244                             ModelStandardTransform.POLARITY_BIPOLAR);
 245                 } else if (control == ModelSource.SOURCE_LFO1
 246                         || control == ModelSource.SOURCE_LFO2) {
 247                     ((ModelStandardTransform)s.getTransform()).setPolarity(
 248                             ModelStandardTransform.POLARITY_BIPOLAR);
 249                 }
 250                 s.setIdentifier(control);
 251                 block.addSource(s);
 252                 ctrl = s;
 253             }
 254             if (source != null) {
 255                 ModelSource s = new ModelSource();
 256                 if (source == ModelSource.SOURCE_MIDI_PITCH) {
 257                     ((ModelStandardTransform)s.getTransform()).setPolarity(
 258                             ModelStandardTransform.POLARITY_BIPOLAR);
 259                 } else if (source == ModelSource.SOURCE_LFO1
 260                         || source == ModelSource.SOURCE_LFO2) {
 261                     ((ModelStandardTransform)s.getTransform()).setPolarity(
 262                             ModelStandardTransform.POLARITY_BIPOLAR);
 263                 }
 264                 s.setIdentifier(source);
 265                 block.addSource(s);
 266                 src = s;
 267             }
 268             ModelDestination destination = new ModelDestination();
 269             destination.setIdentifier(destination_id);
 270             block.setDestination(destination);
 271 
 272             if (mod.getVersion() == 1) {
 273                 //if (mod.getTransform() ==  DLSModulator.CONN_TRN_CONCAVE) {
 274                 //    ((ModelStandardTransform)destination.getTransform())
 275                 //            .setTransform(
 276                 //            ModelStandardTransform.TRANSFORM_CONCAVE);
 277                 //}
 278                 if (mod.getTransform() == DLSModulator.CONN_TRN_CONCAVE) {
 279                     if (src != null) {
 280                         ((ModelStandardTransform)src.getTransform())
 281                                 .setTransform(
 282                                     ModelStandardTransform.TRANSFORM_CONCAVE);
 283                         ((ModelStandardTransform)src.getTransform())
 284                                 .setDirection(
 285                                     ModelStandardTransform.DIRECTION_MAX2MIN);
 286                     }
 287                     if (ctrl != null) {
 288                         ((ModelStandardTransform)ctrl.getTransform())
 289                                 .setTransform(
 290                                     ModelStandardTransform.TRANSFORM_CONCAVE);
 291                         ((ModelStandardTransform)ctrl.getTransform())
 292                                 .setDirection(
 293                                     ModelStandardTransform.DIRECTION_MAX2MIN);
 294                     }
 295                 }
 296 
 297             } else if (mod.getVersion() == 2) {
 298                 int transform = mod.getTransform();
 299                 int src_transform_invert = (transform >> 15) & 1;
 300                 int src_transform_bipolar = (transform >> 14) & 1;
 301                 int src_transform = (transform >> 10) & 8;
 302                 int ctr_transform_invert = (transform >> 9) & 1;
 303                 int ctr_transform_bipolar = (transform >> 8) & 1;
 304                 int ctr_transform = (transform >> 4) & 8;
 305 
 306 
 307                 if (src != null) {
 308                     int trans = ModelStandardTransform.TRANSFORM_LINEAR;
 309                     if (src_transform == DLSModulator.CONN_TRN_SWITCH)
 310                         trans = ModelStandardTransform.TRANSFORM_SWITCH;
 311                     if (src_transform == DLSModulator.CONN_TRN_CONCAVE)
 312                         trans = ModelStandardTransform.TRANSFORM_CONCAVE;
 313                     if (src_transform == DLSModulator.CONN_TRN_CONVEX)
 314                         trans = ModelStandardTransform.TRANSFORM_CONVEX;
 315                     ((ModelStandardTransform)src.getTransform())
 316                             .setTransform(trans);
 317                     ((ModelStandardTransform)src.getTransform())
 318                             .setPolarity(src_transform_bipolar == 1);
 319                     ((ModelStandardTransform)src.getTransform())
 320                             .setDirection(src_transform_invert == 1);
 321 
 322                 }
 323 
 324                 if (ctrl != null) {
 325                     int trans = ModelStandardTransform.TRANSFORM_LINEAR;
 326                     if (ctr_transform == DLSModulator.CONN_TRN_SWITCH)
 327                         trans = ModelStandardTransform.TRANSFORM_SWITCH;
 328                     if (ctr_transform == DLSModulator.CONN_TRN_CONCAVE)
 329                         trans = ModelStandardTransform.TRANSFORM_CONCAVE;
 330                     if (ctr_transform == DLSModulator.CONN_TRN_CONVEX)
 331                         trans = ModelStandardTransform.TRANSFORM_CONVEX;
 332                     ((ModelStandardTransform)ctrl.getTransform())
 333                             .setTransform(trans);
 334                     ((ModelStandardTransform)ctrl.getTransform())
 335                             .setPolarity(ctr_transform_bipolar == 1);
 336                     ((ModelStandardTransform)ctrl.getTransform())
 337                             .setDirection(ctr_transform_invert == 1);
 338                 }
 339 
 340                 /* No output transforms are defined the DLS Level 2
 341                 int out_transform = transform % 8;
 342                 int trans = ModelStandardTransform.TRANSFORM_LINEAR;
 343                 if (out_transform == DLSModulator.CONN_TRN_SWITCH)
 344                     trans = ModelStandardTransform.TRANSFORM_SWITCH;
 345                 if (out_transform == DLSModulator.CONN_TRN_CONCAVE)
 346                     trans = ModelStandardTransform.TRANSFORM_CONCAVE;
 347                 if (out_transform == DLSModulator.CONN_TRN_CONVEX)
 348                     trans = ModelStandardTransform.TRANSFORM_CONVEX;
 349                 if (ctrl != null) {
 350                     ((ModelStandardTransform)destination.getTransform())
 351                             .setTransform(trans);
 352                 }
 353                 */
 354 
 355             }
 356 
 357             block.setScale(f_scale);
 358 
 359             return block;
 360         }
 361 
 362         return null;
 363     }
 364 
 365     public ModelPerformer[] getPerformers() {
 366         List<ModelPerformer> performers = new ArrayList<ModelPerformer>();
 367 
 368         Map<String, DLSModulator> modmap = new HashMap<String, DLSModulator>();
 369         for (DLSModulator mod: getModulators()) {
 370             modmap.put(mod.getSource() + "x" + mod.getControl() + "=" +
 371                     mod.getDestination(), mod);
 372         }
 373 
 374         Map<String, DLSModulator> insmodmap =
 375                 new HashMap<String, DLSModulator>();
 376 
 377         for (DLSRegion zone: regions) {
 378             ModelPerformer performer = new ModelPerformer();
 379             performer.setName(zone.getSample().getName());
 380             performer.setSelfNonExclusive((zone.getFusoptions() &
 381                     DLSRegion.OPTION_SELFNONEXCLUSIVE) != 0);
 382             performer.setExclusiveClass(zone.getExclusiveClass());
 383             performer.setKeyFrom(zone.getKeyfrom());
 384             performer.setKeyTo(zone.getKeyto());
 385             performer.setVelFrom(zone.getVelfrom());
 386             performer.setVelTo(zone.getVelto());
 387 
 388             insmodmap.clear();
 389             insmodmap.putAll(modmap);
 390             for (DLSModulator mod: zone.getModulators()) {
 391                 insmodmap.put(mod.getSource() + "x" + mod.getControl() + "=" +
 392                         mod.getDestination(), mod);
 393             }
 394 
 395             List<ModelConnectionBlock> blocks = performer.getConnectionBlocks();
 396             for (DLSModulator mod: insmodmap.values()) {
 397                 ModelConnectionBlock p = convertToModel(mod);
 398                 if (p != null)
 399                     blocks.add(p);
 400             }
 401 
 402 
 403             DLSSample sample = zone.getSample();
 404             DLSSampleOptions sampleopt = zone.getSampleoptions();
 405             if (sampleopt == null)
 406                 sampleopt = sample.getSampleoptions();
 407 
 408             ModelByteBuffer buff = sample.getDataBuffer();
 409 
 410             float pitchcorrection = (-sampleopt.unitynote * 100) +
 411                     sampleopt.finetune;
 412 
 413             ModelByteBufferWavetable osc = new ModelByteBufferWavetable(buff,
 414                     sample.getFormat(), pitchcorrection);
 415             osc.setAttenuation(osc.getAttenuation() / 65536f);
 416             if (sampleopt.getLoops().size() != 0) {
 417                 DLSSampleLoop loop = sampleopt.getLoops().get(0);
 418                 osc.setLoopStart((int)loop.getStart());
 419                 osc.setLoopLength((int)loop.getLength());
 420                 if (loop.getType() == DLSSampleLoop.LOOP_TYPE_FORWARD)
 421                     osc.setLoopType(ModelWavetable.LOOP_TYPE_FORWARD);
 422                 if (loop.getType() == DLSSampleLoop.LOOP_TYPE_RELEASE)
 423                     osc.setLoopType(ModelWavetable.LOOP_TYPE_RELEASE);
 424                 else
 425                     osc.setLoopType(ModelWavetable.LOOP_TYPE_FORWARD);
 426             }
 427 
 428             performer.getConnectionBlocks().add(
 429                     new ModelConnectionBlock(SoftFilter.FILTERTYPE_LP12,
 430                         new ModelDestination(
 431                             new ModelIdentifier("filter", "type", 1))));
 432 
 433             performer.getOscillators().add(osc);
 434 
 435             performers.add(performer);
 436 
 437         }
 438 
 439         return performers.toArray(new ModelPerformer[performers.size()]);
 440     }
 441 
 442     public byte[] getGuid() {
 443         return guid == null ? null : Arrays.copyOf(guid, guid.length);
 444     }
 445 
 446     public void setGuid(byte[] guid) {
 447         this.guid = guid == null ? null : Arrays.copyOf(guid, guid.length);
 448     }
 449 }