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