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.ByteArrayOutputStream; 28 import java.io.IOException; 29 import java.io.InputStream; 30 import java.util.Arrays; 31 32 import javax.sound.sampled.AudioFormat; 33 import javax.sound.sampled.AudioInputStream; 34 import javax.sound.sampled.AudioSystem; 35 import javax.sound.sampled.Clip; 36 import javax.sound.sampled.DataLine; 37 import javax.sound.sampled.LineEvent; 38 import javax.sound.sampled.LineUnavailableException; 39 40 /** 41 * Clip implementation for the SoftMixingMixer. 42 * 43 * @author Karl Helgason 44 */ 45 public final class SoftMixingClip extends SoftMixingDataLine implements Clip { 46 47 private AudioFormat format; 48 49 private int framesize; 50 51 private byte[] data; 52 53 private final InputStream datastream = new InputStream() { 54 55 public int read() throws IOException { 56 byte[] b = new byte[1]; 57 int ret = read(b); 58 if (ret < 0) 59 return ret; 60 return b[0] & 0xFF; 61 } 62 63 public int read(byte[] b, int off, int len) throws IOException { 64 65 if (_loopcount != 0) { 66 int bloopend = _loopend * framesize; 67 int bloopstart = _loopstart * framesize; 68 int pos = _frameposition * framesize; 69 70 if (pos + len >= bloopend) 71 if (pos < bloopend) { 72 int offend = off + len; 73 int o = off; 74 while (off != offend) { 75 if (pos == bloopend) { 76 if (_loopcount == 0) 77 break; 78 pos = bloopstart; 79 if (_loopcount != LOOP_CONTINUOUSLY) 80 _loopcount--; 81 } 82 len = offend - off; 149 private int _loopcount = 0; 150 151 private int _loopstart = 0; 152 153 private int _loopend = -1; 154 155 private float _rightgain; 156 157 private float _leftgain; 158 159 private float _eff1gain; 160 161 private float _eff2gain; 162 163 private AudioFloatInputStream afis; 164 165 SoftMixingClip(SoftMixingMixer mixer, DataLine.Info info) { 166 super(mixer, info); 167 } 168 169 protected void processControlLogic() { 170 171 _rightgain = rightgain; 172 _leftgain = leftgain; 173 _eff1gain = eff1gain; 174 _eff2gain = eff2gain; 175 176 if (active_sg) { 177 _active = active; 178 active_sg = false; 179 } else { 180 active = _active; 181 } 182 183 if (frameposition_sg) { 184 _frameposition = frameposition; 185 frameposition_sg = false; 186 afis = null; 187 } else { 188 frameposition = _frameposition; 189 } 190 if (loop_sg) { 191 _loopcount = loopcount; 192 _loopstart = loopstart; 193 _loopend = loopend; 194 } 195 196 if (afis == null) { 197 afis = AudioFloatInputStream.getInputStream(new AudioInputStream( 198 datastream, format, AudioSystem.NOT_SPECIFIED)); 199 200 if (Math.abs(format.getSampleRate() - outputformat.getSampleRate()) > 0.000001) 201 afis = new AudioFloatInputStreamResampler(afis, outputformat); 202 } 203 204 } 205 206 protected void processAudioLogic(SoftAudioBuffer[] buffers) { 207 if (_active) { 208 float[] left = buffers[SoftMixingMainMixer.CHANNEL_LEFT].array(); 209 float[] right = buffers[SoftMixingMainMixer.CHANNEL_RIGHT].array(); 210 int bufferlen = buffers[SoftMixingMainMixer.CHANNEL_LEFT].getSize(); 211 212 int readlen = bufferlen * in_nrofchannels; 213 if (readbuffer == null || readbuffer.length < readlen) { 214 readbuffer = new float[readlen]; 215 } 216 int ret = 0; 217 try { 218 ret = afis.read(readbuffer); 219 if (ret == -1) { 220 _active = false; 221 return; 222 } 223 if (ret != in_nrofchannels) 224 Arrays.fill(readbuffer, ret, readlen, 0); 225 } catch (IOException e) { 256 } 257 } 258 } 259 260 if (_eff2gain > 0.0002) { 261 float[] eff2 = buffers[SoftMixingMainMixer.CHANNEL_EFFECT2] 262 .array(); 263 for (int i = 0, ix = 0; i < bufferlen; i++, ix += in_c) { 264 eff2[i] += readbuffer[ix] * _eff2gain; 265 } 266 if (in_nrofchannels == 2) { 267 for (int i = 0, ix = 1; i < bufferlen; i++, ix += in_c) { 268 eff2[i] += readbuffer[ix] * _eff2gain; 269 } 270 } 271 } 272 273 } 274 } 275 276 public int getFrameLength() { 277 return bufferSize / format.getFrameSize(); 278 } 279 280 public long getMicrosecondLength() { 281 return (long) (getFrameLength() * (1000000.0 / (double) getFormat() 282 .getSampleRate())); 283 } 284 285 public void loop(int count) { 286 LineEvent event = null; 287 288 synchronized (control_mutex) { 289 if (isOpen()) { 290 if (active) 291 return; 292 active = true; 293 active_sg = true; 294 loopcount = count; 295 event = new LineEvent(this, LineEvent.Type.START, 296 getLongFramePosition()); 297 } 298 } 299 300 if (event != null) 301 sendEvent(event); 302 303 } 304 305 public void open(AudioInputStream stream) throws LineUnavailableException, 306 IOException { 307 if (isOpen()) { 308 throw new IllegalStateException("Clip is already open with format " 309 + getFormat() + " and frame lengh of " + getFrameLength()); 310 } 311 if (AudioFloatConverter.getConverter(stream.getFormat()) == null) 312 throw new IllegalArgumentException("Invalid format : " 313 + stream.getFormat().toString()); 314 315 if (stream.getFrameLength() != AudioSystem.NOT_SPECIFIED) { 316 byte[] data = new byte[(int) stream.getFrameLength() 317 * stream.getFormat().getFrameSize()]; 318 int readsize = 512 * stream.getFormat().getFrameSize(); 319 int len = 0; 320 while (len != data.length) { 321 if (readsize > data.length - len) 322 readsize = data.length - len; 323 int ret = stream.read(data, len, readsize); 324 if (ret == -1) 325 break; 326 if (ret == 0) 327 Thread.yield(); 328 len += ret; 329 } 330 open(stream.getFormat(), data, 0, len); 331 } else { 332 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 333 byte[] b = new byte[512 * stream.getFormat().getFrameSize()]; 334 int r = 0; 335 while ((r = stream.read(b)) != -1) { 336 if (r == 0) 337 Thread.yield(); 338 baos.write(b, 0, r); 339 } 340 open(stream.getFormat(), baos.toByteArray(), 0, baos.size()); 341 } 342 343 } 344 345 public void open(AudioFormat format, byte[] data, int offset, int bufferSize) 346 throws LineUnavailableException { 347 synchronized (control_mutex) { 348 if (isOpen()) { 349 throw new IllegalStateException( 350 "Clip is already open with format " + getFormat() 351 + " and frame lengh of " + getFrameLength()); 352 } 353 if (AudioFloatConverter.getConverter(format) == null) 354 throw new IllegalArgumentException("Invalid format : " 355 + format.toString()); 356 if (bufferSize % format.getFrameSize() != 0) 357 throw new IllegalArgumentException( 358 "Buffer size does not represent an integral number of sample frames!"); 359 360 if (data != null) { 361 this.data = Arrays.copyOf(data, data.length); 362 } 363 this.offset = offset; 364 this.bufferSize = bufferSize; 368 loopstart = 0; 369 loopend = -1; 370 loop_sg = true; 371 372 if (!mixer.isOpen()) { 373 mixer.open(); 374 mixer.implicitOpen = true; 375 } 376 377 outputformat = mixer.getFormat(); 378 out_nrofchannels = outputformat.getChannels(); 379 in_nrofchannels = format.getChannels(); 380 381 open = true; 382 383 mixer.getMainMixer().openLine(this); 384 } 385 386 } 387 388 public void setFramePosition(int frames) { 389 synchronized (control_mutex) { 390 frameposition_sg = true; 391 frameposition = frames; 392 } 393 } 394 395 public void setLoopPoints(int start, int end) { 396 synchronized (control_mutex) { 397 if (end != -1) { 398 if (end < start) 399 throw new IllegalArgumentException("Invalid loop points : " 400 + start + " - " + end); 401 if (end * framesize > bufferSize) 402 throw new IllegalArgumentException("Invalid loop points : " 403 + start + " - " + end); 404 } 405 if (start * framesize > bufferSize) 406 throw new IllegalArgumentException("Invalid loop points : " 407 + start + " - " + end); 408 if (0 < start) 409 throw new IllegalArgumentException("Invalid loop points : " 410 + start + " - " + end); 411 loopstart = start; 412 loopend = end; 413 loop_sg = true; 414 } 415 } 416 417 public void setMicrosecondPosition(long microseconds) { 418 setFramePosition((int) (microseconds * (((double) getFormat() 419 .getSampleRate()) / 1000000.0))); 420 } 421 422 public int available() { 423 return 0; 424 } 425 426 public void drain() { 427 } 428 429 public void flush() { 430 } 431 432 public int getBufferSize() { 433 return bufferSize; 434 } 435 436 public AudioFormat getFormat() { 437 return format; 438 } 439 440 public int getFramePosition() { 441 synchronized (control_mutex) { 442 return frameposition; 443 } 444 } 445 446 public float getLevel() { 447 return AudioSystem.NOT_SPECIFIED; 448 } 449 450 public long getLongFramePosition() { 451 return getFramePosition(); 452 } 453 454 public long getMicrosecondPosition() { 455 return (long) (getFramePosition() * (1000000.0 / (double) getFormat() 456 .getSampleRate())); 457 } 458 459 public boolean isActive() { 460 synchronized (control_mutex) { 461 return active; 462 } 463 } 464 465 public boolean isRunning() { 466 synchronized (control_mutex) { 467 return active; 468 } 469 } 470 471 public void start() { 472 473 LineEvent event = null; 474 475 synchronized (control_mutex) { 476 if (isOpen()) { 477 if (active) 478 return; 479 active = true; 480 active_sg = true; 481 loopcount = 0; 482 event = new LineEvent(this, LineEvent.Type.START, 483 getLongFramePosition()); 484 } 485 } 486 487 if (event != null) 488 sendEvent(event); 489 } 490 491 public void stop() { 492 LineEvent event = null; 493 494 synchronized (control_mutex) { 495 if (isOpen()) { 496 if (!active) 497 return; 498 active = false; 499 active_sg = true; 500 event = new LineEvent(this, LineEvent.Type.STOP, 501 getLongFramePosition()); 502 } 503 } 504 505 if (event != null) 506 sendEvent(event); 507 } 508 509 public void close() { 510 LineEvent event = null; 511 512 synchronized (control_mutex) { 513 if (!isOpen()) 514 return; 515 stop(); 516 517 event = new LineEvent(this, LineEvent.Type.CLOSE, 518 getLongFramePosition()); 519 520 open = false; 521 mixer.getMainMixer().closeLine(this); 522 } 523 524 if (event != null) 525 sendEvent(event); 526 527 } 528 529 public boolean isOpen() { 530 return open; 531 } 532 533 public void open() throws LineUnavailableException { 534 if (data == null) { 535 throw new IllegalArgumentException( 536 "Illegal call to open() in interface Clip"); 537 } 538 open(format, data, offset, bufferSize); 539 } 540 541 } | 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.ByteArrayOutputStream; 29 import java.io.IOException; 30 import java.io.InputStream; 31 import java.util.Arrays; 32 33 import javax.sound.sampled.AudioFormat; 34 import javax.sound.sampled.AudioInputStream; 35 import javax.sound.sampled.AudioSystem; 36 import javax.sound.sampled.Clip; 37 import javax.sound.sampled.DataLine; 38 import javax.sound.sampled.LineEvent; 39 import javax.sound.sampled.LineUnavailableException; 40 41 /** 42 * Clip implementation for the SoftMixingMixer. 43 * 44 * @author Karl Helgason 45 */ 46 public final class SoftMixingClip extends SoftMixingDataLine implements Clip { 47 48 private AudioFormat format; 49 50 private int framesize; 51 52 private byte[] data; 53 54 private final InputStream datastream = new InputStream() { 55 56 @Override 57 public int read() throws IOException { 58 byte[] b = new byte[1]; 59 int ret = read(b); 60 if (ret < 0) 61 return ret; 62 return b[0] & 0xFF; 63 } 64 65 @Override 66 public int read(byte[] b, int off, int len) throws IOException { 67 68 if (_loopcount != 0) { 69 int bloopend = _loopend * framesize; 70 int bloopstart = _loopstart * framesize; 71 int pos = _frameposition * framesize; 72 73 if (pos + len >= bloopend) 74 if (pos < bloopend) { 75 int offend = off + len; 76 int o = off; 77 while (off != offend) { 78 if (pos == bloopend) { 79 if (_loopcount == 0) 80 break; 81 pos = bloopstart; 82 if (_loopcount != LOOP_CONTINUOUSLY) 83 _loopcount--; 84 } 85 len = offend - off; 152 private int _loopcount = 0; 153 154 private int _loopstart = 0; 155 156 private int _loopend = -1; 157 158 private float _rightgain; 159 160 private float _leftgain; 161 162 private float _eff1gain; 163 164 private float _eff2gain; 165 166 private AudioFloatInputStream afis; 167 168 SoftMixingClip(SoftMixingMixer mixer, DataLine.Info info) { 169 super(mixer, info); 170 } 171 172 @Override 173 protected void processControlLogic() { 174 175 _rightgain = rightgain; 176 _leftgain = leftgain; 177 _eff1gain = eff1gain; 178 _eff2gain = eff2gain; 179 180 if (active_sg) { 181 _active = active; 182 active_sg = false; 183 } else { 184 active = _active; 185 } 186 187 if (frameposition_sg) { 188 _frameposition = frameposition; 189 frameposition_sg = false; 190 afis = null; 191 } else { 192 frameposition = _frameposition; 193 } 194 if (loop_sg) { 195 _loopcount = loopcount; 196 _loopstart = loopstart; 197 _loopend = loopend; 198 } 199 200 if (afis == null) { 201 afis = AudioFloatInputStream.getInputStream(new AudioInputStream( 202 datastream, format, AudioSystem.NOT_SPECIFIED)); 203 204 if (Math.abs(format.getSampleRate() - outputformat.getSampleRate()) > 0.000001) 205 afis = new AudioFloatInputStreamResampler(afis, outputformat); 206 } 207 208 } 209 210 @Override 211 protected void processAudioLogic(SoftAudioBuffer[] buffers) { 212 if (_active) { 213 float[] left = buffers[SoftMixingMainMixer.CHANNEL_LEFT].array(); 214 float[] right = buffers[SoftMixingMainMixer.CHANNEL_RIGHT].array(); 215 int bufferlen = buffers[SoftMixingMainMixer.CHANNEL_LEFT].getSize(); 216 217 int readlen = bufferlen * in_nrofchannels; 218 if (readbuffer == null || readbuffer.length < readlen) { 219 readbuffer = new float[readlen]; 220 } 221 int ret = 0; 222 try { 223 ret = afis.read(readbuffer); 224 if (ret == -1) { 225 _active = false; 226 return; 227 } 228 if (ret != in_nrofchannels) 229 Arrays.fill(readbuffer, ret, readlen, 0); 230 } catch (IOException e) { 261 } 262 } 263 } 264 265 if (_eff2gain > 0.0002) { 266 float[] eff2 = buffers[SoftMixingMainMixer.CHANNEL_EFFECT2] 267 .array(); 268 for (int i = 0, ix = 0; i < bufferlen; i++, ix += in_c) { 269 eff2[i] += readbuffer[ix] * _eff2gain; 270 } 271 if (in_nrofchannels == 2) { 272 for (int i = 0, ix = 1; i < bufferlen; i++, ix += in_c) { 273 eff2[i] += readbuffer[ix] * _eff2gain; 274 } 275 } 276 } 277 278 } 279 } 280 281 @Override 282 public int getFrameLength() { 283 return bufferSize / format.getFrameSize(); 284 } 285 286 @Override 287 public long getMicrosecondLength() { 288 return (long) (getFrameLength() * (1000000.0 / (double) getFormat() 289 .getSampleRate())); 290 } 291 292 @Override 293 public void loop(int count) { 294 LineEvent event = null; 295 296 synchronized (control_mutex) { 297 if (isOpen()) { 298 if (active) 299 return; 300 active = true; 301 active_sg = true; 302 loopcount = count; 303 event = new LineEvent(this, LineEvent.Type.START, 304 getLongFramePosition()); 305 } 306 } 307 308 if (event != null) 309 sendEvent(event); 310 311 } 312 313 @Override 314 public void open(AudioInputStream stream) throws LineUnavailableException, 315 IOException { 316 if (isOpen()) { 317 throw new IllegalStateException("Clip is already open with format " 318 + getFormat() + " and frame lengh of " + getFrameLength()); 319 } 320 if (AudioFloatConverter.getConverter(stream.getFormat()) == null) 321 throw new IllegalArgumentException("Invalid format : " 322 + stream.getFormat().toString()); 323 324 if (stream.getFrameLength() != AudioSystem.NOT_SPECIFIED) { 325 byte[] data = new byte[(int) stream.getFrameLength() 326 * stream.getFormat().getFrameSize()]; 327 int readsize = 512 * stream.getFormat().getFrameSize(); 328 int len = 0; 329 while (len != data.length) { 330 if (readsize > data.length - len) 331 readsize = data.length - len; 332 int ret = stream.read(data, len, readsize); 333 if (ret == -1) 334 break; 335 if (ret == 0) 336 Thread.yield(); 337 len += ret; 338 } 339 open(stream.getFormat(), data, 0, len); 340 } else { 341 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 342 byte[] b = new byte[512 * stream.getFormat().getFrameSize()]; 343 int r = 0; 344 while ((r = stream.read(b)) != -1) { 345 if (r == 0) 346 Thread.yield(); 347 baos.write(b, 0, r); 348 } 349 open(stream.getFormat(), baos.toByteArray(), 0, baos.size()); 350 } 351 352 } 353 354 @Override 355 public void open(AudioFormat format, byte[] data, int offset, int bufferSize) 356 throws LineUnavailableException { 357 synchronized (control_mutex) { 358 if (isOpen()) { 359 throw new IllegalStateException( 360 "Clip is already open with format " + getFormat() 361 + " and frame lengh of " + getFrameLength()); 362 } 363 if (AudioFloatConverter.getConverter(format) == null) 364 throw new IllegalArgumentException("Invalid format : " 365 + format.toString()); 366 if (bufferSize % format.getFrameSize() != 0) 367 throw new IllegalArgumentException( 368 "Buffer size does not represent an integral number of sample frames!"); 369 370 if (data != null) { 371 this.data = Arrays.copyOf(data, data.length); 372 } 373 this.offset = offset; 374 this.bufferSize = bufferSize; 378 loopstart = 0; 379 loopend = -1; 380 loop_sg = true; 381 382 if (!mixer.isOpen()) { 383 mixer.open(); 384 mixer.implicitOpen = true; 385 } 386 387 outputformat = mixer.getFormat(); 388 out_nrofchannels = outputformat.getChannels(); 389 in_nrofchannels = format.getChannels(); 390 391 open = true; 392 393 mixer.getMainMixer().openLine(this); 394 } 395 396 } 397 398 @Override 399 public void setFramePosition(int frames) { 400 synchronized (control_mutex) { 401 frameposition_sg = true; 402 frameposition = frames; 403 } 404 } 405 406 @Override 407 public void setLoopPoints(int start, int end) { 408 synchronized (control_mutex) { 409 if (end != -1) { 410 if (end < start) 411 throw new IllegalArgumentException("Invalid loop points : " 412 + start + " - " + end); 413 if (end * framesize > bufferSize) 414 throw new IllegalArgumentException("Invalid loop points : " 415 + start + " - " + end); 416 } 417 if (start * framesize > bufferSize) 418 throw new IllegalArgumentException("Invalid loop points : " 419 + start + " - " + end); 420 if (0 < start) 421 throw new IllegalArgumentException("Invalid loop points : " 422 + start + " - " + end); 423 loopstart = start; 424 loopend = end; 425 loop_sg = true; 426 } 427 } 428 429 @Override 430 public void setMicrosecondPosition(long microseconds) { 431 setFramePosition((int) (microseconds * (((double) getFormat() 432 .getSampleRate()) / 1000000.0))); 433 } 434 435 @Override 436 public int available() { 437 return 0; 438 } 439 440 @Override 441 public void drain() { 442 } 443 444 @Override 445 public void flush() { 446 } 447 448 @Override 449 public int getBufferSize() { 450 return bufferSize; 451 } 452 453 @Override 454 public AudioFormat getFormat() { 455 return format; 456 } 457 458 @Override 459 public int getFramePosition() { 460 synchronized (control_mutex) { 461 return frameposition; 462 } 463 } 464 465 @Override 466 public float getLevel() { 467 return AudioSystem.NOT_SPECIFIED; 468 } 469 470 @Override 471 public long getLongFramePosition() { 472 return getFramePosition(); 473 } 474 475 @Override 476 public long getMicrosecondPosition() { 477 return (long) (getFramePosition() * (1000000.0 / (double) getFormat() 478 .getSampleRate())); 479 } 480 481 @Override 482 public boolean isActive() { 483 synchronized (control_mutex) { 484 return active; 485 } 486 } 487 488 @Override 489 public boolean isRunning() { 490 synchronized (control_mutex) { 491 return active; 492 } 493 } 494 495 @Override 496 public void start() { 497 498 LineEvent event = null; 499 500 synchronized (control_mutex) { 501 if (isOpen()) { 502 if (active) 503 return; 504 active = true; 505 active_sg = true; 506 loopcount = 0; 507 event = new LineEvent(this, LineEvent.Type.START, 508 getLongFramePosition()); 509 } 510 } 511 512 if (event != null) 513 sendEvent(event); 514 } 515 516 @Override 517 public void stop() { 518 LineEvent event = null; 519 520 synchronized (control_mutex) { 521 if (isOpen()) { 522 if (!active) 523 return; 524 active = false; 525 active_sg = true; 526 event = new LineEvent(this, LineEvent.Type.STOP, 527 getLongFramePosition()); 528 } 529 } 530 531 if (event != null) 532 sendEvent(event); 533 } 534 535 @Override 536 public void close() { 537 LineEvent event = null; 538 539 synchronized (control_mutex) { 540 if (!isOpen()) 541 return; 542 stop(); 543 544 event = new LineEvent(this, LineEvent.Type.CLOSE, 545 getLongFramePosition()); 546 547 open = false; 548 mixer.getMainMixer().closeLine(this); 549 } 550 551 if (event != null) 552 sendEvent(event); 553 554 } 555 556 @Override 557 public boolean isOpen() { 558 return open; 559 } 560 561 @Override 562 public void open() throws LineUnavailableException { 563 if (data == null) { 564 throw new IllegalArgumentException( 565 "Illegal call to open() in interface Clip"); 566 } 567 open(format, data, offset, bufferSize); 568 } 569 570 } |