Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/share/classes/com/sun/media/sound/DLSSoundbank.java
41161 views
1
/*
2
* Copyright (c) 2007, 2021, 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.io.File;
29
import java.io.FileInputStream;
30
import java.io.IOException;
31
import java.io.InputStream;
32
import java.io.OutputStream;
33
import java.net.URL;
34
import java.util.ArrayList;
35
import java.util.Arrays;
36
import java.util.HashMap;
37
import java.util.List;
38
import java.util.Map;
39
import java.util.Stack;
40
41
import javax.sound.midi.Instrument;
42
import javax.sound.midi.Patch;
43
import javax.sound.midi.Soundbank;
44
import javax.sound.midi.SoundbankResource;
45
import javax.sound.sampled.AudioFormat;
46
import javax.sound.sampled.AudioFormat.Encoding;
47
import javax.sound.sampled.AudioInputStream;
48
import javax.sound.sampled.AudioSystem;
49
50
/**
51
* A DLS Level 1 and Level 2 soundbank reader (from files/url/streams).
52
*
53
* @author Karl Helgason
54
*/
55
public final class DLSSoundbank implements Soundbank {
56
57
private static class DLSID {
58
long i1;
59
int s1;
60
int s2;
61
int x1;
62
int x2;
63
int x3;
64
int x4;
65
int x5;
66
int x6;
67
int x7;
68
int x8;
69
70
private DLSID() {
71
}
72
73
DLSID(long i1, int s1, int s2, int x1, int x2, int x3, int x4,
74
int x5, int x6, int x7, int x8) {
75
this.i1 = i1;
76
this.s1 = s1;
77
this.s2 = s2;
78
this.x1 = x1;
79
this.x2 = x2;
80
this.x3 = x3;
81
this.x4 = x4;
82
this.x5 = x5;
83
this.x6 = x6;
84
this.x7 = x7;
85
this.x8 = x8;
86
}
87
88
public static DLSID read(RIFFReader riff) throws IOException {
89
DLSID d = new DLSID();
90
d.i1 = riff.readUnsignedInt();
91
d.s1 = riff.readUnsignedShort();
92
d.s2 = riff.readUnsignedShort();
93
d.x1 = riff.readUnsignedByte();
94
d.x2 = riff.readUnsignedByte();
95
d.x3 = riff.readUnsignedByte();
96
d.x4 = riff.readUnsignedByte();
97
d.x5 = riff.readUnsignedByte();
98
d.x6 = riff.readUnsignedByte();
99
d.x7 = riff.readUnsignedByte();
100
d.x8 = riff.readUnsignedByte();
101
return d;
102
}
103
104
@Override
105
public int hashCode() {
106
return (int)i1;
107
}
108
109
@Override
110
public boolean equals(Object obj) {
111
if (!(obj instanceof DLSID)) {
112
return false;
113
}
114
DLSID t = (DLSID) obj;
115
return i1 == t.i1 && s1 == t.s1 && s2 == t.s2
116
&& x1 == t.x1 && x2 == t.x2 && x3 == t.x3 && x4 == t.x4
117
&& x5 == t.x5 && x6 == t.x6 && x7 == t.x7 && x8 == t.x8;
118
}
119
}
120
121
/** X = X & Y */
122
private static final int DLS_CDL_AND = 0x0001;
123
/** X = X | Y */
124
private static final int DLS_CDL_OR = 0x0002;
125
/** X = X ^ Y */
126
private static final int DLS_CDL_XOR = 0x0003;
127
/** X = X + Y */
128
private static final int DLS_CDL_ADD = 0x0004;
129
/** X = X - Y */
130
private static final int DLS_CDL_SUBTRACT = 0x0005;
131
/** X = X * Y */
132
private static final int DLS_CDL_MULTIPLY = 0x0006;
133
/** X = X / Y */
134
private static final int DLS_CDL_DIVIDE = 0x0007;
135
/** X = X && Y */
136
private static final int DLS_CDL_LOGICAL_AND = 0x0008;
137
/** X = X || Y */
138
private static final int DLS_CDL_LOGICAL_OR = 0x0009;
139
/** X = (X < Y) */
140
private static final int DLS_CDL_LT = 0x000A;
141
/** X = (X <= Y) */
142
private static final int DLS_CDL_LE = 0x000B;
143
/** X = (X > Y) */
144
private static final int DLS_CDL_GT = 0x000C;
145
/** X = (X >= Y) */
146
private static final int DLS_CDL_GE = 0x000D;
147
/** X = (X == Y) */
148
private static final int DLS_CDL_EQ = 0x000E;
149
/** X = !X */
150
private static final int DLS_CDL_NOT = 0x000F;
151
/** 32-bit constant */
152
private static final int DLS_CDL_CONST = 0x0010;
153
/** 32-bit value returned from query */
154
private static final int DLS_CDL_QUERY = 0x0011;
155
/** 32-bit value returned from query */
156
private static final int DLS_CDL_QUERYSUPPORTED = 0x0012;
157
158
private static final DLSID DLSID_GMInHardware = new DLSID(0x178f2f24,
159
0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12);
160
private static final DLSID DLSID_GSInHardware = new DLSID(0x178f2f25,
161
0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12);
162
private static final DLSID DLSID_XGInHardware = new DLSID(0x178f2f26,
163
0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12);
164
private static final DLSID DLSID_SupportsDLS1 = new DLSID(0x178f2f27,
165
0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12);
166
private static final DLSID DLSID_SupportsDLS2 = new DLSID(0xf14599e5,
167
0x4689, 0x11d2, 0xaf, 0xa6, 0x0, 0xaa, 0x0, 0x24, 0xd8, 0xb6);
168
private static final DLSID DLSID_SampleMemorySize = new DLSID(0x178f2f28,
169
0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12);
170
private static final DLSID DLSID_ManufacturersID = new DLSID(0xb03e1181,
171
0x8095, 0x11d2, 0xa1, 0xef, 0x0, 0x60, 0x8, 0x33, 0xdb, 0xd8);
172
private static final DLSID DLSID_ProductID = new DLSID(0xb03e1182,
173
0x8095, 0x11d2, 0xa1, 0xef, 0x0, 0x60, 0x8, 0x33, 0xdb, 0xd8);
174
private static final DLSID DLSID_SamplePlaybackRate = new DLSID(0x2a91f713,
175
0xa4bf, 0x11d2, 0xbb, 0xdf, 0x0, 0x60, 0x8, 0x33, 0xdb, 0xd8);
176
177
private long major = -1;
178
private long minor = -1;
179
180
private final DLSInfo info = new DLSInfo();
181
182
private final List<DLSInstrument> instruments = new ArrayList<>();
183
private final List<DLSSample> samples = new ArrayList<>();
184
185
private boolean largeFormat = false;
186
private File sampleFile;
187
188
public DLSSoundbank() {
189
}
190
191
public DLSSoundbank(URL url) throws IOException {
192
InputStream is = url.openStream();
193
try {
194
readSoundbank(is);
195
} finally {
196
is.close();
197
}
198
}
199
200
public DLSSoundbank(File file) throws IOException {
201
largeFormat = true;
202
sampleFile = file;
203
InputStream is = new FileInputStream(file);
204
try {
205
readSoundbank(is);
206
} finally {
207
is.close();
208
}
209
}
210
211
public DLSSoundbank(InputStream inputstream) throws IOException {
212
readSoundbank(inputstream);
213
}
214
215
private void readSoundbank(InputStream inputstream) throws IOException {
216
RIFFReader riff = new RIFFReader(inputstream);
217
if (!riff.getFormat().equals("RIFF")) {
218
throw new RIFFInvalidFormatException(
219
"Input stream is not a valid RIFF stream!");
220
}
221
if (!riff.getType().equals("DLS ")) {
222
throw new RIFFInvalidFormatException(
223
"Input stream is not a valid DLS soundbank!");
224
}
225
while (riff.hasNextChunk()) {
226
RIFFReader chunk = riff.nextChunk();
227
if (chunk.getFormat().equals("LIST")) {
228
if (chunk.getType().equals("INFO"))
229
readInfoChunk(chunk);
230
if (chunk.getType().equals("lins"))
231
readLinsChunk(chunk);
232
if (chunk.getType().equals("wvpl"))
233
readWvplChunk(chunk);
234
} else {
235
if (chunk.getFormat().equals("cdl ")) {
236
if (!readCdlChunk(chunk)) {
237
throw new RIFFInvalidFormatException(
238
"DLS file isn't supported!");
239
}
240
}
241
if (chunk.getFormat().equals("colh")) {
242
// skipped because we will load the entire bank into memory
243
// long instrumentcount = chunk.readUnsignedInt();
244
// System.out.println("instrumentcount = "+ instrumentcount);
245
}
246
if (chunk.getFormat().equals("ptbl")) {
247
// Pool Table Chunk
248
// skipped because we will load the entire bank into memory
249
}
250
if (chunk.getFormat().equals("vers")) {
251
major = chunk.readUnsignedInt();
252
minor = chunk.readUnsignedInt();
253
}
254
}
255
}
256
257
for (Map.Entry<DLSRegion, Long> entry : temp_rgnassign.entrySet()) {
258
entry.getKey().sample = samples.get((int)entry.getValue().longValue());
259
}
260
261
temp_rgnassign = null;
262
}
263
264
private boolean cdlIsQuerySupported(DLSID uuid) {
265
return uuid.equals(DLSID_GMInHardware)
266
|| uuid.equals(DLSID_GSInHardware)
267
|| uuid.equals(DLSID_XGInHardware)
268
|| uuid.equals(DLSID_SupportsDLS1)
269
|| uuid.equals(DLSID_SupportsDLS2)
270
|| uuid.equals(DLSID_SampleMemorySize)
271
|| uuid.equals(DLSID_ManufacturersID)
272
|| uuid.equals(DLSID_ProductID)
273
|| uuid.equals(DLSID_SamplePlaybackRate);
274
}
275
276
private long cdlQuery(DLSID uuid) {
277
if (uuid.equals(DLSID_GMInHardware))
278
return 1;
279
if (uuid.equals(DLSID_GSInHardware))
280
return 0;
281
if (uuid.equals(DLSID_XGInHardware))
282
return 0;
283
if (uuid.equals(DLSID_SupportsDLS1))
284
return 1;
285
if (uuid.equals(DLSID_SupportsDLS2))
286
return 1;
287
if (uuid.equals(DLSID_SampleMemorySize))
288
return Runtime.getRuntime().totalMemory();
289
if (uuid.equals(DLSID_ManufacturersID))
290
return 0;
291
if (uuid.equals(DLSID_ProductID))
292
return 0;
293
if (uuid.equals(DLSID_SamplePlaybackRate))
294
return 44100;
295
return 0;
296
}
297
298
299
// Reading cdl-ck Chunk
300
// "cdl " chunk can only appear inside : DLS,lart,lar2,rgn,rgn2
301
private boolean readCdlChunk(RIFFReader riff) throws IOException {
302
303
DLSID uuid;
304
long x;
305
long y;
306
Stack<Long> stack = new Stack<>();
307
308
while (riff.available() != 0) {
309
int opcode = riff.readUnsignedShort();
310
switch (opcode) {
311
case DLS_CDL_AND:
312
x = stack.pop();
313
y = stack.pop();
314
stack.push(Long.valueOf(((x != 0) && (y != 0)) ? 1 : 0));
315
break;
316
case DLS_CDL_OR:
317
x = stack.pop();
318
y = stack.pop();
319
stack.push(Long.valueOf(((x != 0) || (y != 0)) ? 1 : 0));
320
break;
321
case DLS_CDL_XOR:
322
x = stack.pop();
323
y = stack.pop();
324
stack.push(Long.valueOf(((x != 0) ^ (y != 0)) ? 1 : 0));
325
break;
326
case DLS_CDL_ADD:
327
x = stack.pop();
328
y = stack.pop();
329
stack.push(Long.valueOf(x + y));
330
break;
331
case DLS_CDL_SUBTRACT:
332
x = stack.pop();
333
y = stack.pop();
334
stack.push(Long.valueOf(x - y));
335
break;
336
case DLS_CDL_MULTIPLY:
337
x = stack.pop();
338
y = stack.pop();
339
stack.push(Long.valueOf(x * y));
340
break;
341
case DLS_CDL_DIVIDE:
342
x = stack.pop();
343
y = stack.pop();
344
stack.push(Long.valueOf(x / y));
345
break;
346
case DLS_CDL_LOGICAL_AND:
347
x = stack.pop();
348
y = stack.pop();
349
stack.push(Long.valueOf(((x != 0) && (y != 0)) ? 1 : 0));
350
break;
351
case DLS_CDL_LOGICAL_OR:
352
x = stack.pop();
353
y = stack.pop();
354
stack.push(Long.valueOf(((x != 0) || (y != 0)) ? 1 : 0));
355
break;
356
case DLS_CDL_LT:
357
x = stack.pop();
358
y = stack.pop();
359
stack.push(Long.valueOf((x < y) ? 1 : 0));
360
break;
361
case DLS_CDL_LE:
362
x = stack.pop();
363
y = stack.pop();
364
stack.push(Long.valueOf((x <= y) ? 1 : 0));
365
break;
366
case DLS_CDL_GT:
367
x = stack.pop();
368
y = stack.pop();
369
stack.push(Long.valueOf((x > y) ? 1 : 0));
370
break;
371
case DLS_CDL_GE:
372
x = stack.pop();
373
y = stack.pop();
374
stack.push(Long.valueOf((x >= y) ? 1 : 0));
375
break;
376
case DLS_CDL_EQ:
377
x = stack.pop();
378
y = stack.pop();
379
stack.push(Long.valueOf((x == y) ? 1 : 0));
380
break;
381
case DLS_CDL_NOT:
382
x = stack.pop();
383
y = stack.pop();
384
stack.push(Long.valueOf((x == 0) ? 1 : 0));
385
break;
386
case DLS_CDL_CONST:
387
stack.push(Long.valueOf(riff.readUnsignedInt()));
388
break;
389
case DLS_CDL_QUERY:
390
uuid = DLSID.read(riff);
391
stack.push(cdlQuery(uuid));
392
break;
393
case DLS_CDL_QUERYSUPPORTED:
394
uuid = DLSID.read(riff);
395
stack.push(Long.valueOf(cdlIsQuerySupported(uuid) ? 1 : 0));
396
break;
397
default:
398
break;
399
}
400
}
401
if (stack.isEmpty())
402
return false;
403
404
return stack.pop() == 1;
405
}
406
407
private void readInfoChunk(RIFFReader riff) throws IOException {
408
info.name = null;
409
while (riff.hasNextChunk()) {
410
RIFFReader chunk = riff.nextChunk();
411
String format = chunk.getFormat();
412
if (format.equals("INAM"))
413
info.name = chunk.readString(chunk.available());
414
else if (format.equals("ICRD"))
415
info.creationDate = chunk.readString(chunk.available());
416
else if (format.equals("IENG"))
417
info.engineers = chunk.readString(chunk.available());
418
else if (format.equals("IPRD"))
419
info.product = chunk.readString(chunk.available());
420
else if (format.equals("ICOP"))
421
info.copyright = chunk.readString(chunk.available());
422
else if (format.equals("ICMT"))
423
info.comments = chunk.readString(chunk.available());
424
else if (format.equals("ISFT"))
425
info.tools = chunk.readString(chunk.available());
426
else if (format.equals("IARL"))
427
info.archival_location = chunk.readString(chunk.available());
428
else if (format.equals("IART"))
429
info.artist = chunk.readString(chunk.available());
430
else if (format.equals("ICMS"))
431
info.commissioned = chunk.readString(chunk.available());
432
else if (format.equals("IGNR"))
433
info.genre = chunk.readString(chunk.available());
434
else if (format.equals("IKEY"))
435
info.keywords = chunk.readString(chunk.available());
436
else if (format.equals("IMED"))
437
info.medium = chunk.readString(chunk.available());
438
else if (format.equals("ISBJ"))
439
info.subject = chunk.readString(chunk.available());
440
else if (format.equals("ISRC"))
441
info.source = chunk.readString(chunk.available());
442
else if (format.equals("ISRF"))
443
info.source_form = chunk.readString(chunk.available());
444
else if (format.equals("ITCH"))
445
info.technician = chunk.readString(chunk.available());
446
}
447
}
448
449
private void readLinsChunk(RIFFReader riff) throws IOException {
450
while (riff.hasNextChunk()) {
451
RIFFReader chunk = riff.nextChunk();
452
if (chunk.getFormat().equals("LIST")) {
453
if (chunk.getType().equals("ins "))
454
readInsChunk(chunk);
455
}
456
}
457
}
458
459
private void readInsChunk(RIFFReader riff) throws IOException {
460
DLSInstrument instrument = new DLSInstrument(this);
461
462
while (riff.hasNextChunk()) {
463
RIFFReader chunk = riff.nextChunk();
464
String format = chunk.getFormat();
465
if (format.equals("LIST")) {
466
if (chunk.getType().equals("INFO")) {
467
readInsInfoChunk(instrument, chunk);
468
}
469
if (chunk.getType().equals("lrgn")) {
470
while (chunk.hasNextChunk()) {
471
RIFFReader subchunk = chunk.nextChunk();
472
if (subchunk.getFormat().equals("LIST")) {
473
if (subchunk.getType().equals("rgn ")) {
474
DLSRegion split = new DLSRegion();
475
if (readRgnChunk(split, subchunk))
476
instrument.getRegions().add(split);
477
}
478
if (subchunk.getType().equals("rgn2")) {
479
// support for DLS level 2 regions
480
DLSRegion split = new DLSRegion();
481
if (readRgnChunk(split, subchunk))
482
instrument.getRegions().add(split);
483
}
484
}
485
}
486
}
487
if (chunk.getType().equals("lart")) {
488
List<DLSModulator> modlist = new ArrayList<>();
489
while (chunk.hasNextChunk()) {
490
RIFFReader subchunk = chunk.nextChunk();
491
if (chunk.getFormat().equals("cdl ")) {
492
if (!readCdlChunk(chunk)) {
493
modlist.clear();
494
break;
495
}
496
}
497
if (subchunk.getFormat().equals("art1"))
498
readArt1Chunk(modlist, subchunk);
499
}
500
instrument.getModulators().addAll(modlist);
501
}
502
if (chunk.getType().equals("lar2")) {
503
// support for DLS level 2 ART
504
List<DLSModulator> modlist = new ArrayList<>();
505
while (chunk.hasNextChunk()) {
506
RIFFReader subchunk = chunk.nextChunk();
507
if (chunk.getFormat().equals("cdl ")) {
508
if (!readCdlChunk(chunk)) {
509
modlist.clear();
510
break;
511
}
512
}
513
if (subchunk.getFormat().equals("art2"))
514
readArt2Chunk(modlist, subchunk);
515
}
516
instrument.getModulators().addAll(modlist);
517
}
518
} else {
519
if (format.equals("dlid")) {
520
instrument.guid = new byte[16];
521
chunk.readFully(instrument.guid);
522
}
523
if (format.equals("insh")) {
524
chunk.readUnsignedInt(); // Read Region Count - ignored
525
526
int bank = chunk.read(); // LSB
527
bank += (chunk.read() & 127) << 7; // MSB
528
chunk.read(); // Read Reserved byte
529
int drumins = chunk.read(); // Drum Instrument
530
531
int id = chunk.read() & 127; // Read only first 7 bits
532
chunk.read(); // Read Reserved byte
533
chunk.read(); // Read Reserved byte
534
chunk.read(); // Read Reserved byte
535
536
instrument.bank = bank;
537
instrument.preset = id;
538
instrument.druminstrument = (drumins & 128) > 0;
539
//System.out.println("bank="+bank+" drumkit="+drumkit
540
// +" id="+id);
541
}
542
543
}
544
}
545
instruments.add(instrument);
546
}
547
548
private void readArt1Chunk(List<DLSModulator> modulators, RIFFReader riff)
549
throws IOException {
550
long size = riff.readUnsignedInt();
551
long count = riff.readUnsignedInt();
552
553
if (size - 8 != 0)
554
riff.skip(size - 8);
555
556
for (int i = 0; i < count; i++) {
557
DLSModulator modulator = new DLSModulator();
558
modulator.version = 1;
559
modulator.source = riff.readUnsignedShort();
560
modulator.control = riff.readUnsignedShort();
561
modulator.destination = riff.readUnsignedShort();
562
modulator.transform = riff.readUnsignedShort();
563
modulator.scale = riff.readInt();
564
modulators.add(modulator);
565
}
566
}
567
568
private void readArt2Chunk(List<DLSModulator> modulators, RIFFReader riff)
569
throws IOException {
570
long size = riff.readUnsignedInt();
571
long count = riff.readUnsignedInt();
572
573
if (size - 8 != 0)
574
riff.skip(size - 8);
575
576
for (int i = 0; i < count; i++) {
577
DLSModulator modulator = new DLSModulator();
578
modulator.version = 2;
579
modulator.source = riff.readUnsignedShort();
580
modulator.control = riff.readUnsignedShort();
581
modulator.destination = riff.readUnsignedShort();
582
modulator.transform = riff.readUnsignedShort();
583
modulator.scale = riff.readInt();
584
modulators.add(modulator);
585
}
586
}
587
588
private Map<DLSRegion, Long> temp_rgnassign = new HashMap<>();
589
590
private boolean readRgnChunk(DLSRegion split, RIFFReader riff)
591
throws IOException {
592
while (riff.hasNextChunk()) {
593
RIFFReader chunk = riff.nextChunk();
594
String format = chunk.getFormat();
595
if (format.equals("LIST")) {
596
if (chunk.getType().equals("lart")) {
597
List<DLSModulator> modlist = new ArrayList<>();
598
while (chunk.hasNextChunk()) {
599
RIFFReader subchunk = chunk.nextChunk();
600
if (chunk.getFormat().equals("cdl ")) {
601
if (!readCdlChunk(chunk)) {
602
modlist.clear();
603
break;
604
}
605
}
606
if (subchunk.getFormat().equals("art1"))
607
readArt1Chunk(modlist, subchunk);
608
}
609
split.getModulators().addAll(modlist);
610
}
611
if (chunk.getType().equals("lar2")) {
612
// support for DLS level 2 ART
613
List<DLSModulator> modlist = new ArrayList<>();
614
while (chunk.hasNextChunk()) {
615
RIFFReader subchunk = chunk.nextChunk();
616
if (chunk.getFormat().equals("cdl ")) {
617
if (!readCdlChunk(chunk)) {
618
modlist.clear();
619
break;
620
}
621
}
622
if (subchunk.getFormat().equals("art2"))
623
readArt2Chunk(modlist, subchunk);
624
}
625
split.getModulators().addAll(modlist);
626
}
627
} else {
628
629
if (format.equals("cdl ")) {
630
if (!readCdlChunk(chunk))
631
return false;
632
}
633
if (format.equals("rgnh")) {
634
split.keyfrom = chunk.readUnsignedShort();
635
split.keyto = chunk.readUnsignedShort();
636
split.velfrom = chunk.readUnsignedShort();
637
split.velto = chunk.readUnsignedShort();
638
split.options = chunk.readUnsignedShort();
639
split.exclusiveClass = chunk.readUnsignedShort();
640
}
641
if (format.equals("wlnk")) {
642
split.fusoptions = chunk.readUnsignedShort();
643
split.phasegroup = chunk.readUnsignedShort();
644
split.channel = chunk.readUnsignedInt();
645
long sampleid = chunk.readUnsignedInt();
646
temp_rgnassign.put(split, sampleid);
647
}
648
if (format.equals("wsmp")) {
649
split.sampleoptions = new DLSSampleOptions();
650
readWsmpChunk(split.sampleoptions, chunk);
651
}
652
}
653
}
654
return true;
655
}
656
657
private void readWsmpChunk(DLSSampleOptions sampleOptions, RIFFReader riff)
658
throws IOException {
659
long size = riff.readUnsignedInt();
660
sampleOptions.unitynote = riff.readUnsignedShort();
661
sampleOptions.finetune = riff.readShort();
662
sampleOptions.attenuation = riff.readInt();
663
sampleOptions.options = riff.readUnsignedInt();
664
long loops = riff.readInt();
665
666
if (size > 20)
667
riff.skip(size - 20);
668
669
for (int i = 0; i < loops; i++) {
670
DLSSampleLoop loop = new DLSSampleLoop();
671
long size2 = riff.readUnsignedInt();
672
loop.type = riff.readUnsignedInt();
673
loop.start = riff.readUnsignedInt();
674
loop.length = riff.readUnsignedInt();
675
sampleOptions.loops.add(loop);
676
if (size2 > 16)
677
riff.skip(size2 - 16);
678
}
679
}
680
681
private void readInsInfoChunk(DLSInstrument dlsinstrument, RIFFReader riff)
682
throws IOException {
683
dlsinstrument.info.name = null;
684
while (riff.hasNextChunk()) {
685
RIFFReader chunk = riff.nextChunk();
686
String format = chunk.getFormat();
687
if (format.equals("INAM")) {
688
dlsinstrument.info.name = chunk.readString(chunk.available());
689
} else if (format.equals("ICRD")) {
690
dlsinstrument.info.creationDate =
691
chunk.readString(chunk.available());
692
} else if (format.equals("IENG")) {
693
dlsinstrument.info.engineers =
694
chunk.readString(chunk.available());
695
} else if (format.equals("IPRD")) {
696
dlsinstrument.info.product = chunk.readString(chunk.available());
697
} else if (format.equals("ICOP")) {
698
dlsinstrument.info.copyright =
699
chunk.readString(chunk.available());
700
} else if (format.equals("ICMT")) {
701
dlsinstrument.info.comments =
702
chunk.readString(chunk.available());
703
} else if (format.equals("ISFT")) {
704
dlsinstrument.info.tools = chunk.readString(chunk.available());
705
} else if (format.equals("IARL")) {
706
dlsinstrument.info.archival_location =
707
chunk.readString(chunk.available());
708
} else if (format.equals("IART")) {
709
dlsinstrument.info.artist = chunk.readString(chunk.available());
710
} else if (format.equals("ICMS")) {
711
dlsinstrument.info.commissioned =
712
chunk.readString(chunk.available());
713
} else if (format.equals("IGNR")) {
714
dlsinstrument.info.genre = chunk.readString(chunk.available());
715
} else if (format.equals("IKEY")) {
716
dlsinstrument.info.keywords =
717
chunk.readString(chunk.available());
718
} else if (format.equals("IMED")) {
719
dlsinstrument.info.medium = chunk.readString(chunk.available());
720
} else if (format.equals("ISBJ")) {
721
dlsinstrument.info.subject = chunk.readString(chunk.available());
722
} else if (format.equals("ISRC")) {
723
dlsinstrument.info.source = chunk.readString(chunk.available());
724
} else if (format.equals("ISRF")) {
725
dlsinstrument.info.source_form =
726
chunk.readString(chunk.available());
727
} else if (format.equals("ITCH")) {
728
dlsinstrument.info.technician =
729
chunk.readString(chunk.available());
730
}
731
}
732
}
733
734
private void readWvplChunk(RIFFReader riff) throws IOException {
735
while (riff.hasNextChunk()) {
736
RIFFReader chunk = riff.nextChunk();
737
if (chunk.getFormat().equals("LIST")) {
738
if (chunk.getType().equals("wave"))
739
readWaveChunk(chunk);
740
}
741
}
742
}
743
744
private void readWaveChunk(RIFFReader riff) throws IOException {
745
DLSSample sample = new DLSSample(this);
746
747
while (riff.hasNextChunk()) {
748
RIFFReader chunk = riff.nextChunk();
749
String format = chunk.getFormat();
750
if (format.equals("LIST")) {
751
if (chunk.getType().equals("INFO")) {
752
readWaveInfoChunk(sample, chunk);
753
}
754
} else {
755
if (format.equals("dlid")) {
756
sample.guid = new byte[16];
757
chunk.readFully(sample.guid);
758
}
759
760
if (format.equals("fmt ")) {
761
int sampleformat = chunk.readUnsignedShort();
762
if (sampleformat != 1 && sampleformat != 3) {
763
throw new RIFFInvalidDataException(
764
"Only PCM samples are supported!");
765
}
766
int channels = chunk.readUnsignedShort();
767
long samplerate = chunk.readUnsignedInt();
768
// bytes per sec
769
/* long framerate = */ chunk.readUnsignedInt();
770
// block align, framesize
771
int framesize = chunk.readUnsignedShort();
772
int bits = chunk.readUnsignedShort();
773
AudioFormat audioformat = null;
774
if (sampleformat == 1) {
775
if (bits == 8) {
776
audioformat = new AudioFormat(
777
Encoding.PCM_UNSIGNED, samplerate, bits,
778
channels, framesize, samplerate, false);
779
} else {
780
audioformat = new AudioFormat(
781
Encoding.PCM_SIGNED, samplerate, bits,
782
channels, framesize, samplerate, false);
783
}
784
}
785
if (sampleformat == 3) {
786
audioformat = new AudioFormat(
787
Encoding.PCM_FLOAT, samplerate, bits,
788
channels, framesize, samplerate, false);
789
}
790
791
sample.format = audioformat;
792
}
793
794
if (format.equals("data")) {
795
if (largeFormat) {
796
sample.setData(new ModelByteBuffer(sampleFile,
797
chunk.getFilePointer(), chunk.available()));
798
} else {
799
byte[] buffer = new byte[chunk.available()];
800
// chunk.read(buffer);
801
sample.setData(buffer);
802
803
int read = 0;
804
int avail = chunk.available();
805
while (read != avail) {
806
if (avail - read > 65536) {
807
chunk.readFully(buffer, read, 65536);
808
read += 65536;
809
} else {
810
chunk.readFully(buffer, read, avail - read);
811
read = avail;
812
}
813
}
814
}
815
}
816
817
if (format.equals("wsmp")) {
818
sample.sampleoptions = new DLSSampleOptions();
819
readWsmpChunk(sample.sampleoptions, chunk);
820
}
821
}
822
}
823
824
samples.add(sample);
825
826
}
827
828
private void readWaveInfoChunk(DLSSample dlssample, RIFFReader riff)
829
throws IOException {
830
dlssample.info.name = null;
831
while (riff.hasNextChunk()) {
832
RIFFReader chunk = riff.nextChunk();
833
String format = chunk.getFormat();
834
if (format.equals("INAM")) {
835
dlssample.info.name = chunk.readString(chunk.available());
836
} else if (format.equals("ICRD")) {
837
dlssample.info.creationDate =
838
chunk.readString(chunk.available());
839
} else if (format.equals("IENG")) {
840
dlssample.info.engineers = chunk.readString(chunk.available());
841
} else if (format.equals("IPRD")) {
842
dlssample.info.product = chunk.readString(chunk.available());
843
} else if (format.equals("ICOP")) {
844
dlssample.info.copyright = chunk.readString(chunk.available());
845
} else if (format.equals("ICMT")) {
846
dlssample.info.comments = chunk.readString(chunk.available());
847
} else if (format.equals("ISFT")) {
848
dlssample.info.tools = chunk.readString(chunk.available());
849
} else if (format.equals("IARL")) {
850
dlssample.info.archival_location =
851
chunk.readString(chunk.available());
852
} else if (format.equals("IART")) {
853
dlssample.info.artist = chunk.readString(chunk.available());
854
} else if (format.equals("ICMS")) {
855
dlssample.info.commissioned =
856
chunk.readString(chunk.available());
857
} else if (format.equals("IGNR")) {
858
dlssample.info.genre = chunk.readString(chunk.available());
859
} else if (format.equals("IKEY")) {
860
dlssample.info.keywords = chunk.readString(chunk.available());
861
} else if (format.equals("IMED")) {
862
dlssample.info.medium = chunk.readString(chunk.available());
863
} else if (format.equals("ISBJ")) {
864
dlssample.info.subject = chunk.readString(chunk.available());
865
} else if (format.equals("ISRC")) {
866
dlssample.info.source = chunk.readString(chunk.available());
867
} else if (format.equals("ISRF")) {
868
dlssample.info.source_form = chunk.readString(chunk.available());
869
} else if (format.equals("ITCH")) {
870
dlssample.info.technician = chunk.readString(chunk.available());
871
}
872
}
873
}
874
875
public void save(String name) throws IOException {
876
writeSoundbank(new RIFFWriter(name, "DLS "));
877
}
878
879
public void save(File file) throws IOException {
880
writeSoundbank(new RIFFWriter(file, "DLS "));
881
}
882
883
public void save(OutputStream out) throws IOException {
884
writeSoundbank(new RIFFWriter(out, "DLS "));
885
}
886
887
private void writeSoundbank(RIFFWriter writer) throws IOException {
888
RIFFWriter colh_chunk = writer.writeChunk("colh");
889
colh_chunk.writeUnsignedInt(instruments.size());
890
891
if (major != -1 && minor != -1) {
892
RIFFWriter vers_chunk = writer.writeChunk("vers");
893
vers_chunk.writeUnsignedInt(major);
894
vers_chunk.writeUnsignedInt(minor);
895
}
896
897
writeInstruments(writer.writeList("lins"));
898
899
RIFFWriter ptbl = writer.writeChunk("ptbl");
900
ptbl.writeUnsignedInt(8);
901
ptbl.writeUnsignedInt(samples.size());
902
long ptbl_offset = writer.getFilePointer();
903
for (int i = 0; i < samples.size(); i++)
904
ptbl.writeUnsignedInt(0);
905
906
RIFFWriter wvpl = writer.writeList("wvpl");
907
long off = wvpl.getFilePointer();
908
List<Long> offsettable = new ArrayList<>();
909
for (DLSSample sample : samples) {
910
offsettable.add(Long.valueOf(wvpl.getFilePointer() - off));
911
writeSample(wvpl.writeList("wave"), sample);
912
}
913
914
// small cheat, we are going to rewrite data back in wvpl
915
long bak = writer.getFilePointer();
916
writer.seek(ptbl_offset);
917
writer.setWriteOverride(true);
918
for (Long offset : offsettable)
919
writer.writeUnsignedInt(offset.longValue());
920
writer.setWriteOverride(false);
921
writer.seek(bak);
922
923
writeInfo(writer.writeList("INFO"), info);
924
925
writer.close();
926
}
927
928
private void writeSample(RIFFWriter writer, DLSSample sample)
929
throws IOException {
930
931
AudioFormat audioformat = sample.getFormat();
932
933
Encoding encoding = audioformat.getEncoding();
934
float sampleRate = audioformat.getSampleRate();
935
int sampleSizeInBits = audioformat.getSampleSizeInBits();
936
int channels = audioformat.getChannels();
937
int frameSize = audioformat.getFrameSize();
938
float frameRate = audioformat.getFrameRate();
939
boolean bigEndian = audioformat.isBigEndian();
940
941
boolean convert_needed = false;
942
943
if (audioformat.getSampleSizeInBits() == 8) {
944
if (!encoding.equals(Encoding.PCM_UNSIGNED)) {
945
encoding = Encoding.PCM_UNSIGNED;
946
convert_needed = true;
947
}
948
} else {
949
if (!encoding.equals(Encoding.PCM_SIGNED)) {
950
encoding = Encoding.PCM_SIGNED;
951
convert_needed = true;
952
}
953
if (bigEndian) {
954
bigEndian = false;
955
convert_needed = true;
956
}
957
}
958
959
if (convert_needed) {
960
audioformat = new AudioFormat(encoding, sampleRate,
961
sampleSizeInBits, channels, frameSize, frameRate, bigEndian);
962
}
963
964
// fmt
965
RIFFWriter fmt_chunk = writer.writeChunk("fmt ");
966
int sampleformat = 0;
967
if (audioformat.getEncoding().equals(Encoding.PCM_UNSIGNED))
968
sampleformat = 1;
969
else if (audioformat.getEncoding().equals(Encoding.PCM_SIGNED))
970
sampleformat = 1;
971
else if (audioformat.getEncoding().equals(Encoding.PCM_FLOAT))
972
sampleformat = 3;
973
974
fmt_chunk.writeUnsignedShort(sampleformat);
975
fmt_chunk.writeUnsignedShort(audioformat.getChannels());
976
fmt_chunk.writeUnsignedInt((long) audioformat.getSampleRate());
977
long srate = ((long)audioformat.getFrameRate())*audioformat.getFrameSize();
978
fmt_chunk.writeUnsignedInt(srate);
979
fmt_chunk.writeUnsignedShort(audioformat.getFrameSize());
980
fmt_chunk.writeUnsignedShort(audioformat.getSampleSizeInBits());
981
fmt_chunk.write(0);
982
fmt_chunk.write(0);
983
984
writeSampleOptions(writer.writeChunk("wsmp"), sample.sampleoptions);
985
986
if (convert_needed) {
987
RIFFWriter data_chunk = writer.writeChunk("data");
988
AudioInputStream stream = AudioSystem.getAudioInputStream(
989
audioformat, (AudioInputStream)sample.getData());
990
stream.transferTo(data_chunk);
991
} else {
992
RIFFWriter data_chunk = writer.writeChunk("data");
993
ModelByteBuffer databuff = sample.getDataBuffer();
994
databuff.writeTo(data_chunk);
995
/*
996
data_chunk.write(databuff.array(),
997
databuff.arrayOffset(),
998
databuff.capacity());
999
*/
1000
}
1001
1002
writeInfo(writer.writeList("INFO"), sample.info);
1003
}
1004
1005
private void writeInstruments(RIFFWriter writer) throws IOException {
1006
for (DLSInstrument instrument : instruments) {
1007
writeInstrument(writer.writeList("ins "), instrument);
1008
}
1009
}
1010
1011
private void writeInstrument(RIFFWriter writer, DLSInstrument instrument)
1012
throws IOException {
1013
1014
int art1_count = 0;
1015
int art2_count = 0;
1016
for (DLSModulator modulator : instrument.getModulators()) {
1017
if (modulator.version == 1)
1018
art1_count++;
1019
if (modulator.version == 2)
1020
art2_count++;
1021
}
1022
for (DLSRegion region : instrument.regions) {
1023
for (DLSModulator modulator : region.getModulators()) {
1024
if (modulator.version == 1)
1025
art1_count++;
1026
if (modulator.version == 2)
1027
art2_count++;
1028
}
1029
}
1030
1031
int version = 1;
1032
if (art2_count > 0)
1033
version = 2;
1034
1035
RIFFWriter insh_chunk = writer.writeChunk("insh");
1036
insh_chunk.writeUnsignedInt(instrument.getRegions().size());
1037
insh_chunk.writeUnsignedInt(instrument.bank +
1038
(instrument.druminstrument ? 2147483648L : 0));
1039
insh_chunk.writeUnsignedInt(instrument.preset);
1040
1041
RIFFWriter lrgn = writer.writeList("lrgn");
1042
for (DLSRegion region: instrument.regions)
1043
writeRegion(lrgn, region, version);
1044
1045
writeArticulators(writer, instrument.getModulators());
1046
1047
writeInfo(writer.writeList("INFO"), instrument.info);
1048
1049
}
1050
1051
private void writeArticulators(RIFFWriter writer,
1052
List<DLSModulator> modulators) throws IOException {
1053
int art1_count = 0;
1054
int art2_count = 0;
1055
for (DLSModulator modulator : modulators) {
1056
if (modulator.version == 1)
1057
art1_count++;
1058
if (modulator.version == 2)
1059
art2_count++;
1060
}
1061
if (art1_count > 0) {
1062
RIFFWriter lar1 = writer.writeList("lart");
1063
RIFFWriter art1 = lar1.writeChunk("art1");
1064
art1.writeUnsignedInt(8);
1065
art1.writeUnsignedInt(art1_count);
1066
for (DLSModulator modulator : modulators) {
1067
if (modulator.version == 1) {
1068
art1.writeUnsignedShort(modulator.source);
1069
art1.writeUnsignedShort(modulator.control);
1070
art1.writeUnsignedShort(modulator.destination);
1071
art1.writeUnsignedShort(modulator.transform);
1072
art1.writeInt(modulator.scale);
1073
}
1074
}
1075
}
1076
if (art2_count > 0) {
1077
RIFFWriter lar2 = writer.writeList("lar2");
1078
RIFFWriter art2 = lar2.writeChunk("art2");
1079
art2.writeUnsignedInt(8);
1080
art2.writeUnsignedInt(art2_count);
1081
for (DLSModulator modulator : modulators) {
1082
if (modulator.version == 2) {
1083
art2.writeUnsignedShort(modulator.source);
1084
art2.writeUnsignedShort(modulator.control);
1085
art2.writeUnsignedShort(modulator.destination);
1086
art2.writeUnsignedShort(modulator.transform);
1087
art2.writeInt(modulator.scale);
1088
}
1089
}
1090
}
1091
}
1092
1093
private void writeRegion(RIFFWriter writer, DLSRegion region, int version)
1094
throws IOException {
1095
RIFFWriter rgns = null;
1096
if (version == 1)
1097
rgns = writer.writeList("rgn ");
1098
if (version == 2)
1099
rgns = writer.writeList("rgn2");
1100
if (rgns == null)
1101
return;
1102
1103
RIFFWriter rgnh = rgns.writeChunk("rgnh");
1104
rgnh.writeUnsignedShort(region.keyfrom);
1105
rgnh.writeUnsignedShort(region.keyto);
1106
rgnh.writeUnsignedShort(region.velfrom);
1107
rgnh.writeUnsignedShort(region.velto);
1108
rgnh.writeUnsignedShort(region.options);
1109
rgnh.writeUnsignedShort(region.exclusiveClass);
1110
1111
if (region.sampleoptions != null)
1112
writeSampleOptions(rgns.writeChunk("wsmp"), region.sampleoptions);
1113
1114
if (region.sample != null) {
1115
if (samples.indexOf(region.sample) != -1) {
1116
RIFFWriter wlnk = rgns.writeChunk("wlnk");
1117
wlnk.writeUnsignedShort(region.fusoptions);
1118
wlnk.writeUnsignedShort(region.phasegroup);
1119
wlnk.writeUnsignedInt(region.channel);
1120
wlnk.writeUnsignedInt(samples.indexOf(region.sample));
1121
}
1122
}
1123
writeArticulators(rgns, region.getModulators());
1124
rgns.close();
1125
}
1126
1127
private void writeSampleOptions(RIFFWriter wsmp,
1128
DLSSampleOptions sampleoptions) throws IOException {
1129
wsmp.writeUnsignedInt(20);
1130
wsmp.writeUnsignedShort(sampleoptions.unitynote);
1131
wsmp.writeShort(sampleoptions.finetune);
1132
wsmp.writeInt(sampleoptions.attenuation);
1133
wsmp.writeUnsignedInt(sampleoptions.options);
1134
wsmp.writeInt(sampleoptions.loops.size());
1135
1136
for (DLSSampleLoop loop : sampleoptions.loops) {
1137
wsmp.writeUnsignedInt(16);
1138
wsmp.writeUnsignedInt(loop.type);
1139
wsmp.writeUnsignedInt(loop.start);
1140
wsmp.writeUnsignedInt(loop.length);
1141
}
1142
}
1143
1144
private void writeInfoStringChunk(RIFFWriter writer,
1145
String name, String value) throws IOException {
1146
if (value == null)
1147
return;
1148
RIFFWriter chunk = writer.writeChunk(name);
1149
chunk.writeString(value);
1150
int len = value.getBytes("ascii").length;
1151
chunk.write(0);
1152
len++;
1153
if (len % 2 != 0)
1154
chunk.write(0);
1155
}
1156
1157
private void writeInfo(RIFFWriter writer, DLSInfo info) throws IOException {
1158
writeInfoStringChunk(writer, "INAM", info.name);
1159
writeInfoStringChunk(writer, "ICRD", info.creationDate);
1160
writeInfoStringChunk(writer, "IENG", info.engineers);
1161
writeInfoStringChunk(writer, "IPRD", info.product);
1162
writeInfoStringChunk(writer, "ICOP", info.copyright);
1163
writeInfoStringChunk(writer, "ICMT", info.comments);
1164
writeInfoStringChunk(writer, "ISFT", info.tools);
1165
writeInfoStringChunk(writer, "IARL", info.archival_location);
1166
writeInfoStringChunk(writer, "IART", info.artist);
1167
writeInfoStringChunk(writer, "ICMS", info.commissioned);
1168
writeInfoStringChunk(writer, "IGNR", info.genre);
1169
writeInfoStringChunk(writer, "IKEY", info.keywords);
1170
writeInfoStringChunk(writer, "IMED", info.medium);
1171
writeInfoStringChunk(writer, "ISBJ", info.subject);
1172
writeInfoStringChunk(writer, "ISRC", info.source);
1173
writeInfoStringChunk(writer, "ISRF", info.source_form);
1174
writeInfoStringChunk(writer, "ITCH", info.technician);
1175
}
1176
1177
public DLSInfo getInfo() {
1178
return info;
1179
}
1180
1181
@Override
1182
public String getName() {
1183
return info.name;
1184
}
1185
1186
@Override
1187
public String getVersion() {
1188
return major + "." + minor;
1189
}
1190
1191
@Override
1192
public String getVendor() {
1193
return info.engineers;
1194
}
1195
1196
@Override
1197
public String getDescription() {
1198
return info.comments;
1199
}
1200
1201
public void setName(String s) {
1202
info.name = s;
1203
}
1204
1205
public void setVendor(String s) {
1206
info.engineers = s;
1207
}
1208
1209
public void setDescription(String s) {
1210
info.comments = s;
1211
}
1212
1213
@Override
1214
public SoundbankResource[] getResources() {
1215
SoundbankResource[] resources = new SoundbankResource[samples.size()];
1216
int j = 0;
1217
for (int i = 0; i < samples.size(); i++)
1218
resources[j++] = samples.get(i);
1219
return resources;
1220
}
1221
1222
@Override
1223
public DLSInstrument[] getInstruments() {
1224
DLSInstrument[] inslist_array =
1225
instruments.toArray(new DLSInstrument[instruments.size()]);
1226
Arrays.sort(inslist_array, new ModelInstrumentComparator());
1227
return inslist_array;
1228
}
1229
1230
public DLSSample[] getSamples() {
1231
return samples.toArray(new DLSSample[samples.size()]);
1232
}
1233
1234
@Override
1235
public Instrument getInstrument(Patch patch) {
1236
int program = patch.getProgram();
1237
int bank = patch.getBank();
1238
boolean percussion = false;
1239
if (patch instanceof ModelPatch)
1240
percussion = ((ModelPatch) patch).isPercussion();
1241
for (Instrument instrument : instruments) {
1242
Patch patch2 = instrument.getPatch();
1243
int program2 = patch2.getProgram();
1244
int bank2 = patch2.getBank();
1245
if (program == program2 && bank == bank2) {
1246
boolean percussion2 = false;
1247
if (patch2 instanceof ModelPatch)
1248
percussion2 = ((ModelPatch) patch2).isPercussion();
1249
if (percussion == percussion2)
1250
return instrument;
1251
}
1252
}
1253
return null;
1254
}
1255
1256
public void addResource(SoundbankResource resource) {
1257
if (resource instanceof DLSInstrument)
1258
instruments.add((DLSInstrument) resource);
1259
if (resource instanceof DLSSample)
1260
samples.add((DLSSample) resource);
1261
}
1262
1263
public void removeResource(SoundbankResource resource) {
1264
if (resource instanceof DLSInstrument)
1265
instruments.remove(resource);
1266
if (resource instanceof DLSSample)
1267
samples.remove(resource);
1268
}
1269
1270
public void addInstrument(DLSInstrument resource) {
1271
instruments.add(resource);
1272
}
1273
1274
public void removeInstrument(DLSInstrument resource) {
1275
instruments.remove(resource);
1276
}
1277
1278
public long getMajor() {
1279
return major;
1280
}
1281
1282
public void setMajor(long major) {
1283
this.major = major;
1284
}
1285
1286
public long getMinor() {
1287
return minor;
1288
}
1289
1290
public void setMinor(long minor) {
1291
this.minor = minor;
1292
}
1293
}
1294
1295