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 DLSID()70 private DLSID() { 71 } 72 DLSID(long i1, int s1, int s2, int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8)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 read(RIFFReader riff)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 hashCode()105 public int hashCode() { 106 return (int)i1; 107 } 108 109 @Override equals(Object obj)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 DLSSoundbank()188 public DLSSoundbank() { 189 } 190 DLSSoundbank(URL url)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 DLSSoundbank(File file)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 DLSSoundbank(InputStream inputstream)211 public DLSSoundbank(InputStream inputstream) throws IOException { 212 readSoundbank(inputstream); 213 } 214 readSoundbank(InputStream inputstream)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 cdlIsQuerySupported(DLSID uuid)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 cdlQuery(DLSID uuid)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 readCdlChunk(RIFFReader riff)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 readInfoChunk(RIFFReader riff)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 readLinsChunk(RIFFReader riff)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 readInsChunk(RIFFReader riff)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 readArt1Chunk(List<DLSModulator> modulators, RIFFReader riff)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 readArt2Chunk(List<DLSModulator> modulators, RIFFReader riff)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 readRgnChunk(DLSRegion split, RIFFReader riff)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 readWsmpChunk(DLSSampleOptions sampleOptions, RIFFReader riff)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 readInsInfoChunk(DLSInstrument dlsinstrument, RIFFReader riff)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 readWvplChunk(RIFFReader riff)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 readWaveChunk(RIFFReader riff)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 readWaveInfoChunk(DLSSample dlssample, RIFFReader riff)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 save(String name)875 public void save(String name) throws IOException { 876 writeSoundbank(new RIFFWriter(name, "DLS ")); 877 } 878 save(File file)879 public void save(File file) throws IOException { 880 writeSoundbank(new RIFFWriter(file, "DLS ")); 881 } 882 save(OutputStream out)883 public void save(OutputStream out) throws IOException { 884 writeSoundbank(new RIFFWriter(out, "DLS ")); 885 } 886 writeSoundbank(RIFFWriter writer)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 writeSample(RIFFWriter writer, DLSSample sample)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 writeInstruments(RIFFWriter writer)1009 private void writeInstruments(RIFFWriter writer) throws IOException { 1010 for (DLSInstrument instrument : instruments) { 1011 writeInstrument(writer.writeList("ins "), instrument); 1012 } 1013 } 1014 writeInstrument(RIFFWriter writer, DLSInstrument instrument)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 writeArticulators(RIFFWriter writer, List<DLSModulator> modulators)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 writeRegion(RIFFWriter writer, DLSRegion region, int version)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 writeSampleOptions(RIFFWriter wsmp, DLSSampleOptions sampleoptions)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 writeInfoStringChunk(RIFFWriter writer, String name, String value)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 writeInfo(RIFFWriter writer, DLSInfo info)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 getInfo()1181 public DLSInfo getInfo() { 1182 return info; 1183 } 1184 1185 @Override getName()1186 public String getName() { 1187 return info.name; 1188 } 1189 1190 @Override getVersion()1191 public String getVersion() { 1192 return major + "." + minor; 1193 } 1194 1195 @Override getVendor()1196 public String getVendor() { 1197 return info.engineers; 1198 } 1199 1200 @Override getDescription()1201 public String getDescription() { 1202 return info.comments; 1203 } 1204 setName(String s)1205 public void setName(String s) { 1206 info.name = s; 1207 } 1208 setVendor(String s)1209 public void setVendor(String s) { 1210 info.engineers = s; 1211 } 1212 setDescription(String s)1213 public void setDescription(String s) { 1214 info.comments = s; 1215 } 1216 1217 @Override getResources()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 getInstruments()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 getSamples()1234 public DLSSample[] getSamples() { 1235 return samples.toArray(new DLSSample[samples.size()]); 1236 } 1237 1238 @Override getInstrument(Patch patch)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 addResource(SoundbankResource resource)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 removeResource(SoundbankResource resource)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 addInstrument(DLSInstrument resource)1274 public void addInstrument(DLSInstrument resource) { 1275 instruments.add(resource); 1276 } 1277 removeInstrument(DLSInstrument resource)1278 public void removeInstrument(DLSInstrument resource) { 1279 instruments.remove(resource); 1280 } 1281 getMajor()1282 public long getMajor() { 1283 return major; 1284 } 1285 setMajor(long major)1286 public void setMajor(long major) { 1287 this.major = major; 1288 } 1289 getMinor()1290 public long getMinor() { 1291 return minor; 1292 } 1293 setMinor(long minor)1294 public void setMinor(long minor) { 1295 this.minor = minor; 1296 } 1297 } 1298