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 
DLSInstrument()54     public DLSInstrument() {
55         super(null, null, null, null);
56     }
57 
DLSInstrument(DLSSoundbank soundbank)58     public DLSInstrument(DLSSoundbank soundbank) {
59         super(soundbank, null, null, null);
60     }
61 
getInfo()62     public DLSInfo getInfo() {
63         return info;
64     }
65 
66     @Override
getName()67     public String getName() {
68         return info.name;
69     }
70 
setName(String name)71     public void setName(String name) {
72         info.name = name;
73     }
74 
75     @Override
getPatch()76     public ModelPatch getPatch() {
77         return new ModelPatch(bank, preset, druminstrument);
78     }
79 
setPatch(Patch patch)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
getData()93     public Object getData() {
94         return null;
95     }
96 
getRegions()97     public List<DLSRegion> getRegions() {
98         return regions;
99     }
100 
getModulators()101     public List<DLSModulator> getModulators() {
102         return modulators;
103     }
104 
105     @Override
toString()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 
convertToModelDest(int dest)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 
convertToModelSrc(int src)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 
convertToModel(DLSModulator mod)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
getPerformers()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 
getGuid()447     public byte[] getGuid() {
448         return guid == null ? null : Arrays.copyOf(guid, guid.length);
449     }
450 
setGuid(byte[] guid)451     public void setGuid(byte[] guid) {
452         this.guid = guid == null ? null : Arrays.copyOf(guid, guid.length);
453     }
454 }
455