1 /* 2 * Copyright (c) 2007, 2014, 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 byte[] buff = new byte[1024]; 991 int ret; 992 while ((ret = stream.read(buff)) != -1) { 993 data_chunk.write(buff, 0, ret); 994 } 995 } else { 996 RIFFWriter data_chunk = writer.writeChunk("data"); 997 ModelByteBuffer databuff = sample.getDataBuffer(); 998 databuff.writeTo(data_chunk); 999 /* 1000 data_chunk.write(databuff.array(), 1001 databuff.arrayOffset(), 1002 databuff.capacity()); 1003 */ 1004 } 1005 1006 writeInfo(writer.writeList("INFO"), sample.info); 1007 } 1008 1009 private void writeInstruments(RIFFWriter writer) throws IOException { 1010 for (DLSInstrument instrument : instruments) { 1011 writeInstrument(writer.writeList("ins "), instrument); 1012 } 1013 } 1014 1015 private void writeInstrument(RIFFWriter writer, DLSInstrument instrument) 1016 throws IOException { 1017 1018 int art1_count = 0; 1019 int art2_count = 0; 1020 for (DLSModulator modulator : instrument.getModulators()) { 1021 if (modulator.version == 1) 1022 art1_count++; 1023 if (modulator.version == 2) 1024 art2_count++; 1025 } 1026 for (DLSRegion region : instrument.regions) { 1027 for (DLSModulator modulator : region.getModulators()) { 1028 if (modulator.version == 1) 1029 art1_count++; 1030 if (modulator.version == 2) 1031 art2_count++; 1032 } 1033 } 1034 1035 int version = 1; 1036 if (art2_count > 0) 1037 version = 2; 1038 1039 RIFFWriter insh_chunk = writer.writeChunk("insh"); 1040 insh_chunk.writeUnsignedInt(instrument.getRegions().size()); 1041 insh_chunk.writeUnsignedInt(instrument.bank + 1042 (instrument.druminstrument ? 2147483648L : 0)); 1043 insh_chunk.writeUnsignedInt(instrument.preset); 1044 1045 RIFFWriter lrgn = writer.writeList("lrgn"); 1046 for (DLSRegion region: instrument.regions) 1047 writeRegion(lrgn, region, version); 1048 1049 writeArticulators(writer, instrument.getModulators()); 1050 1051 writeInfo(writer.writeList("INFO"), instrument.info); 1052 1053 } 1054 1055 private void writeArticulators(RIFFWriter writer, 1056 List<DLSModulator> modulators) throws IOException { 1057 int art1_count = 0; 1058 int art2_count = 0; 1059 for (DLSModulator modulator : modulators) { 1060 if (modulator.version == 1) 1061 art1_count++; 1062 if (modulator.version == 2) 1063 art2_count++; 1064 } 1065 if (art1_count > 0) { 1066 RIFFWriter lar1 = writer.writeList("lart"); 1067 RIFFWriter art1 = lar1.writeChunk("art1"); 1068 art1.writeUnsignedInt(8); 1069 art1.writeUnsignedInt(art1_count); 1070 for (DLSModulator modulator : modulators) { 1071 if (modulator.version == 1) { 1072 art1.writeUnsignedShort(modulator.source); 1073 art1.writeUnsignedShort(modulator.control); 1074 art1.writeUnsignedShort(modulator.destination); 1075 art1.writeUnsignedShort(modulator.transform); 1076 art1.writeInt(modulator.scale); 1077 } 1078 } 1079 } 1080 if (art2_count > 0) { 1081 RIFFWriter lar2 = writer.writeList("lar2"); 1082 RIFFWriter art2 = lar2.writeChunk("art2"); 1083 art2.writeUnsignedInt(8); 1084 art2.writeUnsignedInt(art2_count); 1085 for (DLSModulator modulator : modulators) { 1086 if (modulator.version == 2) { 1087 art2.writeUnsignedShort(modulator.source); 1088 art2.writeUnsignedShort(modulator.control); 1089 art2.writeUnsignedShort(modulator.destination); 1090 art2.writeUnsignedShort(modulator.transform); 1091 art2.writeInt(modulator.scale); 1092 } 1093 } 1094 } 1095 } 1096 1097 private void writeRegion(RIFFWriter writer, DLSRegion region, int version) 1098 throws IOException { 1099 RIFFWriter rgns = null; 1100 if (version == 1) 1101 rgns = writer.writeList("rgn "); 1102 if (version == 2) 1103 rgns = writer.writeList("rgn2"); 1104 if (rgns == null) 1105 return; 1106 1107 RIFFWriter rgnh = rgns.writeChunk("rgnh"); 1108 rgnh.writeUnsignedShort(region.keyfrom); 1109 rgnh.writeUnsignedShort(region.keyto); 1110 rgnh.writeUnsignedShort(region.velfrom); 1111 rgnh.writeUnsignedShort(region.velto); 1112 rgnh.writeUnsignedShort(region.options); 1113 rgnh.writeUnsignedShort(region.exclusiveClass); 1114 1115 if (region.sampleoptions != null) 1116 writeSampleOptions(rgns.writeChunk("wsmp"), region.sampleoptions); 1117 1118 if (region.sample != null) { 1119 if (samples.indexOf(region.sample) != -1) { 1120 RIFFWriter wlnk = rgns.writeChunk("wlnk"); 1121 wlnk.writeUnsignedShort(region.fusoptions); 1122 wlnk.writeUnsignedShort(region.phasegroup); 1123 wlnk.writeUnsignedInt(region.channel); 1124 wlnk.writeUnsignedInt(samples.indexOf(region.sample)); 1125 } 1126 } 1127 writeArticulators(rgns, region.getModulators()); 1128 rgns.close(); 1129 } 1130 1131 private void writeSampleOptions(RIFFWriter wsmp, 1132 DLSSampleOptions sampleoptions) throws IOException { 1133 wsmp.writeUnsignedInt(20); 1134 wsmp.writeUnsignedShort(sampleoptions.unitynote); 1135 wsmp.writeShort(sampleoptions.finetune); 1136 wsmp.writeInt(sampleoptions.attenuation); 1137 wsmp.writeUnsignedInt(sampleoptions.options); 1138 wsmp.writeInt(sampleoptions.loops.size()); 1139 1140 for (DLSSampleLoop loop : sampleoptions.loops) { 1141 wsmp.writeUnsignedInt(16); 1142 wsmp.writeUnsignedInt(loop.type); 1143 wsmp.writeUnsignedInt(loop.start); 1144 wsmp.writeUnsignedInt(loop.length); 1145 } 1146 } 1147 1148 private void writeInfoStringChunk(RIFFWriter writer, 1149 String name, String value) throws IOException { 1150 if (value == null) 1151 return; 1152 RIFFWriter chunk = writer.writeChunk(name); 1153 chunk.writeString(value); 1154 int len = value.getBytes("ascii").length; 1155 chunk.write(0); 1156 len++; 1157 if (len % 2 != 0) 1158 chunk.write(0); 1159 } 1160 1161 private void writeInfo(RIFFWriter writer, DLSInfo info) throws IOException { 1162 writeInfoStringChunk(writer, "INAM", info.name); 1163 writeInfoStringChunk(writer, "ICRD", info.creationDate); 1164 writeInfoStringChunk(writer, "IENG", info.engineers); 1165 writeInfoStringChunk(writer, "IPRD", info.product); 1166 writeInfoStringChunk(writer, "ICOP", info.copyright); 1167 writeInfoStringChunk(writer, "ICMT", info.comments); 1168 writeInfoStringChunk(writer, "ISFT", info.tools); 1169 writeInfoStringChunk(writer, "IARL", info.archival_location); 1170 writeInfoStringChunk(writer, "IART", info.artist); 1171 writeInfoStringChunk(writer, "ICMS", info.commissioned); 1172 writeInfoStringChunk(writer, "IGNR", info.genre); 1173 writeInfoStringChunk(writer, "IKEY", info.keywords); 1174 writeInfoStringChunk(writer, "IMED", info.medium); 1175 writeInfoStringChunk(writer, "ISBJ", info.subject); 1176 writeInfoStringChunk(writer, "ISRC", info.source); 1177 writeInfoStringChunk(writer, "ISRF", info.source_form); 1178 writeInfoStringChunk(writer, "ITCH", info.technician); 1179 } 1180 1181 public DLSInfo getInfo() { 1182 return info; 1183 } 1184 1185 @Override 1186 public String getName() { 1187 return info.name; 1188 } 1189 1190 @Override 1191 public String getVersion() { 1192 return major + "." + minor; 1193 } 1194 1195 @Override 1196 public String getVendor() { 1197 return info.engineers; 1198 } 1199 1200 @Override 1201 public String getDescription() { 1202 return info.comments; 1203 } 1204 1205 public void setName(String s) { 1206 info.name = s; 1207 } 1208 1209 public void setVendor(String s) { 1210 info.engineers = s; 1211 } 1212 1213 public void setDescription(String s) { 1214 info.comments = s; 1215 } 1216 1217 @Override 1218 public SoundbankResource[] getResources() { 1219 SoundbankResource[] resources = new SoundbankResource[samples.size()]; 1220 int j = 0; 1221 for (int i = 0; i < samples.size(); i++) 1222 resources[j++] = samples.get(i); 1223 return resources; 1224 } 1225 1226 @Override 1227 public DLSInstrument[] getInstruments() { 1228 DLSInstrument[] inslist_array = 1229 instruments.toArray(new DLSInstrument[instruments.size()]); 1230 Arrays.sort(inslist_array, new ModelInstrumentComparator()); 1231 return inslist_array; 1232 } 1233 1234 public DLSSample[] getSamples() { 1235 return samples.toArray(new DLSSample[samples.size()]); 1236 } 1237 1238 @Override 1239 public Instrument getInstrument(Patch patch) { 1240 int program = patch.getProgram(); 1241 int bank = patch.getBank(); 1242 boolean percussion = false; 1243 if (patch instanceof ModelPatch) 1244 percussion = ((ModelPatch) patch).isPercussion(); 1245 for (Instrument instrument : instruments) { 1246 Patch patch2 = instrument.getPatch(); 1247 int program2 = patch2.getProgram(); 1248 int bank2 = patch2.getBank(); 1249 if (program == program2 && bank == bank2) { 1250 boolean percussion2 = false; 1251 if (patch2 instanceof ModelPatch) 1252 percussion2 = ((ModelPatch) patch2).isPercussion(); 1253 if (percussion == percussion2) 1254 return instrument; 1255 } 1256 } 1257 return null; 1258 } 1259 1260 public void addResource(SoundbankResource resource) { 1261 if (resource instanceof DLSInstrument) 1262 instruments.add((DLSInstrument) resource); 1263 if (resource instanceof DLSSample) 1264 samples.add((DLSSample) resource); 1265 } 1266 1267 public void removeResource(SoundbankResource resource) { 1268 if (resource instanceof DLSInstrument) 1269 instruments.remove(resource); 1270 if (resource instanceof DLSSample) 1271 samples.remove(resource); 1272 } 1273 1274 public void addInstrument(DLSInstrument resource) { 1275 instruments.add(resource); 1276 } 1277 1278 public void removeInstrument(DLSInstrument resource) { 1279 instruments.remove(resource); 1280 } 1281 1282 public long getMajor() { 1283 return major; 1284 } 1285 1286 public void setMajor(long major) { 1287 this.major = major; 1288 } 1289 1290 public long getMinor() { 1291 return minor; 1292 } 1293 1294 public void setMinor(long minor) { 1295 this.minor = minor; 1296 } 1297 }