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.HashMap;
29 import java.util.List;
30 import java.util.Map;
31
32 import javax.sound.midi.Patch;
33
34 /**
35 * Soundfont instrument.
36 *
37 * @author Karl Helgason
38 */
39 public final class SF2Instrument extends ModelInstrument {
40
41 String name = "";
42 int preset = 0;
43 int bank = 0;
44 long library = 0;
45 long genre = 0;
46 long morphology = 0;
47 SF2GlobalRegion globalregion = null;
48 List<SF2InstrumentRegion> regions
49 = new ArrayList<SF2InstrumentRegion>();
50
51 public SF2Instrument() {
52 super(null, null, null, null);
53 }
54
55 public SF2Instrument(SF2Soundbank soundbank) {
56 super(soundbank, null, null, null);
57 }
58
59 public String getName() {
60 return name;
61 }
62
63 public void setName(String name) {
64 this.name = name;
65 }
66
67 public Patch getPatch() {
68 if (bank == 128)
69 return new ModelPatch(0, preset, true);
70 else
71 return new ModelPatch(bank << 7, preset, false);
72 }
73
74 public void setPatch(Patch patch) {
75 if (patch instanceof ModelPatch && ((ModelPatch) patch).isPercussion()) {
76 bank = 128;
77 preset = patch.getProgram();
78 } else {
79 bank = patch.getBank() >> 7;
80 preset = patch.getProgram();
81 }
82 }
83
84 public Object getData() {
85 return null;
86 }
87
88 public long getGenre() {
89 return genre;
90 }
91
92 public void setGenre(long genre) {
93 this.genre = genre;
94 }
95
96 public long getLibrary() {
97 return library;
98 }
99
100 public void setLibrary(long library) {
101 this.library = library;
102 }
103
104 public long getMorphology() {
105 return morphology;
106 }
107
108 public void setMorphology(long morphology) {
109 this.morphology = morphology;
110 }
111
112 public List<SF2InstrumentRegion> getRegions() {
113 return regions;
114 }
115
116 public SF2GlobalRegion getGlobalRegion() {
117 return globalregion;
118 }
119
120 public void setGlobalZone(SF2GlobalRegion zone) {
121 globalregion = zone;
122 }
123
124 public String toString() {
125 if (bank == 128)
126 return "Drumkit: " + name + " preset #" + preset;
127 else
128 return "Instrument: " + name + " bank #" + bank
129 + " preset #" + preset;
130 }
131
132 public ModelPerformer[] getPerformers() {
133 int performercount = 0;
134 for (SF2InstrumentRegion presetzone : regions)
135 performercount += presetzone.getLayer().getRegions().size();
136 ModelPerformer[] performers = new ModelPerformer[performercount];
137 int pi = 0;
138
139 SF2GlobalRegion presetglobal = globalregion;
140 for (SF2InstrumentRegion presetzone : regions) {
141 Map<Integer, Short> pgenerators = new HashMap<Integer, Short>();
142 pgenerators.putAll(presetzone.getGenerators());
143 if (presetglobal != null)
144 pgenerators.putAll(presetglobal.getGenerators());
145
146 SF2Layer layer = presetzone.getLayer();
147 SF2GlobalRegion layerglobal = layer.getGlobalRegion();
148 for (SF2LayerRegion layerzone : layer.getRegions()) {
149 ModelPerformer performer = new ModelPerformer();
150 if (layerzone.getSample() != null)
151 performer.setName(layerzone.getSample().getName());
152 else
153 performer.setName(layer.getName());
154
155 performers[pi++] = performer;
156
157 int keyfrom = 0;
158 int keyto = 127;
159 int velfrom = 0;
160 int velto = 127;
161
250 byte[] data = buff.array();
251 int off = (int)buff.arrayOffset() + startAddrsOffset*2;
252 int len = (int)buff.capacity() + endAddrsOffset*2;
253 if (off+len > data.length)
254 len = data.length - off;
255 buff = new ModelByteBuffer(data, off, len);
256 if(buff24 != null) {
257 data = buff.array();
258 off = (int)buff.arrayOffset() + startAddrsOffset;
259 len = (int)buff.capacity() + endAddrsOffset;
260 buff24 = new ModelByteBuffer(data, off, len);
261 }
262 */
263 }
264
265 ModelByteBufferWavetable osc = new ModelByteBufferWavetable(
266 buff, sample.getFormat(), pitchcorrection);
267 if (buff24 != null)
268 osc.set8BitExtensionBuffer(buff24);
269
270 Map<Integer, Short> generators = new HashMap<Integer, Short>();
271 if (layerglobal != null)
272 generators.putAll(layerglobal.getGenerators());
273 generators.putAll(layerzone.getGenerators());
274 for (Map.Entry<Integer, Short> gen : pgenerators.entrySet()) {
275 short val;
276 if (!generators.containsKey(gen.getKey()))
277 val = layerzone.getShort(gen.getKey());
278 else
279 val = generators.get(gen.getKey());
280 val += gen.getValue();
281 generators.put(gen.getKey(), val);
282 }
283
284 // SampleMode:
285 // 0 indicates a sound reproduced with no loop
286 // 1 indicates a sound which loops continuously
287 // 2 is unused but should be interpreted as indicating no loop
288 // 3 indicates a sound which loops for the duration of key
289 // depression then proceeds to play the remainder of the sample.
290 int sampleMode = getGeneratorValue(generators,
591 new ModelDestination(dest)));
592 } else {
593 ModelIdentifier dest = ModelDestination.DESTINATION_PITCH;
594 performer.getConnectionBlocks().add(
595 new ModelConnectionBlock(null, rootkey * (100 - fvalue),
596 new ModelDestination(dest)));
597 }
598
599 ModelIdentifier src = ModelSource.SOURCE_NOTEON_KEYNUMBER;
600 ModelIdentifier dest = ModelDestination.DESTINATION_PITCH;
601 performer.getConnectionBlocks().add(
602 new ModelConnectionBlock(new ModelSource(src),
603 128 * fvalue, new ModelDestination(dest)));
604
605 }
606
607 performer.getConnectionBlocks().add(
608 new ModelConnectionBlock(
609 new ModelSource(ModelSource.SOURCE_NOTEON_VELOCITY,
610 new ModelTransform() {
611 public double transform(double value) {
612 if (value < 0.5)
613 return 1 - value * 2;
614 else
615 return 0;
616 }
617 }),
618 -2400,
619 new ModelDestination(
620 ModelDestination.DESTINATION_FILTER_FREQ)));
621
622
623 performer.getConnectionBlocks().add(
624 new ModelConnectionBlock(
625 new ModelSource(ModelSource.SOURCE_LFO2,
626 ModelStandardTransform.DIRECTION_MIN2MAX,
627 ModelStandardTransform.POLARITY_BIPOLAR,
628 ModelStandardTransform.TRANSFORM_LINEAR),
629 new ModelSource(new ModelIdentifier("midi_cc", "1", 0),
630 ModelStandardTransform.DIRECTION_MIN2MAX,
|
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.HashMap;
30 import java.util.List;
31 import java.util.Map;
32
33 import javax.sound.midi.Patch;
34
35 /**
36 * Soundfont instrument.
37 *
38 * @author Karl Helgason
39 */
40 public final class SF2Instrument extends ModelInstrument {
41
42 String name = "";
43 int preset = 0;
44 int bank = 0;
45 long library = 0;
46 long genre = 0;
47 long morphology = 0;
48 SF2GlobalRegion globalregion = null;
49 List<SF2InstrumentRegion> regions = new ArrayList<>();
50
51 public SF2Instrument() {
52 super(null, null, null, null);
53 }
54
55 public SF2Instrument(SF2Soundbank soundbank) {
56 super(soundbank, null, null, null);
57 }
58
59 @Override
60 public String getName() {
61 return name;
62 }
63
64 public void setName(String name) {
65 this.name = name;
66 }
67
68 @Override
69 public Patch getPatch() {
70 if (bank == 128)
71 return new ModelPatch(0, preset, true);
72 else
73 return new ModelPatch(bank << 7, preset, false);
74 }
75
76 public void setPatch(Patch patch) {
77 if (patch instanceof ModelPatch && ((ModelPatch) patch).isPercussion()) {
78 bank = 128;
79 preset = patch.getProgram();
80 } else {
81 bank = patch.getBank() >> 7;
82 preset = patch.getProgram();
83 }
84 }
85
86 @Override
87 public Object getData() {
88 return null;
89 }
90
91 public long getGenre() {
92 return genre;
93 }
94
95 public void setGenre(long genre) {
96 this.genre = genre;
97 }
98
99 public long getLibrary() {
100 return library;
101 }
102
103 public void setLibrary(long library) {
104 this.library = library;
105 }
106
107 public long getMorphology() {
108 return morphology;
109 }
110
111 public void setMorphology(long morphology) {
112 this.morphology = morphology;
113 }
114
115 public List<SF2InstrumentRegion> getRegions() {
116 return regions;
117 }
118
119 public SF2GlobalRegion getGlobalRegion() {
120 return globalregion;
121 }
122
123 public void setGlobalZone(SF2GlobalRegion zone) {
124 globalregion = zone;
125 }
126
127 @Override
128 public String toString() {
129 if (bank == 128)
130 return "Drumkit: " + name + " preset #" + preset;
131 else
132 return "Instrument: " + name + " bank #" + bank
133 + " preset #" + preset;
134 }
135
136 @Override
137 public ModelPerformer[] getPerformers() {
138 int performercount = 0;
139 for (SF2InstrumentRegion presetzone : regions)
140 performercount += presetzone.getLayer().getRegions().size();
141 ModelPerformer[] performers = new ModelPerformer[performercount];
142 int pi = 0;
143
144 SF2GlobalRegion presetglobal = globalregion;
145 for (SF2InstrumentRegion presetzone : regions) {
146 Map<Integer, Short> pgenerators = new HashMap<>();
147 pgenerators.putAll(presetzone.getGenerators());
148 if (presetglobal != null)
149 pgenerators.putAll(presetglobal.getGenerators());
150
151 SF2Layer layer = presetzone.getLayer();
152 SF2GlobalRegion layerglobal = layer.getGlobalRegion();
153 for (SF2LayerRegion layerzone : layer.getRegions()) {
154 ModelPerformer performer = new ModelPerformer();
155 if (layerzone.getSample() != null)
156 performer.setName(layerzone.getSample().getName());
157 else
158 performer.setName(layer.getName());
159
160 performers[pi++] = performer;
161
162 int keyfrom = 0;
163 int keyto = 127;
164 int velfrom = 0;
165 int velto = 127;
166
255 byte[] data = buff.array();
256 int off = (int)buff.arrayOffset() + startAddrsOffset*2;
257 int len = (int)buff.capacity() + endAddrsOffset*2;
258 if (off+len > data.length)
259 len = data.length - off;
260 buff = new ModelByteBuffer(data, off, len);
261 if(buff24 != null) {
262 data = buff.array();
263 off = (int)buff.arrayOffset() + startAddrsOffset;
264 len = (int)buff.capacity() + endAddrsOffset;
265 buff24 = new ModelByteBuffer(data, off, len);
266 }
267 */
268 }
269
270 ModelByteBufferWavetable osc = new ModelByteBufferWavetable(
271 buff, sample.getFormat(), pitchcorrection);
272 if (buff24 != null)
273 osc.set8BitExtensionBuffer(buff24);
274
275 Map<Integer, Short> generators = new HashMap<>();
276 if (layerglobal != null)
277 generators.putAll(layerglobal.getGenerators());
278 generators.putAll(layerzone.getGenerators());
279 for (Map.Entry<Integer, Short> gen : pgenerators.entrySet()) {
280 short val;
281 if (!generators.containsKey(gen.getKey()))
282 val = layerzone.getShort(gen.getKey());
283 else
284 val = generators.get(gen.getKey());
285 val += gen.getValue();
286 generators.put(gen.getKey(), val);
287 }
288
289 // SampleMode:
290 // 0 indicates a sound reproduced with no loop
291 // 1 indicates a sound which loops continuously
292 // 2 is unused but should be interpreted as indicating no loop
293 // 3 indicates a sound which loops for the duration of key
294 // depression then proceeds to play the remainder of the sample.
295 int sampleMode = getGeneratorValue(generators,
596 new ModelDestination(dest)));
597 } else {
598 ModelIdentifier dest = ModelDestination.DESTINATION_PITCH;
599 performer.getConnectionBlocks().add(
600 new ModelConnectionBlock(null, rootkey * (100 - fvalue),
601 new ModelDestination(dest)));
602 }
603
604 ModelIdentifier src = ModelSource.SOURCE_NOTEON_KEYNUMBER;
605 ModelIdentifier dest = ModelDestination.DESTINATION_PITCH;
606 performer.getConnectionBlocks().add(
607 new ModelConnectionBlock(new ModelSource(src),
608 128 * fvalue, new ModelDestination(dest)));
609
610 }
611
612 performer.getConnectionBlocks().add(
613 new ModelConnectionBlock(
614 new ModelSource(ModelSource.SOURCE_NOTEON_VELOCITY,
615 new ModelTransform() {
616 @Override
617 public double transform(double value) {
618 if (value < 0.5)
619 return 1 - value * 2;
620 else
621 return 0;
622 }
623 }),
624 -2400,
625 new ModelDestination(
626 ModelDestination.DESTINATION_FILTER_FREQ)));
627
628
629 performer.getConnectionBlocks().add(
630 new ModelConnectionBlock(
631 new ModelSource(ModelSource.SOURCE_LFO2,
632 ModelStandardTransform.DIRECTION_MIN2MAX,
633 ModelStandardTransform.POLARITY_BIPOLAR,
634 ModelStandardTransform.TRANSFORM_LINEAR),
635 new ModelSource(new ModelIdentifier("midi_cc", "1", 0),
636 ModelStandardTransform.DIRECTION_MIN2MAX,
|