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