feat(jdk8): move files to new folder to avoid resources compiled.
This commit is contained in:
459
jdkSrc/jdk8/com/sun/media/sound/AbstractDataLine.java
Normal file
459
jdkSrc/jdk8/com/sun/media/sound/AbstractDataLine.java
Normal file
@@ -0,0 +1,459 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.media.sound;
|
||||
|
||||
import javax.sound.sampled.AudioFormat;
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
import javax.sound.sampled.Control;
|
||||
import javax.sound.sampled.DataLine;
|
||||
import javax.sound.sampled.LineEvent;
|
||||
import javax.sound.sampled.LineUnavailableException;
|
||||
|
||||
|
||||
/**
|
||||
* AbstractDataLine
|
||||
*
|
||||
* @author Kara Kytle
|
||||
*/
|
||||
abstract class AbstractDataLine extends AbstractLine implements DataLine {
|
||||
|
||||
// DEFAULTS
|
||||
|
||||
// default format
|
||||
private final AudioFormat defaultFormat;
|
||||
|
||||
// default buffer size in bytes
|
||||
private final int defaultBufferSize;
|
||||
|
||||
// the lock for synchronization
|
||||
protected final Object lock = new Object();
|
||||
|
||||
// STATE
|
||||
|
||||
// current format
|
||||
protected AudioFormat format;
|
||||
|
||||
// current buffer size in bytes
|
||||
protected int bufferSize;
|
||||
|
||||
private volatile boolean running;
|
||||
private volatile boolean started;
|
||||
private volatile boolean active;
|
||||
|
||||
/**
|
||||
* Constructs a new AbstractLine.
|
||||
*/
|
||||
protected AbstractDataLine(DataLine.Info info, AbstractMixer mixer, Control[] controls) {
|
||||
this(info, mixer, controls, null, AudioSystem.NOT_SPECIFIED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new AbstractLine.
|
||||
*/
|
||||
protected AbstractDataLine(DataLine.Info info, AbstractMixer mixer, Control[] controls, AudioFormat format, int bufferSize) {
|
||||
|
||||
super(info, mixer, controls);
|
||||
|
||||
// record the default values
|
||||
if (format != null) {
|
||||
defaultFormat = format;
|
||||
} else {
|
||||
// default CD-quality
|
||||
defaultFormat = new AudioFormat(44100.0f, 16, 2, true, Platform.isBigEndian());
|
||||
}
|
||||
if (bufferSize > 0) {
|
||||
defaultBufferSize = bufferSize;
|
||||
} else {
|
||||
// 0.5 seconds buffer
|
||||
defaultBufferSize = ((int) (defaultFormat.getFrameRate() / 2)) * defaultFormat.getFrameSize();
|
||||
}
|
||||
|
||||
// set the initial values to the defaults
|
||||
this.format = defaultFormat;
|
||||
this.bufferSize = defaultBufferSize;
|
||||
}
|
||||
|
||||
|
||||
// DATA LINE METHODS
|
||||
|
||||
public final void open(AudioFormat format, int bufferSize) throws LineUnavailableException {
|
||||
//$$fb 2001-10-09: Bug #4517739: avoiding deadlock by synchronizing to mixer !
|
||||
synchronized (mixer) {
|
||||
if (Printer.trace) Printer.trace("> AbstractDataLine.open(format, bufferSize) (class: "+getClass().getName());
|
||||
|
||||
// if the line is not currently open, try to open it with this format and buffer size
|
||||
if (!isOpen()) {
|
||||
// make sure that the format is specified correctly
|
||||
// $$fb part of fix for 4679187: Clip.open() throws unexpected Exceptions
|
||||
Toolkit.isFullySpecifiedAudioFormat(format);
|
||||
|
||||
if (Printer.debug) Printer.debug(" need to open the mixer...");
|
||||
// reserve mixer resources for this line
|
||||
//mixer.open(this, format, bufferSize);
|
||||
mixer.open(this);
|
||||
|
||||
try {
|
||||
// open the data line. may throw LineUnavailableException.
|
||||
implOpen(format, bufferSize);
|
||||
|
||||
// if we succeeded, set the open state to true and send events
|
||||
setOpen(true);
|
||||
|
||||
} catch (LineUnavailableException e) {
|
||||
// release mixer resources for this line and then throw the exception
|
||||
mixer.close(this);
|
||||
throw e;
|
||||
}
|
||||
} else {
|
||||
if (Printer.debug) Printer.debug(" dataline already open");
|
||||
|
||||
// if the line is already open and the requested format differs from the
|
||||
// current settings, throw an IllegalStateException
|
||||
//$$fb 2002-04-02: fix for 4661602: Buffersize is checked when re-opening line
|
||||
if (!format.matches(getFormat())) {
|
||||
throw new IllegalStateException("Line is already open with format " + getFormat() +
|
||||
" and bufferSize " + getBufferSize());
|
||||
}
|
||||
//$$fb 2002-07-26: allow changing the buffersize of already open lines
|
||||
if (bufferSize > 0) {
|
||||
setBufferSize(bufferSize);
|
||||
}
|
||||
}
|
||||
|
||||
if (Printer.trace) Printer.trace("< AbstractDataLine.open(format, bufferSize) completed");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public final void open(AudioFormat format) throws LineUnavailableException {
|
||||
open(format, AudioSystem.NOT_SPECIFIED);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This implementation always returns 0.
|
||||
*/
|
||||
public int available() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This implementation does nothing.
|
||||
*/
|
||||
public void drain() {
|
||||
if (Printer.trace) Printer.trace("AbstractDataLine: drain");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This implementation does nothing.
|
||||
*/
|
||||
public void flush() {
|
||||
if (Printer.trace) Printer.trace("AbstractDataLine: flush");
|
||||
}
|
||||
|
||||
|
||||
public final void start() {
|
||||
//$$fb 2001-10-09: Bug #4517739: avoiding deadlock by synchronizing to mixer !
|
||||
synchronized(mixer) {
|
||||
if (Printer.trace) Printer.trace("> "+getClass().getName()+".start() - AbstractDataLine");
|
||||
|
||||
// $$kk: 06.06.99: if not open, this doesn't work....???
|
||||
if (isOpen()) {
|
||||
|
||||
if (!isStartedRunning()) {
|
||||
mixer.start(this);
|
||||
implStart();
|
||||
running = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
synchronized(lock) {
|
||||
lock.notifyAll();
|
||||
}
|
||||
|
||||
if (Printer.trace) Printer.trace("< "+getClass().getName()+".start() - AbstractDataLine");
|
||||
}
|
||||
|
||||
|
||||
public final void stop() {
|
||||
|
||||
//$$fb 2001-10-09: Bug #4517739: avoiding deadlock by synchronizing to mixer !
|
||||
synchronized(mixer) {
|
||||
if (Printer.trace) Printer.trace("> "+getClass().getName()+".stop() - AbstractDataLine");
|
||||
|
||||
// $$kk: 06.06.99: if not open, this doesn't work.
|
||||
if (isOpen()) {
|
||||
|
||||
if (isStartedRunning()) {
|
||||
|
||||
implStop();
|
||||
mixer.stop(this);
|
||||
|
||||
running = false;
|
||||
|
||||
// $$kk: 11.10.99: this is not exactly correct, but will probably work
|
||||
if (started && (!isActive())) {
|
||||
setStarted(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
synchronized(lock) {
|
||||
lock.notifyAll();
|
||||
}
|
||||
|
||||
if (Printer.trace) Printer.trace("< "+getClass().getName()+".stop() - AbstractDataLine");
|
||||
}
|
||||
|
||||
// $$jb: 12.10.99: The official API for this is isRunning().
|
||||
// Per the denied RFE 4297981,
|
||||
// the change to isStarted() is technically an unapproved API change.
|
||||
// The 'started' variable is false when playback of data stops.
|
||||
// It is changed throughout the implementation with setStarted().
|
||||
// This state is what should be returned by isRunning() in the API.
|
||||
// Note that the 'running' variable is true between calls to
|
||||
// start() and stop(). This state is accessed now through the
|
||||
// isStartedRunning() method, defined below. I have not changed
|
||||
// the variable names at this point, since 'running' is accessed
|
||||
// in MixerSourceLine and MixerClip, and I want to touch as little
|
||||
// code as possible to change isStarted() back to isRunning().
|
||||
|
||||
public final boolean isRunning() {
|
||||
return started;
|
||||
}
|
||||
|
||||
public final boolean isActive() {
|
||||
return active;
|
||||
}
|
||||
|
||||
|
||||
public final long getMicrosecondPosition() {
|
||||
|
||||
long microseconds = getLongFramePosition();
|
||||
if (microseconds != AudioSystem.NOT_SPECIFIED) {
|
||||
microseconds = Toolkit.frames2micros(getFormat(), microseconds);
|
||||
}
|
||||
return microseconds;
|
||||
}
|
||||
|
||||
|
||||
public final AudioFormat getFormat() {
|
||||
return format;
|
||||
}
|
||||
|
||||
|
||||
public final int getBufferSize() {
|
||||
return bufferSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation does NOT change the buffer size
|
||||
*/
|
||||
public final int setBufferSize(int newSize) {
|
||||
return getBufferSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation returns AudioSystem.NOT_SPECIFIED.
|
||||
*/
|
||||
public final float getLevel() {
|
||||
return (float)AudioSystem.NOT_SPECIFIED;
|
||||
}
|
||||
|
||||
|
||||
// HELPER METHODS
|
||||
|
||||
/**
|
||||
* running is true after start is called and before stop is called,
|
||||
* regardless of whether data is actually being presented.
|
||||
*/
|
||||
// $$jb: 12.10.99: calling this method isRunning() conflicts with
|
||||
// the official API that was once called isStarted(). Since we
|
||||
// use this method throughout the implementation, I am renaming
|
||||
// it to isStartedRunning(). This is part of backing out the
|
||||
// change denied in RFE 4297981.
|
||||
|
||||
final boolean isStartedRunning() {
|
||||
return running;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method sets the active state and generates
|
||||
* events if it changes.
|
||||
*/
|
||||
final void setActive(boolean active) {
|
||||
|
||||
if (Printer.trace) Printer.trace("> AbstractDataLine: setActive(" + active + ")");
|
||||
|
||||
//boolean sendEvents = false;
|
||||
//long position = getLongFramePosition();
|
||||
|
||||
synchronized (this) {
|
||||
|
||||
//if (Printer.debug) Printer.debug(" AbstractDataLine: setActive: this.active: " + this.active);
|
||||
//if (Printer.debug) Printer.debug(" active: " + active);
|
||||
|
||||
if (this.active != active) {
|
||||
this.active = active;
|
||||
//sendEvents = true;
|
||||
}
|
||||
}
|
||||
|
||||
//if (Printer.debug) Printer.debug(" this.active: " + this.active);
|
||||
//if (Printer.debug) Printer.debug(" sendEvents: " + sendEvents);
|
||||
|
||||
|
||||
// $$kk: 11.19.99: take ACTIVE / INACTIVE / EOM events out;
|
||||
// putting them in is technically an API change.
|
||||
// do not generate ACTIVE / INACTIVE events for now
|
||||
// if (sendEvents) {
|
||||
//
|
||||
// if (active) {
|
||||
// sendEvents(new LineEvent(this, LineEvent.Type.ACTIVE, position));
|
||||
// } else {
|
||||
// sendEvents(new LineEvent(this, LineEvent.Type.INACTIVE, position));
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method sets the started state and generates
|
||||
* events if it changes.
|
||||
*/
|
||||
final void setStarted(boolean started) {
|
||||
|
||||
if (Printer.trace) Printer.trace("> AbstractDataLine: setStarted(" + started + ")");
|
||||
|
||||
boolean sendEvents = false;
|
||||
long position = getLongFramePosition();
|
||||
|
||||
synchronized (this) {
|
||||
|
||||
//if (Printer.debug) Printer.debug(" AbstractDataLine: setStarted: this.started: " + this.started);
|
||||
//if (Printer.debug) Printer.debug(" started: " + started);
|
||||
|
||||
if (this.started != started) {
|
||||
this.started = started;
|
||||
sendEvents = true;
|
||||
}
|
||||
}
|
||||
|
||||
//if (Printer.debug) Printer.debug(" this.started: " + this.started);
|
||||
//if (Printer.debug) Printer.debug(" sendEvents: " + sendEvents);
|
||||
|
||||
if (sendEvents) {
|
||||
|
||||
if (started) {
|
||||
sendEvents(new LineEvent(this, LineEvent.Type.START, position));
|
||||
} else {
|
||||
sendEvents(new LineEvent(this, LineEvent.Type.STOP, position));
|
||||
}
|
||||
}
|
||||
if (Printer.trace) Printer.trace("< AbstractDataLine: setStarted completed");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method generates a STOP event and sets the started state to false.
|
||||
* It is here for historic reasons when an EOM event existed.
|
||||
*/
|
||||
final void setEOM() {
|
||||
|
||||
if (Printer.trace) Printer.trace("> AbstractDataLine: setEOM()");
|
||||
//$$fb 2002-04-21: sometimes, 2 STOP events are generated.
|
||||
// better use setStarted() to send STOP event.
|
||||
setStarted(false);
|
||||
if (Printer.trace) Printer.trace("< AbstractDataLine: setEOM() completed");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// OVERRIDES OF ABSTRACT LINE METHODS
|
||||
|
||||
/**
|
||||
* Try to open the line with the current format and buffer size values.
|
||||
* If the line is not open, these will be the defaults. If the
|
||||
* line is open, this should return quietly because the values
|
||||
* requested will match the current ones.
|
||||
*/
|
||||
public final void open() throws LineUnavailableException {
|
||||
|
||||
if (Printer.trace) Printer.trace("> "+getClass().getName()+".open() - AbstractDataLine");
|
||||
|
||||
// this may throw a LineUnavailableException.
|
||||
open(format, bufferSize);
|
||||
if (Printer.trace) Printer.trace("< "+getClass().getName()+".open() - AbstractDataLine");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This should also stop the line. The closed line should not be running or active.
|
||||
* After we close the line, we reset the format and buffer size to the defaults.
|
||||
*/
|
||||
public final void close() {
|
||||
//$$fb 2001-10-09: Bug #4517739: avoiding deadlock by synchronizing to mixer !
|
||||
synchronized (mixer) {
|
||||
if (Printer.trace) Printer.trace("> "+getClass().getName()+".close() - in AbstractDataLine.");
|
||||
|
||||
if (isOpen()) {
|
||||
|
||||
// stop
|
||||
stop();
|
||||
|
||||
// set the open state to false and send events
|
||||
setOpen(false);
|
||||
|
||||
// close resources for this line
|
||||
implClose();
|
||||
|
||||
// release mixer resources for this line
|
||||
mixer.close(this);
|
||||
|
||||
// reset format and buffer size to the defaults
|
||||
format = defaultFormat;
|
||||
bufferSize = defaultBufferSize;
|
||||
}
|
||||
}
|
||||
if (Printer.trace) Printer.trace("< "+getClass().getName()+".close() - in AbstractDataLine");
|
||||
}
|
||||
|
||||
|
||||
// IMPLEMENTATIONS OF ABSTRACT LINE ABSTRACE METHODS
|
||||
|
||||
|
||||
// ABSTRACT METHODS
|
||||
|
||||
abstract void implOpen(AudioFormat format, int bufferSize) throws LineUnavailableException;
|
||||
abstract void implClose();
|
||||
|
||||
abstract void implStart();
|
||||
abstract void implStop();
|
||||
}
|
||||
239
jdkSrc/jdk8/com/sun/media/sound/AbstractLine.java
Normal file
239
jdkSrc/jdk8/com/sun/media/sound/AbstractLine.java
Normal file
@@ -0,0 +1,239 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Vector;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
import javax.sound.sampled.Control;
|
||||
import javax.sound.sampled.Line;
|
||||
import javax.sound.sampled.LineEvent;
|
||||
import javax.sound.sampled.LineListener;
|
||||
import javax.sound.sampled.LineUnavailableException;
|
||||
|
||||
|
||||
/**
|
||||
* AbstractLine
|
||||
*
|
||||
* @author Kara Kytle
|
||||
*/
|
||||
abstract class AbstractLine implements Line {
|
||||
|
||||
protected final Line.Info info;
|
||||
protected Control[] controls;
|
||||
AbstractMixer mixer;
|
||||
private volatile boolean open;
|
||||
private final Vector listeners = new Vector();
|
||||
|
||||
/**
|
||||
* Contains event dispatcher per thread group.
|
||||
*/
|
||||
private static final Map<ThreadGroup, EventDispatcher> dispatchers =
|
||||
new WeakHashMap<>();
|
||||
|
||||
/**
|
||||
* Constructs a new AbstractLine.
|
||||
* @param mixer the mixer with which this line is associated
|
||||
* @param controls set of supported controls
|
||||
*/
|
||||
protected AbstractLine(Line.Info info, AbstractMixer mixer, Control[] controls) {
|
||||
|
||||
if (controls == null) {
|
||||
controls = new Control[0];
|
||||
}
|
||||
|
||||
this.info = info;
|
||||
this.mixer = mixer;
|
||||
this.controls = controls;
|
||||
}
|
||||
|
||||
|
||||
// LINE METHODS
|
||||
|
||||
public final Line.Info getLineInfo() {
|
||||
return info;
|
||||
}
|
||||
|
||||
|
||||
public final boolean isOpen() {
|
||||
return open;
|
||||
}
|
||||
|
||||
|
||||
public final void addLineListener(LineListener listener) {
|
||||
synchronized(listeners) {
|
||||
if ( ! (listeners.contains(listener)) ) {
|
||||
listeners.addElement(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes an audio listener.
|
||||
* @param listener listener to remove
|
||||
*/
|
||||
public final void removeLineListener(LineListener listener) {
|
||||
listeners.removeElement(listener);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtains the set of controls supported by the
|
||||
* line. If no controls are supported, returns an
|
||||
* array of length 0.
|
||||
* @return control set
|
||||
*/
|
||||
public final Control[] getControls() {
|
||||
Control[] returnedArray = new Control[controls.length];
|
||||
|
||||
for (int i = 0; i < controls.length; i++) {
|
||||
returnedArray[i] = controls[i];
|
||||
}
|
||||
|
||||
return returnedArray;
|
||||
}
|
||||
|
||||
|
||||
public final boolean isControlSupported(Control.Type controlType) {
|
||||
// protect against a NullPointerException
|
||||
if (controlType == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < controls.length; i++) {
|
||||
if (controlType == controls[i].getType()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public final Control getControl(Control.Type controlType) {
|
||||
// protect against a NullPointerException
|
||||
if (controlType != null) {
|
||||
|
||||
for (int i = 0; i < controls.length; i++) {
|
||||
if (controlType == controls[i].getType()) {
|
||||
return controls[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Unsupported control type: " + controlType);
|
||||
}
|
||||
|
||||
|
||||
// HELPER METHODS
|
||||
|
||||
|
||||
/**
|
||||
* This method sets the open state and generates
|
||||
* events if it changes.
|
||||
*/
|
||||
final void setOpen(boolean open) {
|
||||
|
||||
if (Printer.trace) Printer.trace("> "+getClass().getName()+" (AbstractLine): setOpen(" + open + ") this.open: " + this.open);
|
||||
|
||||
boolean sendEvents = false;
|
||||
long position = getLongFramePosition();
|
||||
|
||||
synchronized (this) {
|
||||
if (this.open != open) {
|
||||
this.open = open;
|
||||
sendEvents = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (sendEvents) {
|
||||
if (open) {
|
||||
sendEvents(new LineEvent(this, LineEvent.Type.OPEN, position));
|
||||
} else {
|
||||
sendEvents(new LineEvent(this, LineEvent.Type.CLOSE, position));
|
||||
}
|
||||
}
|
||||
if (Printer.trace) Printer.trace("< "+getClass().getName()+" (AbstractLine): setOpen(" + open + ") this.open: " + this.open);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send line events.
|
||||
*/
|
||||
final void sendEvents(LineEvent event) {
|
||||
getEventDispatcher().sendAudioEvents(event, listeners);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This is an error in the API: getFramePosition
|
||||
* should return a long value. At CD quality,
|
||||
* the int value wraps around after 13 hours.
|
||||
*/
|
||||
public final int getFramePosition() {
|
||||
return (int) getLongFramePosition();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the frame position in a long value
|
||||
* This implementation returns AudioSystem.NOT_SPECIFIED.
|
||||
*/
|
||||
public long getLongFramePosition() {
|
||||
return AudioSystem.NOT_SPECIFIED;
|
||||
}
|
||||
|
||||
|
||||
// $$kk: 06.03.99: returns the mixer used in construction.
|
||||
// this is a hold-over from when there was a public method like
|
||||
// this on line and should be fixed!!
|
||||
final AbstractMixer getMixer() {
|
||||
return mixer;
|
||||
}
|
||||
|
||||
final EventDispatcher getEventDispatcher() {
|
||||
// create and start the global event thread
|
||||
//TODO need a way to stop this thread when the engine is done
|
||||
final ThreadGroup tg = Thread.currentThread().getThreadGroup();
|
||||
synchronized (dispatchers) {
|
||||
EventDispatcher eventDispatcher = dispatchers.get(tg);
|
||||
if (eventDispatcher == null) {
|
||||
eventDispatcher = new EventDispatcher();
|
||||
dispatchers.put(tg, eventDispatcher);
|
||||
eventDispatcher.start();
|
||||
}
|
||||
return eventDispatcher;
|
||||
}
|
||||
}
|
||||
|
||||
// ABSTRACT METHODS
|
||||
|
||||
public abstract void open() throws LineUnavailableException;
|
||||
public abstract void close();
|
||||
}
|
||||
751
jdkSrc/jdk8/com/sun/media/sound/AbstractMidiDevice.java
Normal file
751
jdkSrc/jdk8/com/sun/media/sound/AbstractMidiDevice.java
Normal file
@@ -0,0 +1,751 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Collections;
|
||||
|
||||
import javax.sound.midi.*;
|
||||
|
||||
|
||||
/**
|
||||
* Abstract AbstractMidiDevice class representing functionality shared by
|
||||
* MidiInDevice and MidiOutDevice objects.
|
||||
*
|
||||
* @author David Rivas
|
||||
* @author Kara Kytle
|
||||
* @author Matthias Pfisterer
|
||||
* @author Florian Bomers
|
||||
*/
|
||||
abstract class AbstractMidiDevice implements MidiDevice, ReferenceCountingDevice {
|
||||
|
||||
// STATIC VARIABLES
|
||||
private static final boolean TRACE_TRANSMITTER = false;
|
||||
|
||||
// INSTANCE VARIABLES
|
||||
|
||||
private ArrayList<Receiver> receiverList;
|
||||
|
||||
private TransmitterList transmitterList;
|
||||
|
||||
// lock to protect receiverList and transmitterList
|
||||
// from simultaneous creation and destruction
|
||||
// reduces possibility of deadlock, compared to
|
||||
// synchronizing to the class instance
|
||||
private final Object traRecLock = new Object();
|
||||
|
||||
// DEVICE ATTRIBUTES
|
||||
|
||||
private final MidiDevice.Info info;
|
||||
|
||||
|
||||
// DEVICE STATE
|
||||
|
||||
private volatile boolean open;
|
||||
private int openRefCount;
|
||||
|
||||
/** List of Receivers and Transmitters that opened the device implicitely.
|
||||
*/
|
||||
private List openKeepingObjects;
|
||||
|
||||
/**
|
||||
* This is the device handle returned from native code
|
||||
*/
|
||||
protected volatile long id;
|
||||
|
||||
|
||||
|
||||
// CONSTRUCTOR
|
||||
|
||||
|
||||
/**
|
||||
* Constructs an AbstractMidiDevice with the specified info object.
|
||||
* @param info the description of the device
|
||||
*/
|
||||
/*
|
||||
* The initial mode and and only supported mode default to OMNI_ON_POLY.
|
||||
*/
|
||||
protected AbstractMidiDevice(MidiDevice.Info info) {
|
||||
|
||||
if(Printer.trace) Printer.trace(">> AbstractMidiDevice CONSTRUCTOR");
|
||||
|
||||
this.info = info;
|
||||
openRefCount = 0;
|
||||
|
||||
if(Printer.trace) Printer.trace("<< AbstractMidiDevice CONSTRUCTOR completed");
|
||||
}
|
||||
|
||||
|
||||
// MIDI DEVICE METHODS
|
||||
|
||||
public final MidiDevice.Info getDeviceInfo() {
|
||||
return info;
|
||||
}
|
||||
|
||||
/** Open the device from an application program.
|
||||
* Setting the open reference count to -1 here prevents Transmitters and Receivers that
|
||||
* opened the the device implicitly from closing it. The only way to close the device after
|
||||
* this call is a call to close().
|
||||
*/
|
||||
public final void open() throws MidiUnavailableException {
|
||||
if (Printer.trace) Printer.trace("> AbstractMidiDevice: open()");
|
||||
synchronized(this) {
|
||||
openRefCount = -1;
|
||||
doOpen();
|
||||
}
|
||||
if (Printer.trace) Printer.trace("< AbstractMidiDevice: open() completed");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Open the device implicitly.
|
||||
* This method is intended to be used by AbstractReceiver
|
||||
* and BasicTransmitter. Actually, it is called by getReceiverReferenceCounting() and
|
||||
* getTransmitterReferenceCounting(). These, in turn, are called by MidiSytem on calls to
|
||||
* getReceiver() and getTransmitter(). The former methods should pass the Receiver or
|
||||
* Transmitter just created as the object parameter to this method. Storing references to
|
||||
* these objects is necessary to be able to decide later (when it comes to closing) if
|
||||
* R/T's are ones that opened the device implicitly.
|
||||
*
|
||||
* @object The Receiver or Transmitter instance that triggered this implicit open.
|
||||
*/
|
||||
private void openInternal(Object object) throws MidiUnavailableException {
|
||||
if (Printer.trace) Printer.trace("> AbstractMidiDevice: openInternal()");
|
||||
synchronized(this) {
|
||||
if (openRefCount != -1) {
|
||||
openRefCount++;
|
||||
getOpenKeepingObjects().add(object);
|
||||
}
|
||||
// double calls to doOpens() will be catched by the open flag.
|
||||
doOpen();
|
||||
}
|
||||
if (Printer.trace) Printer.trace("< AbstractMidiDevice: openInternal() completed");
|
||||
}
|
||||
|
||||
|
||||
private void doOpen() throws MidiUnavailableException {
|
||||
if (Printer.trace) Printer.trace("> AbstractMidiDevice: doOpen()");
|
||||
synchronized(this) {
|
||||
if (! isOpen()) {
|
||||
implOpen();
|
||||
open = true;
|
||||
}
|
||||
}
|
||||
if (Printer.trace) Printer.trace("< AbstractMidiDevice: doOpen() completed");
|
||||
}
|
||||
|
||||
|
||||
public final void close() {
|
||||
if (Printer.trace) Printer.trace("> AbstractMidiDevice: close()");
|
||||
synchronized (this) {
|
||||
doClose();
|
||||
openRefCount = 0;
|
||||
}
|
||||
if (Printer.trace) Printer.trace("< AbstractMidiDevice: close() completed");
|
||||
}
|
||||
|
||||
|
||||
/** Close the device for an object that implicitely opened it.
|
||||
* This method is intended to be used by Transmitter.close() and Receiver.close().
|
||||
* Those methods should pass this for the object parameter. Since Transmitters or Receivers
|
||||
* do not know if their device has been opened implicitely because of them, they call this
|
||||
* method in any case. This method now is able to seperate Receivers/Transmitters that opened
|
||||
* the device implicitely from those that didn't by looking up the R/T in the
|
||||
* openKeepingObjects list. Only if the R/T is contained there, the reference count is
|
||||
* reduced.
|
||||
*
|
||||
* @param object The object that might have been opening the device implicitely (for now,
|
||||
* this may be a Transmitter or receiver).
|
||||
*/
|
||||
public final void closeInternal(Object object) {
|
||||
if (Printer.trace) Printer.trace("> AbstractMidiDevice: closeInternal()");
|
||||
synchronized(this) {
|
||||
if (getOpenKeepingObjects().remove(object)) {
|
||||
if (openRefCount > 0) {
|
||||
openRefCount--;
|
||||
if (openRefCount == 0) {
|
||||
doClose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Printer.trace) Printer.trace("< AbstractMidiDevice: closeInternal() completed");
|
||||
}
|
||||
|
||||
|
||||
public final void doClose() {
|
||||
if (Printer.trace) Printer.trace("> AbstractMidiDevice: doClose()");
|
||||
synchronized(this) {
|
||||
if (isOpen()) {
|
||||
implClose();
|
||||
open = false;
|
||||
}
|
||||
}
|
||||
if (Printer.trace) Printer.trace("< AbstractMidiDevice: doClose() completed");
|
||||
}
|
||||
|
||||
|
||||
public final boolean isOpen() {
|
||||
return open;
|
||||
}
|
||||
|
||||
|
||||
protected void implClose() {
|
||||
synchronized (traRecLock) {
|
||||
if (receiverList != null) {
|
||||
// close all receivers
|
||||
for(int i = 0; i < receiverList.size(); i++) {
|
||||
receiverList.get(i).close();
|
||||
}
|
||||
receiverList.clear();
|
||||
}
|
||||
if (transmitterList != null) {
|
||||
// close all transmitters
|
||||
transmitterList.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This implementation always returns -1.
|
||||
* Devices that actually provide this should over-ride
|
||||
* this method.
|
||||
*/
|
||||
public long getMicrosecondPosition() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/** Return the maximum number of Receivers supported by this device.
|
||||
Depending on the return value of hasReceivers(), this method returns either 0 or -1.
|
||||
Subclasses should rather override hasReceivers() than override this method.
|
||||
*/
|
||||
public final int getMaxReceivers() {
|
||||
if (hasReceivers()) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Return the maximum number of Transmitters supported by this device.
|
||||
Depending on the return value of hasTransmitters(), this method returns either 0 or -1.
|
||||
Subclasses should override hasTransmitters().
|
||||
*/
|
||||
public final int getMaxTransmitters() {
|
||||
if (hasTransmitters()) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Retrieve a Receiver for this device.
|
||||
This method returns the value returned by createReceiver(), if it doesn't throw
|
||||
an exception. Subclasses should rather override createReceiver() than override
|
||||
this method.
|
||||
If createReceiver returns a Receiver, it is added to the internal list
|
||||
of Receivers (see getReceiversList)
|
||||
*/
|
||||
public final Receiver getReceiver() throws MidiUnavailableException {
|
||||
Receiver receiver;
|
||||
synchronized (traRecLock) {
|
||||
receiver = createReceiver(); // may throw MidiUnavailableException
|
||||
getReceiverList().add(receiver);
|
||||
}
|
||||
return receiver;
|
||||
}
|
||||
|
||||
|
||||
public final List<Receiver> getReceivers() {
|
||||
List<Receiver> recs;
|
||||
synchronized (traRecLock) {
|
||||
if (receiverList == null) {
|
||||
recs = Collections.unmodifiableList(new ArrayList<Receiver>(0));
|
||||
} else {
|
||||
recs = Collections.unmodifiableList
|
||||
((List<Receiver>) (receiverList.clone()));
|
||||
}
|
||||
}
|
||||
return recs;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This implementation uses createTransmitter, which may throw an exception.
|
||||
* If a transmitter is returned in createTransmitter, it is added to the internal
|
||||
* TransmitterList
|
||||
*/
|
||||
public final Transmitter getTransmitter() throws MidiUnavailableException {
|
||||
Transmitter transmitter;
|
||||
synchronized (traRecLock) {
|
||||
transmitter = createTransmitter(); // may throw MidiUnavailableException
|
||||
getTransmitterList().add(transmitter);
|
||||
}
|
||||
return transmitter;
|
||||
}
|
||||
|
||||
|
||||
public final List<Transmitter> getTransmitters() {
|
||||
List<Transmitter> tras;
|
||||
synchronized (traRecLock) {
|
||||
if (transmitterList == null
|
||||
|| transmitterList.transmitters.size() == 0) {
|
||||
tras = Collections.unmodifiableList(new ArrayList<Transmitter>(0));
|
||||
} else {
|
||||
tras = Collections.unmodifiableList((List<Transmitter>) (transmitterList.transmitters.clone()));
|
||||
}
|
||||
}
|
||||
return tras;
|
||||
}
|
||||
|
||||
|
||||
// HELPER METHODS
|
||||
|
||||
final long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
// REFERENCE COUNTING
|
||||
|
||||
/** Retrieve a Receiver and open the device implicitly.
|
||||
This method is called by MidiSystem.getReceiver().
|
||||
*/
|
||||
public final Receiver getReceiverReferenceCounting()
|
||||
throws MidiUnavailableException {
|
||||
/* Keep this order of commands! If getReceiver() throws an exception,
|
||||
openInternal() should not be called!
|
||||
*/
|
||||
Receiver receiver;
|
||||
synchronized (traRecLock) {
|
||||
receiver = getReceiver();
|
||||
AbstractMidiDevice.this.openInternal(receiver);
|
||||
}
|
||||
return receiver;
|
||||
}
|
||||
|
||||
|
||||
/** Retrieve a Transmitter and open the device implicitly.
|
||||
This method is called by MidiSystem.getTransmitter().
|
||||
*/
|
||||
public final Transmitter getTransmitterReferenceCounting()
|
||||
throws MidiUnavailableException {
|
||||
/* Keep this order of commands! If getTransmitter() throws an exception,
|
||||
openInternal() should not be called!
|
||||
*/
|
||||
Transmitter transmitter;
|
||||
synchronized (traRecLock) {
|
||||
transmitter = getTransmitter();
|
||||
AbstractMidiDevice.this.openInternal(transmitter);
|
||||
}
|
||||
return transmitter;
|
||||
}
|
||||
|
||||
|
||||
/** Return the list of objects that have opened the device implicitely.
|
||||
*/
|
||||
private synchronized List getOpenKeepingObjects() {
|
||||
if (openKeepingObjects == null) {
|
||||
openKeepingObjects = new ArrayList();
|
||||
}
|
||||
return openKeepingObjects;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// RECEIVER HANDLING METHODS
|
||||
|
||||
|
||||
/** Return the internal list of Receivers, possibly creating it first.
|
||||
*/
|
||||
private List<Receiver> getReceiverList() {
|
||||
synchronized (traRecLock) {
|
||||
if (receiverList == null) {
|
||||
receiverList = new ArrayList<Receiver>();
|
||||
}
|
||||
}
|
||||
return receiverList;
|
||||
}
|
||||
|
||||
|
||||
/** Returns if this device supports Receivers.
|
||||
Subclasses that use Receivers should override this method to
|
||||
return true. They also should override createReceiver().
|
||||
|
||||
@return true, if the device supports Receivers, false otherwise.
|
||||
*/
|
||||
protected boolean hasReceivers() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/** Create a Receiver object.
|
||||
throwing an exception here means that Receivers aren't enabled.
|
||||
Subclasses that use Receivers should override this method with
|
||||
one that returns objects implementing Receiver.
|
||||
Classes overriding this method should also override hasReceivers()
|
||||
to return true.
|
||||
*/
|
||||
protected Receiver createReceiver() throws MidiUnavailableException {
|
||||
throw new MidiUnavailableException("MIDI IN receiver not available");
|
||||
}
|
||||
|
||||
|
||||
|
||||
// TRANSMITTER HANDLING
|
||||
|
||||
/** Return the internal list of Transmitters, possibly creating it first.
|
||||
*/
|
||||
final TransmitterList getTransmitterList() {
|
||||
synchronized (traRecLock) {
|
||||
if (transmitterList == null) {
|
||||
transmitterList = new TransmitterList();
|
||||
}
|
||||
}
|
||||
return transmitterList;
|
||||
}
|
||||
|
||||
|
||||
/** Returns if this device supports Transmitters.
|
||||
Subclasses that use Transmitters should override this method to
|
||||
return true. They also should override createTransmitter().
|
||||
|
||||
@return true, if the device supports Transmitters, false otherwise.
|
||||
*/
|
||||
protected boolean hasTransmitters() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/** Create a Transmitter object.
|
||||
throwing an exception here means that Transmitters aren't enabled.
|
||||
Subclasses that use Transmitters should override this method with
|
||||
one that returns objects implementing Transmitters.
|
||||
Classes overriding this method should also override hasTransmitters()
|
||||
to return true.
|
||||
*/
|
||||
protected Transmitter createTransmitter() throws MidiUnavailableException {
|
||||
throw new MidiUnavailableException("MIDI OUT transmitter not available");
|
||||
}
|
||||
|
||||
// ABSTRACT METHODS
|
||||
|
||||
protected abstract void implOpen() throws MidiUnavailableException;
|
||||
|
||||
|
||||
/**
|
||||
* close this device if discarded by the garbage collector
|
||||
*/
|
||||
protected final void finalize() {
|
||||
close();
|
||||
}
|
||||
|
||||
// INNER CLASSES
|
||||
|
||||
/** Base class for Receivers.
|
||||
Subclasses that use Receivers must use this base class, since it
|
||||
contains magic necessary to manage implicit closing the device.
|
||||
This is necessary for Receivers retrieved via MidiSystem.getReceiver()
|
||||
(which opens the device implicitely).
|
||||
*/
|
||||
abstract class AbstractReceiver implements MidiDeviceReceiver {
|
||||
private volatile boolean open = true;
|
||||
|
||||
|
||||
/** Deliver a MidiMessage.
|
||||
This method contains magic related to the closed state of a
|
||||
Receiver. Therefore, subclasses should not override this method.
|
||||
Instead, they should implement implSend().
|
||||
*/
|
||||
@Override
|
||||
public final synchronized void send(final MidiMessage message,
|
||||
final long timeStamp) {
|
||||
if (!open) {
|
||||
throw new IllegalStateException("Receiver is not open");
|
||||
}
|
||||
implSend(message, timeStamp);
|
||||
}
|
||||
|
||||
abstract void implSend(MidiMessage message, long timeStamp);
|
||||
|
||||
/** Close the Receiver.
|
||||
* Here, the call to the magic method closeInternal() takes place.
|
||||
* Therefore, subclasses that override this method must call
|
||||
* 'super.close()'.
|
||||
*/
|
||||
@Override
|
||||
public final void close() {
|
||||
open = false;
|
||||
synchronized (AbstractMidiDevice.this.traRecLock) {
|
||||
AbstractMidiDevice.this.getReceiverList().remove(this);
|
||||
}
|
||||
AbstractMidiDevice.this.closeInternal(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final MidiDevice getMidiDevice() {
|
||||
return AbstractMidiDevice.this;
|
||||
}
|
||||
|
||||
final boolean isOpen() {
|
||||
return open;
|
||||
}
|
||||
|
||||
//$$fb is that a good idea?
|
||||
//protected void finalize() {
|
||||
// close();
|
||||
//}
|
||||
|
||||
} // class AbstractReceiver
|
||||
|
||||
|
||||
/**
|
||||
* Transmitter base class.
|
||||
* This class especially makes sure the device is closed if it
|
||||
* has been opened implicitly by a call to MidiSystem.getTransmitter().
|
||||
* The logic of doing so is actually in closeInternal().
|
||||
*
|
||||
* Also, it has some optimizations regarding sending to the Receivers,
|
||||
* for known Receivers, and managing itself in the TransmitterList.
|
||||
*/
|
||||
class BasicTransmitter implements MidiDeviceTransmitter {
|
||||
|
||||
private Receiver receiver = null;
|
||||
TransmitterList tlist = null;
|
||||
|
||||
protected BasicTransmitter() {
|
||||
}
|
||||
|
||||
private void setTransmitterList(TransmitterList tlist) {
|
||||
this.tlist = tlist;
|
||||
}
|
||||
|
||||
public final void setReceiver(Receiver receiver) {
|
||||
if (tlist != null && this.receiver != receiver) {
|
||||
if (Printer.debug) Printer.debug("Transmitter "+toString()+": set receiver "+receiver);
|
||||
tlist.receiverChanged(this, this.receiver, receiver);
|
||||
this.receiver = receiver;
|
||||
}
|
||||
}
|
||||
|
||||
public final Receiver getReceiver() {
|
||||
return receiver;
|
||||
}
|
||||
|
||||
|
||||
/** Close the Transmitter.
|
||||
* Here, the call to the magic method closeInternal() takes place.
|
||||
* Therefore, subclasses that override this method must call
|
||||
* 'super.close()'.
|
||||
*/
|
||||
public final void close() {
|
||||
AbstractMidiDevice.this.closeInternal(this);
|
||||
if (tlist != null) {
|
||||
tlist.receiverChanged(this, this.receiver, null);
|
||||
tlist.remove(this);
|
||||
tlist = null;
|
||||
}
|
||||
}
|
||||
|
||||
public final MidiDevice getMidiDevice() {
|
||||
return AbstractMidiDevice.this;
|
||||
}
|
||||
|
||||
} // class BasicTransmitter
|
||||
|
||||
|
||||
/**
|
||||
* a class to manage a list of transmitters
|
||||
*/
|
||||
final class TransmitterList {
|
||||
|
||||
private final ArrayList<Transmitter> transmitters = new ArrayList<Transmitter>();
|
||||
private MidiOutDevice.MidiOutReceiver midiOutReceiver;
|
||||
|
||||
// how many transmitters must be present for optimized
|
||||
// handling
|
||||
private int optimizedReceiverCount = 0;
|
||||
|
||||
|
||||
private void add(Transmitter t) {
|
||||
synchronized(transmitters) {
|
||||
transmitters.add(t);
|
||||
}
|
||||
if (t instanceof BasicTransmitter) {
|
||||
((BasicTransmitter) t).setTransmitterList(this);
|
||||
}
|
||||
if (Printer.debug) Printer.debug("--added transmitter "+t);
|
||||
}
|
||||
|
||||
private void remove(Transmitter t) {
|
||||
synchronized(transmitters) {
|
||||
int index = transmitters.indexOf(t);
|
||||
if (index >= 0) {
|
||||
transmitters.remove(index);
|
||||
if (Printer.debug) Printer.debug("--removed transmitter "+t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void receiverChanged(BasicTransmitter t,
|
||||
Receiver oldR,
|
||||
Receiver newR) {
|
||||
synchronized(transmitters) {
|
||||
// some optimization
|
||||
if (midiOutReceiver == oldR) {
|
||||
midiOutReceiver = null;
|
||||
}
|
||||
if (newR != null) {
|
||||
if ((newR instanceof MidiOutDevice.MidiOutReceiver)
|
||||
&& (midiOutReceiver == null)) {
|
||||
midiOutReceiver = ((MidiOutDevice.MidiOutReceiver) newR);
|
||||
}
|
||||
}
|
||||
optimizedReceiverCount =
|
||||
((midiOutReceiver!=null)?1:0);
|
||||
}
|
||||
// more potential for optimization here
|
||||
}
|
||||
|
||||
|
||||
/** closes all transmitters and empties the list */
|
||||
void close() {
|
||||
synchronized (transmitters) {
|
||||
for(int i = 0; i < transmitters.size(); i++) {
|
||||
transmitters.get(i).close();
|
||||
}
|
||||
transmitters.clear();
|
||||
}
|
||||
if (Printer.trace) Printer.trace("TransmitterList.close() succeeded");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Send this message to all receivers
|
||||
* status = packedMessage & 0xFF
|
||||
* data1 = (packedMessage & 0xFF00) >> 8;
|
||||
* data1 = (packedMessage & 0xFF0000) >> 16;
|
||||
*/
|
||||
void sendMessage(int packedMessage, long timeStamp) {
|
||||
try {
|
||||
synchronized(transmitters) {
|
||||
int size = transmitters.size();
|
||||
if (optimizedReceiverCount == size) {
|
||||
if (midiOutReceiver != null) {
|
||||
if (TRACE_TRANSMITTER) Printer.println("Sending packed message to MidiOutReceiver");
|
||||
midiOutReceiver.sendPackedMidiMessage(packedMessage, timeStamp);
|
||||
}
|
||||
} else {
|
||||
if (TRACE_TRANSMITTER) Printer.println("Sending packed message to "+size+" transmitter's receivers");
|
||||
for (int i = 0; i < size; i++) {
|
||||
Receiver receiver = ((Transmitter)transmitters.get(i)).getReceiver();
|
||||
if (receiver != null) {
|
||||
if (optimizedReceiverCount > 0) {
|
||||
if (receiver instanceof MidiOutDevice.MidiOutReceiver) {
|
||||
((MidiOutDevice.MidiOutReceiver) receiver).sendPackedMidiMessage(packedMessage, timeStamp);
|
||||
} else {
|
||||
receiver.send(new FastShortMessage(packedMessage), timeStamp);
|
||||
}
|
||||
} else {
|
||||
receiver.send(new FastShortMessage(packedMessage), timeStamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (InvalidMidiDataException e) {
|
||||
// this happens when invalid data comes over the wire. Ignore it.
|
||||
}
|
||||
}
|
||||
|
||||
void sendMessage(byte[] data, long timeStamp) {
|
||||
try {
|
||||
synchronized(transmitters) {
|
||||
int size = transmitters.size();
|
||||
if (TRACE_TRANSMITTER) Printer.println("Sending long message to "+size+" transmitter's receivers");
|
||||
for (int i = 0; i < size; i++) {
|
||||
Receiver receiver = ((Transmitter)transmitters.get(i)).getReceiver();
|
||||
if (receiver != null) {
|
||||
//$$fb 2002-04-02: SysexMessages are mutable, so
|
||||
// an application could change the contents of this object,
|
||||
// or try to use the object later. So we can't get around object creation
|
||||
// But the array need not be unique for each FastSysexMessage object,
|
||||
// because it cannot be modified.
|
||||
receiver.send(new FastSysexMessage(data), timeStamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (InvalidMidiDataException e) {
|
||||
// this happens when invalid data comes over the wire. Ignore it.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send this message to all transmitters
|
||||
*/
|
||||
void sendMessage(MidiMessage message, long timeStamp) {
|
||||
if (message instanceof FastShortMessage) {
|
||||
sendMessage(((FastShortMessage) message).getPackedMsg(), timeStamp);
|
||||
return;
|
||||
}
|
||||
synchronized(transmitters) {
|
||||
int size = transmitters.size();
|
||||
if (optimizedReceiverCount == size) {
|
||||
if (midiOutReceiver != null) {
|
||||
if (TRACE_TRANSMITTER) Printer.println("Sending MIDI message to MidiOutReceiver");
|
||||
midiOutReceiver.send(message, timeStamp);
|
||||
}
|
||||
} else {
|
||||
if (TRACE_TRANSMITTER) Printer.println("Sending MIDI message to "+size+" transmitter's receivers");
|
||||
for (int i = 0; i < size; i++) {
|
||||
Receiver receiver = ((Transmitter)transmitters.get(i)).getReceiver();
|
||||
if (receiver != null) {
|
||||
//$$fb 2002-04-02: ShortMessages are mutable, so
|
||||
// an application could change the contents of this object,
|
||||
// or try to use the object later.
|
||||
// We violate this spec here, to avoid costly (and gc-intensive)
|
||||
// object creation for potentially hundred of messages per second.
|
||||
// The spec should be changed to allow Immutable MidiMessages
|
||||
// (i.e. throws InvalidStateException or so in setMessage)
|
||||
receiver.send(message, timeStamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // TransmitterList
|
||||
|
||||
}
|
||||
196
jdkSrc/jdk8/com/sun/media/sound/AbstractMidiDeviceProvider.java
Normal file
196
jdkSrc/jdk8/com/sun/media/sound/AbstractMidiDeviceProvider.java
Normal file
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.media.sound;
|
||||
|
||||
import javax.sound.midi.MidiDevice;
|
||||
import javax.sound.midi.spi.MidiDeviceProvider;
|
||||
|
||||
|
||||
/**
|
||||
* Super class for MIDI input or output device provider.
|
||||
*
|
||||
* @author Florian Bomers
|
||||
*/
|
||||
public abstract class AbstractMidiDeviceProvider extends MidiDeviceProvider {
|
||||
|
||||
private static final boolean enabled;
|
||||
|
||||
/**
|
||||
* Create objects representing all MIDI output devices on the system.
|
||||
*/
|
||||
static {
|
||||
if (Printer.trace) Printer.trace("AbstractMidiDeviceProvider: static");
|
||||
Platform.initialize();
|
||||
enabled = Platform.isMidiIOEnabled();
|
||||
if (Printer.trace) Printer.trace("AbstractMidiDeviceProvider: enabled: " + enabled);
|
||||
|
||||
// $$fb number of MIDI devices may change with time
|
||||
// also for memory's sake, do not initialize the arrays here
|
||||
}
|
||||
|
||||
|
||||
final synchronized void readDeviceInfos() {
|
||||
Info[] infos = getInfoCache();
|
||||
MidiDevice[] devices = getDeviceCache();
|
||||
if (!enabled) {
|
||||
if (infos == null || infos.length != 0) {
|
||||
setInfoCache(new Info[0]);
|
||||
}
|
||||
if (devices == null || devices.length != 0) {
|
||||
setDeviceCache(new MidiDevice[0]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int oldNumDevices = (infos==null)?-1:infos.length;
|
||||
int newNumDevices = getNumDevices();
|
||||
if (oldNumDevices != newNumDevices) {
|
||||
if (Printer.trace) Printer.trace(getClass().toString()
|
||||
+": readDeviceInfos: old numDevices: "+oldNumDevices
|
||||
+" newNumDevices: "+ newNumDevices);
|
||||
|
||||
// initialize the arrays
|
||||
Info[] newInfos = new Info[newNumDevices];
|
||||
MidiDevice[] newDevices = new MidiDevice[newNumDevices];
|
||||
|
||||
for (int i = 0; i < newNumDevices; i++) {
|
||||
Info newInfo = createInfo(i);
|
||||
|
||||
// in case that we are re-reading devices, try to find
|
||||
// the previous one and reuse it
|
||||
if (infos != null) {
|
||||
for (int ii = 0; ii < infos.length; ii++) {
|
||||
Info info = infos[ii];
|
||||
if (info != null && info.equalStrings(newInfo)) {
|
||||
// new info matches the still existing info. Use old one
|
||||
newInfos[i] = info;
|
||||
info.setIndex(i);
|
||||
infos[ii] = null; // prevent re-use
|
||||
newDevices[i] = devices[ii];
|
||||
devices[ii] = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (newInfos[i] == null) {
|
||||
newInfos[i] = newInfo;
|
||||
}
|
||||
}
|
||||
// the remaining MidiDevice.Info instances in the infos array
|
||||
// have become obsolete.
|
||||
if (infos != null) {
|
||||
for (int i = 0; i < infos.length; i++) {
|
||||
if (infos[i] != null) {
|
||||
// disable this device info
|
||||
infos[i].setIndex(-1);
|
||||
}
|
||||
// what to do with the MidiDevice instances that are left
|
||||
// in the devices array ?? Close them ?
|
||||
}
|
||||
}
|
||||
// commit new list of infos.
|
||||
setInfoCache(newInfos);
|
||||
setDeviceCache(newDevices);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public final MidiDevice.Info[] getDeviceInfo() {
|
||||
readDeviceInfos();
|
||||
Info[] infos = getInfoCache();
|
||||
MidiDevice.Info[] localArray = new MidiDevice.Info[infos.length];
|
||||
System.arraycopy(infos, 0, localArray, 0, infos.length);
|
||||
return localArray;
|
||||
}
|
||||
|
||||
|
||||
public final MidiDevice getDevice(MidiDevice.Info info) {
|
||||
if (info instanceof Info) {
|
||||
readDeviceInfos();
|
||||
MidiDevice[] devices = getDeviceCache();
|
||||
Info[] infos = getInfoCache();
|
||||
Info thisInfo = (Info) info;
|
||||
int index = thisInfo.getIndex();
|
||||
if (index >= 0 && index < devices.length && infos[index] == info) {
|
||||
if (devices[index] == null) {
|
||||
devices[index] = createDevice(thisInfo);
|
||||
}
|
||||
if (devices[index] != null) {
|
||||
return devices[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("MidiDevice " + info.toString()
|
||||
+ " not supported by this provider.");
|
||||
}
|
||||
|
||||
|
||||
// INNER CLASSES
|
||||
|
||||
|
||||
/**
|
||||
* Info class for MidiDevices. Adds an index value for
|
||||
* making native references to a particular device.
|
||||
*/
|
||||
static class Info extends MidiDevice.Info {
|
||||
private int index;
|
||||
|
||||
Info(String name, String vendor, String description, String version, int index) {
|
||||
super(name, vendor, description, version);
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
final boolean equalStrings(Info info) {
|
||||
return (info != null
|
||||
&& getName().equals(info.getName())
|
||||
&& getVendor().equals(info.getVendor())
|
||||
&& getDescription().equals(info.getDescription())
|
||||
&& getVersion().equals(info.getVersion()));
|
||||
}
|
||||
|
||||
final int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
final void setIndex(int index) {
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
} // class Info
|
||||
|
||||
|
||||
// ABSTRACT METHODS
|
||||
|
||||
abstract int getNumDevices();
|
||||
abstract MidiDevice[] getDeviceCache();
|
||||
abstract void setDeviceCache(MidiDevice[] devices);
|
||||
abstract Info[] getInfoCache();
|
||||
abstract void setInfoCache(Info[] infos);
|
||||
|
||||
abstract Info createInfo(int index);
|
||||
abstract MidiDevice createDevice(Info info);
|
||||
}
|
||||
556
jdkSrc/jdk8/com/sun/media/sound/AbstractMixer.java
Normal file
556
jdkSrc/jdk8/com/sun/media/sound/AbstractMixer.java
Normal file
@@ -0,0 +1,556 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
import javax.sound.sampled.Control;
|
||||
import javax.sound.sampled.Mixer;
|
||||
import javax.sound.sampled.Line;
|
||||
import javax.sound.sampled.LineUnavailableException;
|
||||
|
||||
/**
|
||||
* Abstract Mixer. Implements Mixer (with abstract methods) and specifies
|
||||
* some other common methods for use by our implementation.
|
||||
*
|
||||
* @author Kara Kytle
|
||||
*/
|
||||
//$$fb 2002-07-26: let AbstractMixer be an AbstractLine and NOT an AbstractDataLine!
|
||||
abstract class AbstractMixer extends AbstractLine implements Mixer {
|
||||
|
||||
// STATIC VARIABLES
|
||||
protected static final int PCM = 0;
|
||||
protected static final int ULAW = 1;
|
||||
protected static final int ALAW = 2;
|
||||
|
||||
|
||||
// IMMUTABLE PROPERTIES
|
||||
|
||||
/**
|
||||
* Info object describing this mixer.
|
||||
*/
|
||||
private final Mixer.Info mixerInfo;
|
||||
|
||||
/**
|
||||
* source lines provided by this mixer
|
||||
*/
|
||||
protected Line.Info[] sourceLineInfo;
|
||||
|
||||
/**
|
||||
* target lines provided by this mixer
|
||||
*/
|
||||
protected Line.Info[] targetLineInfo;
|
||||
|
||||
/**
|
||||
* if any line of this mixer is started
|
||||
*/
|
||||
private boolean started = false;
|
||||
|
||||
/**
|
||||
* if this mixer had been opened manually with open()
|
||||
* If it was, then it won't be closed automatically,
|
||||
* only when close() is called manually.
|
||||
*/
|
||||
private boolean manuallyOpened = false;
|
||||
|
||||
|
||||
/**
|
||||
* Supported formats for the mixer.
|
||||
*/
|
||||
//$$fb DELETE
|
||||
//protected Vector formats = new Vector();
|
||||
|
||||
|
||||
// STATE VARIABLES
|
||||
|
||||
|
||||
/**
|
||||
* Source lines (ports) currently open
|
||||
*/
|
||||
private final Vector sourceLines = new Vector();
|
||||
|
||||
|
||||
/**
|
||||
* Target lines currently open.
|
||||
*/
|
||||
private final Vector targetLines = new Vector();
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a new AbstractMixer.
|
||||
* @param mixer the mixer with which this line is associated
|
||||
* @param controls set of supported controls
|
||||
*/
|
||||
protected AbstractMixer(Mixer.Info mixerInfo,
|
||||
Control[] controls,
|
||||
Line.Info[] sourceLineInfo,
|
||||
Line.Info[] targetLineInfo) {
|
||||
|
||||
// Line.Info, AbstractMixer, Control[]
|
||||
super(new Line.Info(Mixer.class), null, controls);
|
||||
|
||||
// setup the line part
|
||||
this.mixer = this;
|
||||
if (controls == null) {
|
||||
controls = new Control[0];
|
||||
}
|
||||
|
||||
// setup the mixer part
|
||||
this.mixerInfo = mixerInfo;
|
||||
this.sourceLineInfo = sourceLineInfo;
|
||||
this.targetLineInfo = targetLineInfo;
|
||||
}
|
||||
|
||||
|
||||
// MIXER METHODS
|
||||
|
||||
|
||||
public final Mixer.Info getMixerInfo() {
|
||||
return mixerInfo;
|
||||
}
|
||||
|
||||
|
||||
public final Line.Info[] getSourceLineInfo() {
|
||||
Line.Info[] localArray = new Line.Info[sourceLineInfo.length];
|
||||
System.arraycopy(sourceLineInfo, 0, localArray, 0, sourceLineInfo.length);
|
||||
return localArray;
|
||||
}
|
||||
|
||||
|
||||
public final Line.Info[] getTargetLineInfo() {
|
||||
|
||||
Line.Info[] localArray = new Line.Info[targetLineInfo.length];
|
||||
System.arraycopy(targetLineInfo, 0, localArray, 0, targetLineInfo.length);
|
||||
return localArray;
|
||||
}
|
||||
|
||||
|
||||
public final Line.Info[] getSourceLineInfo(Line.Info info) {
|
||||
|
||||
int i;
|
||||
Vector vec = new Vector();
|
||||
|
||||
for (i = 0; i < sourceLineInfo.length; i++) {
|
||||
|
||||
if (info.matches(sourceLineInfo[i])) {
|
||||
vec.addElement(sourceLineInfo[i]);
|
||||
}
|
||||
}
|
||||
|
||||
Line.Info[] returnedArray = new Line.Info[vec.size()];
|
||||
for (i = 0; i < returnedArray.length; i++) {
|
||||
returnedArray[i] = (Line.Info)vec.elementAt(i);
|
||||
}
|
||||
|
||||
return returnedArray;
|
||||
}
|
||||
|
||||
|
||||
public final Line.Info[] getTargetLineInfo(Line.Info info) {
|
||||
|
||||
int i;
|
||||
Vector vec = new Vector();
|
||||
|
||||
for (i = 0; i < targetLineInfo.length; i++) {
|
||||
|
||||
if (info.matches(targetLineInfo[i])) {
|
||||
vec.addElement(targetLineInfo[i]);
|
||||
}
|
||||
}
|
||||
|
||||
Line.Info[] returnedArray = new Line.Info[vec.size()];
|
||||
for (i = 0; i < returnedArray.length; i++) {
|
||||
returnedArray[i] = (Line.Info)vec.elementAt(i);
|
||||
}
|
||||
|
||||
return returnedArray;
|
||||
}
|
||||
|
||||
|
||||
public final boolean isLineSupported(Line.Info info) {
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sourceLineInfo.length; i++) {
|
||||
|
||||
if (info.matches(sourceLineInfo[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < targetLineInfo.length; i++) {
|
||||
|
||||
if (info.matches(targetLineInfo[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public abstract Line getLine(Line.Info info) throws LineUnavailableException;
|
||||
|
||||
public abstract int getMaxLines(Line.Info info);
|
||||
|
||||
protected abstract void implOpen() throws LineUnavailableException;
|
||||
protected abstract void implStart();
|
||||
protected abstract void implStop();
|
||||
protected abstract void implClose();
|
||||
|
||||
|
||||
public final Line[] getSourceLines() {
|
||||
|
||||
Line[] localLines;
|
||||
|
||||
synchronized(sourceLines) {
|
||||
|
||||
localLines = new Line[sourceLines.size()];
|
||||
|
||||
for (int i = 0; i < localLines.length; i++) {
|
||||
localLines[i] = (Line)sourceLines.elementAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
return localLines;
|
||||
}
|
||||
|
||||
|
||||
public final Line[] getTargetLines() {
|
||||
|
||||
Line[] localLines;
|
||||
|
||||
synchronized(targetLines) {
|
||||
|
||||
localLines = new Line[targetLines.size()];
|
||||
|
||||
for (int i = 0; i < localLines.length; i++) {
|
||||
localLines[i] = (Line)targetLines.elementAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
return localLines;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Default implementation always throws an exception.
|
||||
*/
|
||||
public final void synchronize(Line[] lines, boolean maintainSync) {
|
||||
throw new IllegalArgumentException("Synchronization not supported by this mixer.");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Default implementation always throws an exception.
|
||||
*/
|
||||
public final void unsynchronize(Line[] lines) {
|
||||
throw new IllegalArgumentException("Synchronization not supported by this mixer.");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Default implementation always returns false.
|
||||
*/
|
||||
public final boolean isSynchronizationSupported(Line[] lines,
|
||||
boolean maintainSync) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// OVERRIDES OF ABSTRACT DATA LINE METHODS
|
||||
|
||||
/**
|
||||
* This implementation tries to open the mixer with its current format and buffer size settings.
|
||||
*/
|
||||
public final synchronized void open() throws LineUnavailableException {
|
||||
open(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation tries to open the mixer with its current format and buffer size settings.
|
||||
*/
|
||||
final synchronized void open(boolean manual) throws LineUnavailableException {
|
||||
if (Printer.trace) Printer.trace(">> AbstractMixer: open()");
|
||||
if (!isOpen()) {
|
||||
implOpen();
|
||||
// if the mixer is not currently open, set open to true and send event
|
||||
setOpen(true);
|
||||
if (manual) {
|
||||
manuallyOpened = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (Printer.trace) Printer.trace("<< AbstractMixer: open() succeeded");
|
||||
}
|
||||
|
||||
|
||||
// METHOD FOR INTERNAL IMPLEMENTATION USE
|
||||
|
||||
|
||||
/**
|
||||
* The default implementation of this method just determines whether
|
||||
* this line is a source or target line, calls open(no-arg) on the
|
||||
* mixer, and adds the line to the appropriate vector.
|
||||
* The mixer may be opened at a format different than the line's
|
||||
* format if it is a DataLine.
|
||||
*/
|
||||
final synchronized void open(Line line) throws LineUnavailableException {
|
||||
|
||||
if (Printer.trace) Printer.trace(">> AbstractMixer: open(line = " + line + ")");
|
||||
|
||||
// $$kk: 06.11.99: ignore ourselves for now
|
||||
if (this.equals(line)) {
|
||||
if (Printer.trace) Printer.trace("<< AbstractMixer: open(" + line + ") nothing done");
|
||||
return;
|
||||
}
|
||||
|
||||
// source line?
|
||||
if (isSourceLine(line.getLineInfo())) {
|
||||
if (! sourceLines.contains(line) ) {
|
||||
// call the no-arg open method for the mixer; it should open at its
|
||||
// default format if it is not open yet
|
||||
open(false);
|
||||
|
||||
// we opened successfully! add the line to the list
|
||||
sourceLines.addElement(line);
|
||||
}
|
||||
} else {
|
||||
// target line?
|
||||
if(isTargetLine(line.getLineInfo())) {
|
||||
if (! targetLines.contains(line) ) {
|
||||
// call the no-arg open method for the mixer; it should open at its
|
||||
// default format if it is not open yet
|
||||
open(false);
|
||||
|
||||
// we opened successfully! add the line to the list
|
||||
targetLines.addElement(line);
|
||||
}
|
||||
} else {
|
||||
if (Printer.err) Printer.err("Unknown line received for AbstractMixer.open(Line): " + line);
|
||||
}
|
||||
}
|
||||
|
||||
if (Printer.trace) Printer.trace("<< AbstractMixer: open(" + line + ") completed");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes this line from the list of open source lines and
|
||||
* open target lines, if it exists in either.
|
||||
* If the list is now empty, closes the mixer.
|
||||
*/
|
||||
final synchronized void close(Line line) {
|
||||
|
||||
if (Printer.trace) Printer.trace(">> AbstractMixer: close(" + line + ")");
|
||||
|
||||
// $$kk: 06.11.99: ignore ourselves for now
|
||||
if (this.equals(line)) {
|
||||
if (Printer.trace) Printer.trace("<< AbstractMixer: close(" + line + ") nothing done");
|
||||
return;
|
||||
}
|
||||
|
||||
sourceLines.removeElement(line);
|
||||
targetLines.removeElement(line);
|
||||
|
||||
if (Printer.debug) Printer.debug("AbstractMixer: close(line): sourceLines.size() now: " + sourceLines.size());
|
||||
if (Printer.debug) Printer.debug("AbstractMixer: close(line): targetLines.size() now: " + targetLines.size());
|
||||
|
||||
|
||||
if (sourceLines.isEmpty() && targetLines.isEmpty() && !manuallyOpened) {
|
||||
if (Printer.trace) Printer.trace("AbstractMixer: close(" + line + "): need to close the mixer");
|
||||
close();
|
||||
}
|
||||
|
||||
if (Printer.trace) Printer.trace("<< AbstractMixer: close(" + line + ") succeeded");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Close all lines and then close this mixer.
|
||||
*/
|
||||
public final synchronized void close() {
|
||||
if (Printer.trace) Printer.trace(">> AbstractMixer: close()");
|
||||
if (isOpen()) {
|
||||
// close all source lines
|
||||
Line[] localLines = getSourceLines();
|
||||
for (int i = 0; i<localLines.length; i++) {
|
||||
localLines[i].close();
|
||||
}
|
||||
|
||||
// close all target lines
|
||||
localLines = getTargetLines();
|
||||
for (int i = 0; i<localLines.length; i++) {
|
||||
localLines[i].close();
|
||||
}
|
||||
|
||||
implClose();
|
||||
|
||||
// set the open state to false and send events
|
||||
setOpen(false);
|
||||
}
|
||||
manuallyOpened = false;
|
||||
if (Printer.trace) Printer.trace("<< AbstractMixer: close() succeeded");
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the mixer.
|
||||
*/
|
||||
final synchronized void start(Line line) {
|
||||
|
||||
if (Printer.trace) Printer.trace(">> AbstractMixer: start(" + line + ")");
|
||||
|
||||
// $$kk: 06.11.99: ignore ourselves for now
|
||||
if (this.equals(line)) {
|
||||
if (Printer.trace) Printer.trace("<< AbstractMixer: start(" + line + ") nothing done");
|
||||
return;
|
||||
}
|
||||
|
||||
// we just start the mixer regardless of anything else here.
|
||||
if (!started) {
|
||||
if (Printer.debug) Printer.debug("AbstractMixer: start(line): starting the mixer");
|
||||
implStart();
|
||||
started = true;
|
||||
}
|
||||
|
||||
if (Printer.trace) Printer.trace("<< AbstractMixer: start(" + line + ") succeeded");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Stops the mixer if this was the last running line.
|
||||
*/
|
||||
final synchronized void stop(Line line) {
|
||||
|
||||
if (Printer.trace) Printer.trace(">> AbstractMixer: stop(" + line + ")");
|
||||
|
||||
// $$kk: 06.11.99: ignore ourselves for now
|
||||
if (this.equals(line)) {
|
||||
if (Printer.trace) Printer.trace("<< AbstractMixer: stop(" + line + ") nothing done");
|
||||
return;
|
||||
}
|
||||
|
||||
Vector localSourceLines = (Vector)sourceLines.clone();
|
||||
for (int i = 0; i < localSourceLines.size(); i++) {
|
||||
|
||||
// if any other open line is running, return
|
||||
|
||||
// this covers clips and source data lines
|
||||
if (localSourceLines.elementAt(i) instanceof AbstractDataLine) {
|
||||
AbstractDataLine sourceLine = (AbstractDataLine)localSourceLines.elementAt(i);
|
||||
if ( sourceLine.isStartedRunning() && (!sourceLine.equals(line)) ) {
|
||||
if (Printer.trace) Printer.trace("<< AbstractMixer: stop(" + line + ") found running sourceLine: " + sourceLine);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vector localTargetLines = (Vector)targetLines.clone();
|
||||
for (int i = 0; i < localTargetLines.size(); i++) {
|
||||
|
||||
// if any other open line is running, return
|
||||
// this covers target data lines
|
||||
if (localTargetLines.elementAt(i) instanceof AbstractDataLine) {
|
||||
AbstractDataLine targetLine = (AbstractDataLine)localTargetLines.elementAt(i);
|
||||
if ( targetLine.isStartedRunning() && (!targetLine.equals(line)) ) {
|
||||
if (Printer.trace) Printer.trace("<< AbstractMixer: stop(" + line + ") found running targetLine: " + targetLine);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise, stop
|
||||
if (Printer.debug) Printer.debug("AbstractMixer: stop(line): stopping the mixer");
|
||||
started = false;
|
||||
implStop();
|
||||
|
||||
if (Printer.trace) Printer.trace("<< AbstractMixer: stop(" + line + ") succeeded");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Determines whether this is a source line for this mixer.
|
||||
* Right now this just checks whether it's supported, but should
|
||||
* check whether it actually belongs to this mixer....
|
||||
*/
|
||||
final boolean isSourceLine(Line.Info info) {
|
||||
|
||||
for (int i = 0; i < sourceLineInfo.length; i++) {
|
||||
if (info.matches(sourceLineInfo[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determines whether this is a target line for this mixer.
|
||||
* Right now this just checks whether it's supported, but should
|
||||
* check whether it actually belongs to this mixer....
|
||||
*/
|
||||
final boolean isTargetLine(Line.Info info) {
|
||||
|
||||
for (int i = 0; i < targetLineInfo.length; i++) {
|
||||
if (info.matches(targetLineInfo[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the first complete Line.Info object it finds that
|
||||
* matches the one specified, or null if no matching Line.Info
|
||||
* object is found.
|
||||
*/
|
||||
final Line.Info getLineInfo(Line.Info info) {
|
||||
if (info == null) {
|
||||
return null;
|
||||
}
|
||||
// $$kk: 05.31.99: need to change this so that
|
||||
// the format and buffer size get set in the
|
||||
// returned info object for data lines??
|
||||
for (int i = 0; i < sourceLineInfo.length; i++) {
|
||||
if (info.matches(sourceLineInfo[i])) {
|
||||
return sourceLineInfo[i];
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < targetLineInfo.length; i++) {
|
||||
if (info.matches(targetLineInfo[i])) {
|
||||
return targetLineInfo[i];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
97
jdkSrc/jdk8/com/sun/media/sound/AiffFileFormat.java
Normal file
97
jdkSrc/jdk8/com/sun/media/sound/AiffFileFormat.java
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.media.sound;
|
||||
|
||||
import javax.sound.sampled.AudioFileFormat;
|
||||
import javax.sound.sampled.AudioFormat;
|
||||
|
||||
|
||||
/**
|
||||
* AIFF file format.
|
||||
*
|
||||
* @author Jan Borgersen
|
||||
*/
|
||||
|
||||
final class AiffFileFormat extends AudioFileFormat {
|
||||
|
||||
static final int AIFF_MAGIC = 1179603533;
|
||||
|
||||
// for writing AIFF
|
||||
static final int AIFC_MAGIC = 0x41494643; // 'AIFC'
|
||||
static final int AIFF_MAGIC2 = 0x41494646; // 'AIFF'
|
||||
static final int FVER_MAGIC = 0x46564552; // 'FVER'
|
||||
static final int FVER_TIMESTAMP = 0xA2805140; // timestamp of last AIFF-C update
|
||||
static final int COMM_MAGIC = 0x434f4d4d; // 'COMM'
|
||||
static final int SSND_MAGIC = 0x53534e44; // 'SSND'
|
||||
|
||||
// compression codes
|
||||
static final int AIFC_PCM = 0x4e4f4e45; // 'NONE' PCM
|
||||
static final int AIFC_ACE2 = 0x41434532; // 'ACE2' ACE 2:1 compression
|
||||
static final int AIFC_ACE8 = 0x41434538; // 'ACE8' ACE 8:3 compression
|
||||
static final int AIFC_MAC3 = 0x4d414333; // 'MAC3' MACE 3:1 compression
|
||||
static final int AIFC_MAC6 = 0x4d414336; // 'MAC6' MACE 6:1 compression
|
||||
static final int AIFC_ULAW = 0x756c6177; // 'ulaw' ITU G.711 u-Law
|
||||
static final int AIFC_IMA4 = 0x696d6134; // 'ima4' IMA ADPCM
|
||||
|
||||
// $$fb static approach not good, but needed for estimation
|
||||
static final int AIFF_HEADERSIZE = 54;
|
||||
|
||||
//$$fb 2001-07-13: added management of header size in this class
|
||||
|
||||
/** header size in bytes */
|
||||
private final int headerSize=AIFF_HEADERSIZE;
|
||||
|
||||
/** comm chunk size in bytes, inclusive magic and length field */
|
||||
private final int commChunkSize=26;
|
||||
|
||||
/** FVER chunk size in bytes, inclusive magic and length field */
|
||||
private final int fverChunkSize=0;
|
||||
|
||||
AiffFileFormat( AudioFileFormat aff ) {
|
||||
this( aff.getType(), aff.getByteLength(), aff.getFormat(), aff.getFrameLength() );
|
||||
}
|
||||
|
||||
AiffFileFormat(Type type, int byteLength, AudioFormat format, int frameLength) {
|
||||
super(type, byteLength, format, frameLength);
|
||||
}
|
||||
|
||||
int getHeaderSize() {
|
||||
return headerSize;
|
||||
}
|
||||
|
||||
int getCommChunkSize() {
|
||||
return commChunkSize;
|
||||
}
|
||||
|
||||
int getFverChunkSize() {
|
||||
return fverChunkSize;
|
||||
}
|
||||
|
||||
int getSsndChunkOffset() {
|
||||
return getHeaderSize()-16;
|
||||
}
|
||||
|
||||
}
|
||||
438
jdkSrc/jdk8/com/sun/media/sound/AiffFileReader.java
Normal file
438
jdkSrc/jdk8/com/sun/media/sound/AiffFileReader.java
Normal file
@@ -0,0 +1,438 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
|
||||
import javax.sound.sampled.AudioFileFormat;
|
||||
import javax.sound.sampled.AudioFormat;
|
||||
import javax.sound.sampled.AudioInputStream;
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
import javax.sound.sampled.UnsupportedAudioFileException;
|
||||
|
||||
|
||||
/**
|
||||
* AIFF file reader and writer.
|
||||
*
|
||||
* @author Kara Kytle
|
||||
* @author Jan Borgersen
|
||||
* @author Florian Bomers
|
||||
*/
|
||||
public final class AiffFileReader extends SunFileReader {
|
||||
|
||||
private static final int MAX_READ_LENGTH = 8;
|
||||
|
||||
// METHODS TO IMPLEMENT AudioFileReader
|
||||
|
||||
/**
|
||||
* Obtains the audio file format of the input stream provided. The stream must
|
||||
* point to valid audio file data. In general, audio file providers may
|
||||
* need to read some data from the stream before determining whether they
|
||||
* support it. These parsers must
|
||||
* be able to mark the stream, read enough data to determine whether they
|
||||
* support the stream, and, if not, reset the stream's read pointer to its original
|
||||
* position. If the input stream does not support this, this method may fail
|
||||
* with an IOException.
|
||||
* @param stream the input stream from which file format information should be
|
||||
* extracted
|
||||
* @return an <code>AudioFileFormat</code> object describing the audio file format
|
||||
* @throws UnsupportedAudioFileException if the stream does not point to valid audio
|
||||
* file data recognized by the system
|
||||
* @throws IOException if an I/O exception occurs
|
||||
* @see InputStream#markSupported
|
||||
* @see InputStream#mark
|
||||
*/
|
||||
public AudioFileFormat getAudioFileFormat(InputStream stream) throws UnsupportedAudioFileException, IOException {
|
||||
// fix for 4489272: AudioSystem.getAudioFileFormat() fails for InputStream, but works for URL
|
||||
AudioFileFormat aff = getCOMM(stream, true);
|
||||
// the following is not strictly necessary - but was implemented like that in 1.3.0 - 1.4.1
|
||||
// so I leave it as it was. May remove this for 1.5.0
|
||||
stream.reset();
|
||||
return aff;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtains the audio file format of the URL provided. The URL must
|
||||
* point to valid audio file data.
|
||||
* @param url the URL from which file format information should be
|
||||
* extracted
|
||||
* @return an <code>AudioFileFormat</code> object describing the audio file format
|
||||
* @throws UnsupportedAudioFileException if the URL does not point to valid audio
|
||||
* file data recognized by the system
|
||||
* @throws IOException if an I/O exception occurs
|
||||
*/
|
||||
public AudioFileFormat getAudioFileFormat(URL url) throws UnsupportedAudioFileException, IOException {
|
||||
AudioFileFormat fileFormat = null;
|
||||
InputStream urlStream = url.openStream(); // throws IOException
|
||||
try {
|
||||
fileFormat = getCOMM(urlStream, false);
|
||||
} finally {
|
||||
urlStream.close();
|
||||
}
|
||||
return fileFormat;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtains the audio file format of the File provided. The File must
|
||||
* point to valid audio file data.
|
||||
* @param file the File from which file format information should be
|
||||
* extracted
|
||||
* @return an <code>AudioFileFormat</code> object describing the audio file format
|
||||
* @throws UnsupportedAudioFileException if the File does not point to valid audio
|
||||
* file data recognized by the system
|
||||
* @throws IOException if an I/O exception occurs
|
||||
*/
|
||||
public AudioFileFormat getAudioFileFormat(File file) throws UnsupportedAudioFileException, IOException {
|
||||
AudioFileFormat fileFormat = null;
|
||||
FileInputStream fis = new FileInputStream(file); // throws IOException
|
||||
// part of fix for 4325421
|
||||
try {
|
||||
fileFormat = getCOMM(fis, false);
|
||||
} finally {
|
||||
fis.close();
|
||||
}
|
||||
|
||||
return fileFormat;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Obtains an audio stream from the input stream provided. The stream must
|
||||
* point to valid audio file data. In general, audio file providers may
|
||||
* need to read some data from the stream before determining whether they
|
||||
* support it. These parsers must
|
||||
* be able to mark the stream, read enough data to determine whether they
|
||||
* support the stream, and, if not, reset the stream's read pointer to its original
|
||||
* position. If the input stream does not support this, this method may fail
|
||||
* with an IOException.
|
||||
* @param stream the input stream from which the <code>AudioInputStream</code> should be
|
||||
* constructed
|
||||
* @return an <code>AudioInputStream</code> object based on the audio file data contained
|
||||
* in the input stream.
|
||||
* @throws UnsupportedAudioFileException if the stream does not point to valid audio
|
||||
* file data recognized by the system
|
||||
* @throws IOException if an I/O exception occurs
|
||||
* @see InputStream#markSupported
|
||||
* @see InputStream#mark
|
||||
*/
|
||||
public AudioInputStream getAudioInputStream(InputStream stream) throws UnsupportedAudioFileException, IOException {
|
||||
// getCOMM leaves the input stream at the beginning of the audio data
|
||||
AudioFileFormat fileFormat = getCOMM(stream, true); // throws UnsupportedAudioFileException, IOException
|
||||
|
||||
// we've got everything, and the stream is at the
|
||||
// beginning of the audio data, so return an AudioInputStream.
|
||||
return new AudioInputStream(stream, fileFormat.getFormat(), fileFormat.getFrameLength());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtains an audio stream from the URL provided. The URL must
|
||||
* point to valid audio file data.
|
||||
* @param url the URL for which the <code>AudioInputStream</code> should be
|
||||
* constructed
|
||||
* @return an <code>AudioInputStream</code> object based on the audio file data pointed
|
||||
* to by the URL
|
||||
* @throws UnsupportedAudioFileException if the URL does not point to valid audio
|
||||
* file data recognized by the system
|
||||
* @throws IOException if an I/O exception occurs
|
||||
*/
|
||||
public AudioInputStream getAudioInputStream(URL url) throws UnsupportedAudioFileException, IOException {
|
||||
InputStream urlStream = url.openStream(); // throws IOException
|
||||
AudioFileFormat fileFormat = null;
|
||||
try {
|
||||
fileFormat = getCOMM(urlStream, false);
|
||||
} finally {
|
||||
if (fileFormat == null) {
|
||||
urlStream.close();
|
||||
}
|
||||
}
|
||||
return new AudioInputStream(urlStream, fileFormat.getFormat(), fileFormat.getFrameLength());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtains an audio stream from the File provided. The File must
|
||||
* point to valid audio file data.
|
||||
* @param file the File for which the <code>AudioInputStream</code> should be
|
||||
* constructed
|
||||
* @return an <code>AudioInputStream</code> object based on the audio file data pointed
|
||||
* to by the File
|
||||
* @throws UnsupportedAudioFileException if the File does not point to valid audio
|
||||
* file data recognized by the system
|
||||
* @throws IOException if an I/O exception occurs
|
||||
*/
|
||||
public AudioInputStream getAudioInputStream(File file)
|
||||
throws UnsupportedAudioFileException, IOException {
|
||||
|
||||
FileInputStream fis = new FileInputStream(file); // throws IOException
|
||||
AudioFileFormat fileFormat = null;
|
||||
// part of fix for 4325421
|
||||
try {
|
||||
fileFormat = getCOMM(fis, false);
|
||||
} finally {
|
||||
if (fileFormat == null) {
|
||||
fis.close();
|
||||
}
|
||||
}
|
||||
return new AudioInputStream(fis, fileFormat.getFormat(), fileFormat.getFrameLength());
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
private AudioFileFormat getCOMM(InputStream is, boolean doReset)
|
||||
throws UnsupportedAudioFileException, IOException {
|
||||
|
||||
DataInputStream dis = new DataInputStream(is);
|
||||
|
||||
if (doReset) {
|
||||
dis.mark(MAX_READ_LENGTH);
|
||||
}
|
||||
|
||||
// assumes a stream at the beginning of the file which has already
|
||||
// passed the magic number test...
|
||||
// leaves the input stream at the beginning of the audio data
|
||||
int fileRead = 0;
|
||||
int dataLength = 0;
|
||||
AudioFormat format = null;
|
||||
|
||||
// Read the magic number
|
||||
int magic = dis.readInt();
|
||||
|
||||
// $$fb: fix for 4369044: javax.sound.sampled.AudioSystem.getAudioInputStream() works wrong with Cp037
|
||||
if (magic != AiffFileFormat.AIFF_MAGIC) {
|
||||
// not AIFF, throw exception
|
||||
if (doReset) {
|
||||
dis.reset();
|
||||
}
|
||||
throw new UnsupportedAudioFileException("not an AIFF file");
|
||||
}
|
||||
|
||||
int length = dis.readInt();
|
||||
int iffType = dis.readInt();
|
||||
fileRead += 12;
|
||||
|
||||
int totallength;
|
||||
if(length <= 0 ) {
|
||||
length = AudioSystem.NOT_SPECIFIED;
|
||||
totallength = AudioSystem.NOT_SPECIFIED;
|
||||
} else {
|
||||
totallength = length + 8;
|
||||
}
|
||||
|
||||
// Is this an AIFC or just plain AIFF file.
|
||||
boolean aifc = false;
|
||||
// $$fb: fix for 4369044: javax.sound.sampled.AudioSystem.getAudioInputStream() works wrong with Cp037
|
||||
if (iffType == AiffFileFormat.AIFC_MAGIC) {
|
||||
aifc = true;
|
||||
}
|
||||
|
||||
// Loop through the AIFF chunks until
|
||||
// we get to the SSND chunk.
|
||||
boolean ssndFound = false;
|
||||
while (!ssndFound) {
|
||||
// Read the chunk name
|
||||
int chunkName = dis.readInt();
|
||||
int chunkLen = dis.readInt();
|
||||
fileRead += 8;
|
||||
|
||||
int chunkRead = 0;
|
||||
|
||||
// Switch on the chunk name.
|
||||
switch (chunkName) {
|
||||
case AiffFileFormat.FVER_MAGIC:
|
||||
// Ignore format version for now.
|
||||
break;
|
||||
|
||||
case AiffFileFormat.COMM_MAGIC:
|
||||
// AIFF vs. AIFC
|
||||
// $$fb: fix for 4399551: Repost of bug candidate: cannot replay aif file (Review ID: 108108)
|
||||
if ((!aifc && chunkLen < 18) || (aifc && chunkLen < 22)) {
|
||||
throw new UnsupportedAudioFileException("Invalid AIFF/COMM chunksize");
|
||||
}
|
||||
// Read header info.
|
||||
int channels = dis.readUnsignedShort();
|
||||
if (channels <= 0) {
|
||||
throw new UnsupportedAudioFileException("Invalid number of channels");
|
||||
}
|
||||
dis.readInt(); // numSampleFrames
|
||||
int sampleSizeInBits = dis.readUnsignedShort();
|
||||
if (sampleSizeInBits < 1 || sampleSizeInBits > 32) {
|
||||
throw new UnsupportedAudioFileException("Invalid AIFF/COMM sampleSize");
|
||||
}
|
||||
float sampleRate = (float) read_ieee_extended(dis);
|
||||
chunkRead += (2 + 4 + 2 + 10);
|
||||
|
||||
// If this is not AIFC then we assume it's
|
||||
// a linearly encoded file.
|
||||
AudioFormat.Encoding encoding = AudioFormat.Encoding.PCM_SIGNED;
|
||||
|
||||
if (aifc) {
|
||||
int enc = dis.readInt(); chunkRead += 4;
|
||||
switch (enc) {
|
||||
case AiffFileFormat.AIFC_PCM:
|
||||
encoding = AudioFormat.Encoding.PCM_SIGNED;
|
||||
break;
|
||||
case AiffFileFormat.AIFC_ULAW:
|
||||
encoding = AudioFormat.Encoding.ULAW;
|
||||
sampleSizeInBits = 8; // Java Sound convention
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedAudioFileException("Invalid AIFF encoding");
|
||||
}
|
||||
}
|
||||
int frameSize = calculatePCMFrameSize(sampleSizeInBits, channels);
|
||||
//$fb what's that ??
|
||||
//if (sampleSizeInBits == 8) {
|
||||
// encoding = AudioFormat.Encoding.PCM_SIGNED;
|
||||
//}
|
||||
format = new AudioFormat(encoding, sampleRate,
|
||||
sampleSizeInBits, channels,
|
||||
frameSize, sampleRate, true);
|
||||
break;
|
||||
case AiffFileFormat.SSND_MAGIC:
|
||||
// Data chunk.
|
||||
// we are getting *weird* numbers for chunkLen sometimes;
|
||||
// this really should be the size of the data chunk....
|
||||
int dataOffset = dis.readInt();
|
||||
int blocksize = dis.readInt();
|
||||
chunkRead += 8;
|
||||
|
||||
// okay, now we are done reading the header. we need to set the size
|
||||
// of the data segment. we know that sometimes the value we get for
|
||||
// the chunksize is absurd. this is the best i can think of:if the
|
||||
// value seems okay, use it. otherwise, we get our value of
|
||||
// length by assuming that everything left is the data segment;
|
||||
// its length should be our original length (for all AIFF data chunks)
|
||||
// minus what we've read so far.
|
||||
// $$kk: we should be able to get length for the data chunk right after
|
||||
// we find "SSND." however, some aiff files give *weird* numbers. what
|
||||
// is going on??
|
||||
|
||||
if (chunkLen < length) {
|
||||
dataLength = chunkLen - chunkRead;
|
||||
} else {
|
||||
// $$kk: 11.03.98: this seems dangerous!
|
||||
dataLength = length - (fileRead + chunkRead);
|
||||
}
|
||||
ssndFound = true;
|
||||
break;
|
||||
} // switch
|
||||
fileRead += chunkRead;
|
||||
// skip the remainder of this chunk
|
||||
if (!ssndFound) {
|
||||
int toSkip = chunkLen - chunkRead;
|
||||
if (toSkip > 0) {
|
||||
fileRead += dis.skipBytes(toSkip);
|
||||
}
|
||||
}
|
||||
} // while
|
||||
|
||||
if (format == null) {
|
||||
throw new UnsupportedAudioFileException("missing COMM chunk");
|
||||
}
|
||||
AudioFileFormat.Type type = aifc?AudioFileFormat.Type.AIFC:AudioFileFormat.Type.AIFF;
|
||||
|
||||
return new AiffFileFormat(type, totallength, format, dataLength / format.getFrameSize());
|
||||
}
|
||||
|
||||
// HELPER METHODS
|
||||
/** write_ieee_extended(DataOutputStream dos, double f) throws IOException {
|
||||
* Extended precision IEEE floating-point conversion routine.
|
||||
* @argument DataOutputStream
|
||||
* @argument double
|
||||
* @return void
|
||||
* @exception IOException
|
||||
*/
|
||||
private void write_ieee_extended(DataOutputStream dos, double f) throws IOException {
|
||||
|
||||
int exponent = 16398;
|
||||
double highMantissa = f;
|
||||
|
||||
// For now write the integer portion of f
|
||||
// $$jb: 03.30.99: stay in synch with JMF on this!!!!
|
||||
while (highMantissa < 44000) {
|
||||
highMantissa *= 2;
|
||||
exponent--;
|
||||
}
|
||||
dos.writeShort(exponent);
|
||||
dos.writeInt( ((int) highMantissa) << 16);
|
||||
dos.writeInt(0); // low Mantissa
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* read_ieee_extended
|
||||
* Extended precision IEEE floating-point conversion routine.
|
||||
* @argument DataInputStream
|
||||
* @return double
|
||||
* @exception IOException
|
||||
*/
|
||||
private double read_ieee_extended(DataInputStream dis) throws IOException {
|
||||
|
||||
double f = 0;
|
||||
int expon = 0;
|
||||
long hiMant = 0, loMant = 0;
|
||||
long t1, t2;
|
||||
double HUGE = ((double)3.40282346638528860e+38);
|
||||
|
||||
|
||||
expon = dis.readUnsignedShort();
|
||||
|
||||
t1 = (long)dis.readUnsignedShort();
|
||||
t2 = (long)dis.readUnsignedShort();
|
||||
hiMant = t1 << 16 | t2;
|
||||
|
||||
t1 = (long)dis.readUnsignedShort();
|
||||
t2 = (long)dis.readUnsignedShort();
|
||||
loMant = t1 << 16 | t2;
|
||||
|
||||
if (expon == 0 && hiMant == 0 && loMant == 0) {
|
||||
f = 0;
|
||||
} else {
|
||||
if (expon == 0x7FFF)
|
||||
f = HUGE;
|
||||
else {
|
||||
expon -= 16383;
|
||||
expon -= 31;
|
||||
f = (hiMant * Math.pow(2, expon));
|
||||
expon -= 32;
|
||||
f += (loMant * Math.pow(2, expon));
|
||||
}
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
}
|
||||
449
jdkSrc/jdk8/com/sun/media/sound/AiffFileWriter.java
Normal file
449
jdkSrc/jdk8/com/sun/media/sound/AiffFileWriter.java
Normal file
@@ -0,0 +1,449 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.io.SequenceInputStream;
|
||||
|
||||
import javax.sound.sampled.AudioFileFormat;
|
||||
import javax.sound.sampled.AudioInputStream;
|
||||
import javax.sound.sampled.AudioFormat;
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
|
||||
//$$fb this class is buggy. Should be replaced in future.
|
||||
|
||||
/**
|
||||
* AIFF file writer.
|
||||
*
|
||||
* @author Jan Borgersen
|
||||
*/
|
||||
public final class AiffFileWriter extends SunFileWriter {
|
||||
|
||||
/**
|
||||
* Constructs a new AiffFileWriter object.
|
||||
*/
|
||||
public AiffFileWriter() {
|
||||
super(new AudioFileFormat.Type[]{AudioFileFormat.Type.AIFF});
|
||||
}
|
||||
|
||||
|
||||
// METHODS TO IMPLEMENT AudioFileWriter
|
||||
|
||||
public AudioFileFormat.Type[] getAudioFileTypes(AudioInputStream stream) {
|
||||
|
||||
AudioFileFormat.Type[] filetypes = new AudioFileFormat.Type[types.length];
|
||||
System.arraycopy(types, 0, filetypes, 0, types.length);
|
||||
|
||||
// make sure we can write this stream
|
||||
AudioFormat format = stream.getFormat();
|
||||
AudioFormat.Encoding encoding = format.getEncoding();
|
||||
|
||||
if( (AudioFormat.Encoding.ALAW.equals(encoding)) ||
|
||||
(AudioFormat.Encoding.ULAW.equals(encoding)) ||
|
||||
(AudioFormat.Encoding.PCM_SIGNED.equals(encoding)) ||
|
||||
(AudioFormat.Encoding.PCM_UNSIGNED.equals(encoding)) ) {
|
||||
|
||||
return filetypes;
|
||||
}
|
||||
|
||||
return new AudioFileFormat.Type[0];
|
||||
}
|
||||
|
||||
|
||||
public int write(AudioInputStream stream, AudioFileFormat.Type fileType, OutputStream out) throws IOException {
|
||||
|
||||
//$$fb the following check must come first ! Otherwise
|
||||
// the next frame length check may throw an IOException and
|
||||
// interrupt iterating File Writers. (see bug 4351296)
|
||||
|
||||
// throws IllegalArgumentException if not supported
|
||||
AiffFileFormat aiffFileFormat = (AiffFileFormat)getAudioFileFormat(fileType, stream);
|
||||
|
||||
// we must know the total data length to calculate the file length
|
||||
if( stream.getFrameLength() == AudioSystem.NOT_SPECIFIED ) {
|
||||
throw new IOException("stream length not specified");
|
||||
}
|
||||
|
||||
int bytesWritten = writeAiffFile(stream, aiffFileFormat, out);
|
||||
return bytesWritten;
|
||||
}
|
||||
|
||||
|
||||
public int write(AudioInputStream stream, AudioFileFormat.Type fileType, File out) throws IOException {
|
||||
|
||||
// throws IllegalArgumentException if not supported
|
||||
AiffFileFormat aiffFileFormat = (AiffFileFormat)getAudioFileFormat(fileType, stream);
|
||||
|
||||
// first write the file without worrying about length fields
|
||||
FileOutputStream fos = new FileOutputStream( out ); // throws IOException
|
||||
BufferedOutputStream bos = new BufferedOutputStream( fos, bisBufferSize );
|
||||
int bytesWritten = writeAiffFile(stream, aiffFileFormat, bos );
|
||||
bos.close();
|
||||
|
||||
// now, if length fields were not specified, calculate them,
|
||||
// open as a random access file, write the appropriate fields,
|
||||
// close again....
|
||||
if( aiffFileFormat.getByteLength()== AudioSystem.NOT_SPECIFIED ) {
|
||||
|
||||
// $$kk: 10.22.99: jan: please either implement this or throw an exception!
|
||||
// $$fb: 2001-07-13: done. Fixes Bug 4479981
|
||||
int ssndBlockSize = (aiffFileFormat.getFormat().getChannels() * aiffFileFormat.getFormat().getSampleSizeInBits());
|
||||
|
||||
int aiffLength=bytesWritten;
|
||||
int ssndChunkSize=aiffLength-aiffFileFormat.getHeaderSize()+16;
|
||||
long dataSize=ssndChunkSize-16;
|
||||
int numFrames=(int) (dataSize*8/ssndBlockSize);
|
||||
|
||||
RandomAccessFile raf=new RandomAccessFile(out, "rw");
|
||||
// skip FORM magic
|
||||
raf.skipBytes(4);
|
||||
raf.writeInt(aiffLength-8);
|
||||
// skip aiff2 magic, fver chunk, comm magic, comm size, channel count,
|
||||
raf.skipBytes(4+aiffFileFormat.getFverChunkSize()+4+4+2);
|
||||
// write frame count
|
||||
raf.writeInt(numFrames);
|
||||
// skip sample size, samplerate, SSND magic
|
||||
raf.skipBytes(2+10+4);
|
||||
raf.writeInt(ssndChunkSize-8);
|
||||
// that's all
|
||||
raf.close();
|
||||
}
|
||||
|
||||
return bytesWritten;
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the AudioFileFormat describing the file that will be written from this AudioInputStream.
|
||||
* Throws IllegalArgumentException if not supported.
|
||||
*/
|
||||
private AudioFileFormat getAudioFileFormat(AudioFileFormat.Type type, AudioInputStream stream) {
|
||||
|
||||
AudioFormat format = null;
|
||||
AiffFileFormat fileFormat = null;
|
||||
AudioFormat.Encoding encoding = AudioFormat.Encoding.PCM_SIGNED;
|
||||
|
||||
AudioFormat streamFormat = stream.getFormat();
|
||||
AudioFormat.Encoding streamEncoding = streamFormat.getEncoding();
|
||||
|
||||
|
||||
float sampleRate;
|
||||
int sampleSizeInBits;
|
||||
int channels;
|
||||
int frameSize;
|
||||
float frameRate;
|
||||
int fileSize;
|
||||
boolean convert8to16 = false;
|
||||
|
||||
if( !types[0].equals(type) ) {
|
||||
throw new IllegalArgumentException("File type " + type + " not supported.");
|
||||
}
|
||||
|
||||
if( (AudioFormat.Encoding.ALAW.equals(streamEncoding)) ||
|
||||
(AudioFormat.Encoding.ULAW.equals(streamEncoding)) ) {
|
||||
|
||||
if( streamFormat.getSampleSizeInBits()==8 ) {
|
||||
|
||||
encoding = AudioFormat.Encoding.PCM_SIGNED;
|
||||
sampleSizeInBits=16;
|
||||
convert8to16 = true;
|
||||
|
||||
} else {
|
||||
|
||||
// can't convert non-8-bit ALAW,ULAW
|
||||
throw new IllegalArgumentException("Encoding " + streamEncoding + " supported only for 8-bit data.");
|
||||
}
|
||||
} else if ( streamFormat.getSampleSizeInBits()==8 ) {
|
||||
|
||||
encoding = AudioFormat.Encoding.PCM_UNSIGNED;
|
||||
sampleSizeInBits=8;
|
||||
|
||||
} else {
|
||||
|
||||
encoding = AudioFormat.Encoding.PCM_SIGNED;
|
||||
sampleSizeInBits=streamFormat.getSampleSizeInBits();
|
||||
}
|
||||
|
||||
|
||||
format = new AudioFormat( encoding,
|
||||
streamFormat.getSampleRate(),
|
||||
sampleSizeInBits,
|
||||
streamFormat.getChannels(),
|
||||
streamFormat.getFrameSize(),
|
||||
streamFormat.getFrameRate(),
|
||||
true); // AIFF is big endian
|
||||
|
||||
|
||||
if( stream.getFrameLength()!=AudioSystem.NOT_SPECIFIED ) {
|
||||
if( convert8to16 ) {
|
||||
fileSize = (int)stream.getFrameLength()*streamFormat.getFrameSize()*2 + AiffFileFormat.AIFF_HEADERSIZE;
|
||||
} else {
|
||||
fileSize = (int)stream.getFrameLength()*streamFormat.getFrameSize() + AiffFileFormat.AIFF_HEADERSIZE;
|
||||
}
|
||||
} else {
|
||||
fileSize = AudioSystem.NOT_SPECIFIED;
|
||||
}
|
||||
|
||||
fileFormat = new AiffFileFormat( AudioFileFormat.Type.AIFF,
|
||||
fileSize,
|
||||
format,
|
||||
(int)stream.getFrameLength() );
|
||||
|
||||
return fileFormat;
|
||||
}
|
||||
|
||||
|
||||
private int writeAiffFile(InputStream in, AiffFileFormat aiffFileFormat, OutputStream out) throws IOException {
|
||||
|
||||
int bytesRead = 0;
|
||||
int bytesWritten = 0;
|
||||
InputStream fileStream = getFileStream(aiffFileFormat, in);
|
||||
byte buffer[] = new byte[bisBufferSize];
|
||||
int maxLength = aiffFileFormat.getByteLength();
|
||||
|
||||
while( (bytesRead = fileStream.read( buffer )) >= 0 ) {
|
||||
if (maxLength>0) {
|
||||
if( bytesRead < maxLength ) {
|
||||
out.write( buffer, 0, (int)bytesRead );
|
||||
bytesWritten += bytesRead;
|
||||
maxLength -= bytesRead;
|
||||
} else {
|
||||
out.write( buffer, 0, (int)maxLength );
|
||||
bytesWritten += maxLength;
|
||||
maxLength = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
out.write( buffer, 0, (int)bytesRead );
|
||||
bytesWritten += bytesRead;
|
||||
}
|
||||
}
|
||||
|
||||
return bytesWritten;
|
||||
}
|
||||
|
||||
private InputStream getFileStream(AiffFileFormat aiffFileFormat, InputStream audioStream) throws IOException {
|
||||
|
||||
// private method ... assumes aiffFileFormat is a supported file format
|
||||
|
||||
AudioFormat format = aiffFileFormat.getFormat();
|
||||
AudioFormat streamFormat = null;
|
||||
AudioFormat.Encoding encoding = null;
|
||||
|
||||
//$$fb a little bit nicer handling of constants
|
||||
|
||||
//int headerSize = 54;
|
||||
int headerSize = aiffFileFormat.getHeaderSize();
|
||||
|
||||
//int fverChunkSize = 0;
|
||||
int fverChunkSize = aiffFileFormat.getFverChunkSize();
|
||||
//int commChunkSize = 26;
|
||||
int commChunkSize = aiffFileFormat.getCommChunkSize();
|
||||
int aiffLength = -1;
|
||||
int ssndChunkSize = -1;
|
||||
//int ssndOffset = headerSize - 16;
|
||||
int ssndOffset = aiffFileFormat.getSsndChunkOffset();
|
||||
short channels = (short) format.getChannels();
|
||||
short sampleSize = (short) format.getSampleSizeInBits();
|
||||
int ssndBlockSize = (channels * sampleSize);
|
||||
int numFrames = aiffFileFormat.getFrameLength();
|
||||
long dataSize = -1;
|
||||
if( numFrames != AudioSystem.NOT_SPECIFIED) {
|
||||
dataSize = (long) numFrames * ssndBlockSize / 8;
|
||||
ssndChunkSize = (int)dataSize + 16;
|
||||
aiffLength = (int)dataSize+headerSize;
|
||||
}
|
||||
float sampleFramesPerSecond = format.getSampleRate();
|
||||
int compCode = AiffFileFormat.AIFC_PCM;
|
||||
|
||||
byte header[] = null;
|
||||
ByteArrayInputStream headerStream = null;
|
||||
ByteArrayOutputStream baos = null;
|
||||
DataOutputStream dos = null;
|
||||
SequenceInputStream aiffStream = null;
|
||||
InputStream codedAudioStream = audioStream;
|
||||
|
||||
// if we need to do any format conversion, do it here....
|
||||
|
||||
if( audioStream instanceof AudioInputStream ) {
|
||||
|
||||
streamFormat = ((AudioInputStream)audioStream).getFormat();
|
||||
encoding = streamFormat.getEncoding();
|
||||
|
||||
|
||||
// $$jb: Note that AIFF samples are ALWAYS signed
|
||||
if( (AudioFormat.Encoding.PCM_UNSIGNED.equals(encoding)) ||
|
||||
( (AudioFormat.Encoding.PCM_SIGNED.equals(encoding)) && !streamFormat.isBigEndian() ) ) {
|
||||
|
||||
// plug in the transcoder to convert to PCM_SIGNED. big endian
|
||||
codedAudioStream = AudioSystem.getAudioInputStream( new AudioFormat (
|
||||
AudioFormat.Encoding.PCM_SIGNED,
|
||||
streamFormat.getSampleRate(),
|
||||
streamFormat.getSampleSizeInBits(),
|
||||
streamFormat.getChannels(),
|
||||
streamFormat.getFrameSize(),
|
||||
streamFormat.getFrameRate(),
|
||||
true ),
|
||||
(AudioInputStream)audioStream );
|
||||
|
||||
} else if( (AudioFormat.Encoding.ULAW.equals(encoding)) ||
|
||||
(AudioFormat.Encoding.ALAW.equals(encoding)) ) {
|
||||
|
||||
if( streamFormat.getSampleSizeInBits() != 8 ) {
|
||||
throw new IllegalArgumentException("unsupported encoding");
|
||||
}
|
||||
|
||||
//$$fb 2001-07-13: this is probably not what we want:
|
||||
// writing PCM when ULAW/ALAW is requested. AIFC is able to write ULAW !
|
||||
|
||||
// plug in the transcoder to convert to PCM_SIGNED_BIG_ENDIAN
|
||||
codedAudioStream = AudioSystem.getAudioInputStream( new AudioFormat (
|
||||
AudioFormat.Encoding.PCM_SIGNED,
|
||||
streamFormat.getSampleRate(),
|
||||
streamFormat.getSampleSizeInBits() * 2,
|
||||
streamFormat.getChannels(),
|
||||
streamFormat.getFrameSize() * 2,
|
||||
streamFormat.getFrameRate(),
|
||||
true ),
|
||||
(AudioInputStream)audioStream );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Now create an AIFF stream header...
|
||||
baos = new ByteArrayOutputStream();
|
||||
dos = new DataOutputStream(baos);
|
||||
|
||||
// Write the outer FORM chunk
|
||||
dos.writeInt(AiffFileFormat.AIFF_MAGIC);
|
||||
dos.writeInt( (aiffLength-8) );
|
||||
dos.writeInt(AiffFileFormat.AIFF_MAGIC2);
|
||||
|
||||
// Write a FVER chunk - only for AIFC
|
||||
//dos.writeInt(FVER_MAGIC);
|
||||
//dos.writeInt( (fverChunkSize-8) );
|
||||
//dos.writeInt(FVER_TIMESTAMP);
|
||||
|
||||
// Write a COMM chunk
|
||||
dos.writeInt(AiffFileFormat.COMM_MAGIC);
|
||||
dos.writeInt( (commChunkSize-8) );
|
||||
dos.writeShort(channels);
|
||||
dos.writeInt(numFrames);
|
||||
dos.writeShort(sampleSize);
|
||||
write_ieee_extended(dos, sampleFramesPerSecond); // 10 bytes
|
||||
|
||||
//Only for AIFC
|
||||
//dos.writeInt(compCode);
|
||||
//dos.writeInt(compCode);
|
||||
//dos.writeShort(0);
|
||||
|
||||
// Write the SSND chunk header
|
||||
dos.writeInt(AiffFileFormat.SSND_MAGIC);
|
||||
dos.writeInt( (ssndChunkSize-8) );
|
||||
// ssndOffset and ssndBlockSize set to 0 upon
|
||||
// recommendation in "Sound Manager" chapter in
|
||||
// "Inside Macintosh Sound", pp 2-87 (from Babu)
|
||||
dos.writeInt(0); // ssndOffset
|
||||
dos.writeInt(0); // ssndBlockSize
|
||||
|
||||
// Concat this with the audioStream and return it
|
||||
|
||||
dos.close();
|
||||
header = baos.toByteArray();
|
||||
headerStream = new ByteArrayInputStream( header );
|
||||
|
||||
aiffStream = new SequenceInputStream(headerStream,
|
||||
new NoCloseInputStream(codedAudioStream));
|
||||
|
||||
return aiffStream;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// HELPER METHODS
|
||||
|
||||
private static final int DOUBLE_MANTISSA_LENGTH = 52;
|
||||
private static final int DOUBLE_EXPONENT_LENGTH = 11;
|
||||
private static final long DOUBLE_SIGN_MASK = 0x8000000000000000L;
|
||||
private static final long DOUBLE_EXPONENT_MASK = 0x7FF0000000000000L;
|
||||
private static final long DOUBLE_MANTISSA_MASK = 0x000FFFFFFFFFFFFFL;
|
||||
private static final int DOUBLE_EXPONENT_OFFSET = 1023;
|
||||
|
||||
private static final int EXTENDED_EXPONENT_OFFSET = 16383;
|
||||
private static final int EXTENDED_MANTISSA_LENGTH = 63;
|
||||
private static final int EXTENDED_EXPONENT_LENGTH = 15;
|
||||
private static final long EXTENDED_INTEGER_MASK = 0x8000000000000000L;
|
||||
|
||||
/**
|
||||
* Extended precision IEEE floating-point conversion routine.
|
||||
* @argument DataOutputStream
|
||||
* @argument double
|
||||
* @exception IOException
|
||||
*/
|
||||
private void write_ieee_extended(DataOutputStream dos, float f) throws IOException {
|
||||
/* The special cases NaN, Infinity and Zero are ignored, since
|
||||
they do not represent useful sample rates anyway.
|
||||
Denormalized number aren't handled, too. Below, there is a cast
|
||||
from float to double. We hope that in this conversion,
|
||||
numbers are normalized. Numbers that cannot be normalized are
|
||||
ignored, too, as they, too, do not represent useful sample rates. */
|
||||
long doubleBits = Double.doubleToLongBits((double) f);
|
||||
|
||||
long sign = (doubleBits & DOUBLE_SIGN_MASK)
|
||||
>> (DOUBLE_EXPONENT_LENGTH + DOUBLE_MANTISSA_LENGTH);
|
||||
long doubleExponent = (doubleBits & DOUBLE_EXPONENT_MASK)
|
||||
>> DOUBLE_MANTISSA_LENGTH;
|
||||
long doubleMantissa = doubleBits & DOUBLE_MANTISSA_MASK;
|
||||
|
||||
long extendedExponent = doubleExponent - DOUBLE_EXPONENT_OFFSET
|
||||
+ EXTENDED_EXPONENT_OFFSET;
|
||||
long extendedMantissa = doubleMantissa
|
||||
<< (EXTENDED_MANTISSA_LENGTH - DOUBLE_MANTISSA_LENGTH);
|
||||
long extendedSign = sign << EXTENDED_EXPONENT_LENGTH;
|
||||
short extendedBits79To64 = (short) (extendedSign | extendedExponent);
|
||||
long extendedBits63To0 = EXTENDED_INTEGER_MASK | extendedMantissa;
|
||||
|
||||
dos.writeShort(extendedBits79To64);
|
||||
dos.writeLong(extendedBits63To0);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
448
jdkSrc/jdk8/com/sun/media/sound/AlawCodec.java
Normal file
448
jdkSrc/jdk8/com/sun/media/sound/AlawCodec.java
Normal file
@@ -0,0 +1,448 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Vector;
|
||||
|
||||
import javax.sound.sampled.AudioFormat;
|
||||
import javax.sound.sampled.AudioInputStream;
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
|
||||
|
||||
/**
|
||||
* A-law encodes linear data, and decodes a-law data to linear data.
|
||||
*
|
||||
* @author Kara Kytle
|
||||
*/
|
||||
public final class AlawCodec extends SunCodec {
|
||||
|
||||
/* Tables used for A-law decoding */
|
||||
|
||||
private static final byte[] ALAW_TABH = new byte[256];
|
||||
private static final byte[] ALAW_TABL = new byte[256];
|
||||
|
||||
private static final AudioFormat.Encoding[] alawEncodings = { AudioFormat.Encoding.ALAW, AudioFormat.Encoding.PCM_SIGNED };
|
||||
|
||||
private static final short seg_end [] = {0xFF, 0x1FF, 0x3FF,
|
||||
0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF};
|
||||
|
||||
/**
|
||||
* Initializes the decode tables
|
||||
*/
|
||||
static {
|
||||
for (int i=0;i<256;i++) {
|
||||
int input = i ^ 0x55;
|
||||
int mantissa = (input & 0xf ) << 4;
|
||||
int segment = (input & 0x70) >> 4;
|
||||
int value = mantissa+8;
|
||||
|
||||
if(segment>=1)
|
||||
value+=0x100;
|
||||
if(segment>1)
|
||||
value <<= (segment -1);
|
||||
|
||||
if( (input & 0x80)==0 )
|
||||
value = -value;
|
||||
|
||||
ALAW_TABL[i] = (byte)value;
|
||||
ALAW_TABH[i] = (byte)(value>>8);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a new ALAW codec object.
|
||||
*/
|
||||
public AlawCodec() {
|
||||
|
||||
super(alawEncodings, alawEncodings);
|
||||
}
|
||||
|
||||
// NEW CODE
|
||||
|
||||
/**
|
||||
*/
|
||||
public AudioFormat.Encoding[] getTargetEncodings(AudioFormat sourceFormat){
|
||||
|
||||
if( sourceFormat.getEncoding().equals( AudioFormat.Encoding.PCM_SIGNED )) {
|
||||
|
||||
if( sourceFormat.getSampleSizeInBits() == 16 ) {
|
||||
|
||||
AudioFormat.Encoding enc[] = new AudioFormat.Encoding[1];
|
||||
enc[0] = AudioFormat.Encoding.ALAW;
|
||||
return enc;
|
||||
|
||||
} else {
|
||||
return new AudioFormat.Encoding[0];
|
||||
}
|
||||
} else if( sourceFormat.getEncoding().equals( AudioFormat.Encoding.ALAW ) ) {
|
||||
|
||||
if( sourceFormat.getSampleSizeInBits() == 8 ) {
|
||||
|
||||
AudioFormat.Encoding enc[] = new AudioFormat.Encoding[1];
|
||||
enc[0] = AudioFormat.Encoding.PCM_SIGNED;
|
||||
return enc;
|
||||
|
||||
} else {
|
||||
return new AudioFormat.Encoding[0];
|
||||
}
|
||||
|
||||
} else {
|
||||
return new AudioFormat.Encoding[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
public AudioFormat[] getTargetFormats(AudioFormat.Encoding targetEncoding, AudioFormat sourceFormat){
|
||||
if( (targetEncoding.equals( AudioFormat.Encoding.PCM_SIGNED ) && sourceFormat.getEncoding().equals( AudioFormat.Encoding.ALAW)) ||
|
||||
(targetEncoding.equals( AudioFormat.Encoding.ALAW) && sourceFormat.getEncoding().equals( AudioFormat.Encoding.PCM_SIGNED)) ) {
|
||||
return getOutputFormats( sourceFormat );
|
||||
} else {
|
||||
return new AudioFormat[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
public AudioInputStream getAudioInputStream(AudioFormat.Encoding targetEncoding, AudioInputStream sourceStream){
|
||||
AudioFormat sourceFormat = sourceStream.getFormat();
|
||||
AudioFormat.Encoding sourceEncoding = sourceFormat.getEncoding();
|
||||
|
||||
if( sourceEncoding.equals( targetEncoding ) ) {
|
||||
return sourceStream;
|
||||
} else {
|
||||
AudioFormat targetFormat = null;
|
||||
if( !isConversionSupported(targetEncoding,sourceStream.getFormat()) ) {
|
||||
throw new IllegalArgumentException("Unsupported conversion: " + sourceStream.getFormat().toString() + " to " + targetEncoding.toString());
|
||||
}
|
||||
if( sourceEncoding.equals( AudioFormat.Encoding.ALAW ) &&
|
||||
targetEncoding.equals( AudioFormat.Encoding.PCM_SIGNED ) ) {
|
||||
|
||||
targetFormat = new AudioFormat( targetEncoding,
|
||||
sourceFormat.getSampleRate(),
|
||||
16,
|
||||
sourceFormat.getChannels(),
|
||||
2*sourceFormat.getChannels(),
|
||||
sourceFormat.getSampleRate(),
|
||||
sourceFormat.isBigEndian());
|
||||
|
||||
} else if( sourceEncoding.equals( AudioFormat.Encoding.PCM_SIGNED ) &&
|
||||
targetEncoding.equals( AudioFormat.Encoding.ALAW ) ) {
|
||||
|
||||
targetFormat = new AudioFormat( targetEncoding,
|
||||
sourceFormat.getSampleRate(),
|
||||
8,
|
||||
sourceFormat.getChannels(),
|
||||
sourceFormat.getChannels(),
|
||||
sourceFormat.getSampleRate(),
|
||||
false);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported conversion: " + sourceStream.getFormat().toString() + " to " + targetEncoding.toString());
|
||||
}
|
||||
return getAudioInputStream( targetFormat, sourceStream );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* use old code...
|
||||
*/
|
||||
public AudioInputStream getAudioInputStream(AudioFormat targetFormat, AudioInputStream sourceStream){
|
||||
return getConvertedStream( targetFormat, sourceStream );
|
||||
}
|
||||
|
||||
|
||||
// OLD CODE
|
||||
|
||||
|
||||
/**
|
||||
* Opens the codec with the specified parameters.
|
||||
* @param stream stream from which data to be processed should be read
|
||||
* @param outputFormat desired data format of the stream after processing
|
||||
* @return stream from which processed data may be read
|
||||
* @throws IllegalArgumentException if the format combination supplied is
|
||||
* not supported.
|
||||
*/
|
||||
/* public AudioInputStream getConvertedStream(AudioFormat outputFormat, AudioInputStream stream) { */
|
||||
private AudioInputStream getConvertedStream(AudioFormat outputFormat, AudioInputStream stream) {
|
||||
|
||||
AudioInputStream cs = null;
|
||||
AudioFormat inputFormat = stream.getFormat();
|
||||
|
||||
if( inputFormat.matches(outputFormat) ) {
|
||||
cs = stream;
|
||||
} else {
|
||||
cs = (AudioInputStream) (new AlawCodecStream(stream, outputFormat));
|
||||
}
|
||||
|
||||
return cs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the set of output formats supported by the codec
|
||||
* given a particular input format.
|
||||
* If no output formats are supported for this input format,
|
||||
* returns an array of length 0.
|
||||
* @return array of supported output formats.
|
||||
*/
|
||||
/* public AudioFormat[] getOutputFormats(AudioFormat inputFormat) { */
|
||||
private AudioFormat[] getOutputFormats(AudioFormat inputFormat) {
|
||||
|
||||
|
||||
Vector formats = new Vector();
|
||||
AudioFormat format;
|
||||
|
||||
if ( AudioFormat.Encoding.PCM_SIGNED.equals(inputFormat.getEncoding())) {
|
||||
format = new AudioFormat(AudioFormat.Encoding.ALAW,
|
||||
inputFormat.getSampleRate(),
|
||||
8,
|
||||
inputFormat.getChannels(),
|
||||
inputFormat.getChannels(),
|
||||
inputFormat.getSampleRate(),
|
||||
false );
|
||||
formats.addElement(format);
|
||||
}
|
||||
|
||||
if (AudioFormat.Encoding.ALAW.equals(inputFormat.getEncoding())) {
|
||||
format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
|
||||
inputFormat.getSampleRate(),
|
||||
16,
|
||||
inputFormat.getChannels(),
|
||||
inputFormat.getChannels()*2,
|
||||
inputFormat.getSampleRate(),
|
||||
false );
|
||||
formats.addElement(format);
|
||||
format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
|
||||
inputFormat.getSampleRate(),
|
||||
16,
|
||||
inputFormat.getChannels(),
|
||||
inputFormat.getChannels()*2,
|
||||
inputFormat.getSampleRate(),
|
||||
true );
|
||||
formats.addElement(format);
|
||||
}
|
||||
|
||||
AudioFormat[] formatArray = new AudioFormat[formats.size()];
|
||||
for (int i = 0; i < formatArray.length; i++) {
|
||||
formatArray[i] = (AudioFormat)(formats.elementAt(i));
|
||||
}
|
||||
return formatArray;
|
||||
}
|
||||
|
||||
|
||||
final class AlawCodecStream extends AudioInputStream {
|
||||
|
||||
// tempBuffer required only for encoding (when encode is true)
|
||||
private static final int tempBufferSize = 64;
|
||||
private byte tempBuffer [] = null;
|
||||
|
||||
/**
|
||||
* True to encode to a-law, false to decode to linear
|
||||
*/
|
||||
boolean encode = false;
|
||||
|
||||
AudioFormat encodeFormat;
|
||||
AudioFormat decodeFormat;
|
||||
|
||||
byte tabByte1[] = null;
|
||||
byte tabByte2[] = null;
|
||||
int highByte = 0;
|
||||
int lowByte = 1;
|
||||
|
||||
AlawCodecStream(AudioInputStream stream, AudioFormat outputFormat) {
|
||||
|
||||
super(stream, outputFormat, -1);
|
||||
|
||||
AudioFormat inputFormat = stream.getFormat();
|
||||
|
||||
// throw an IllegalArgumentException if not ok
|
||||
if ( ! (isConversionSupported(outputFormat, inputFormat)) ) {
|
||||
|
||||
throw new IllegalArgumentException("Unsupported conversion: " + inputFormat.toString() + " to " + outputFormat.toString());
|
||||
}
|
||||
|
||||
//$$fb 2002-07-18: fix for 4714846: JavaSound ULAW (8-bit) encoder erroneously depends on endian-ness
|
||||
boolean PCMIsBigEndian;
|
||||
|
||||
// determine whether we are encoding or decoding
|
||||
if (AudioFormat.Encoding.ALAW.equals(inputFormat.getEncoding())) {
|
||||
encode = false;
|
||||
encodeFormat = inputFormat;
|
||||
decodeFormat = outputFormat;
|
||||
PCMIsBigEndian = outputFormat.isBigEndian();
|
||||
} else {
|
||||
encode = true;
|
||||
encodeFormat = outputFormat;
|
||||
decodeFormat = inputFormat;
|
||||
PCMIsBigEndian = inputFormat.isBigEndian();
|
||||
tempBuffer = new byte[tempBufferSize];
|
||||
}
|
||||
|
||||
if (PCMIsBigEndian) {
|
||||
tabByte1 = ALAW_TABH;
|
||||
tabByte2 = ALAW_TABL;
|
||||
highByte = 0;
|
||||
lowByte = 1;
|
||||
} else {
|
||||
tabByte1 = ALAW_TABL;
|
||||
tabByte2 = ALAW_TABH;
|
||||
highByte = 1;
|
||||
lowByte = 0;
|
||||
}
|
||||
|
||||
// set the AudioInputStream length in frames if we know it
|
||||
if (stream instanceof AudioInputStream) {
|
||||
frameLength = ((AudioInputStream)stream).getFrameLength();
|
||||
}
|
||||
|
||||
// set framePos to zero
|
||||
framePos = 0;
|
||||
frameSize = inputFormat.getFrameSize();
|
||||
if( frameSize==AudioSystem.NOT_SPECIFIED ) {
|
||||
frameSize=1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* $$jb 2/23/99
|
||||
* Used to determine segment number in aLaw encoding
|
||||
*/
|
||||
private short search(short val, short table[], short size) {
|
||||
for(short i = 0; i < size; i++) {
|
||||
if (val <= table[i]) { return i; }
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note that this won't actually read anything; must read in
|
||||
* two-byte units.
|
||||
*/
|
||||
public int read() throws IOException {
|
||||
|
||||
byte[] b = new byte[1];
|
||||
return (int)read(b, 0, b.length);
|
||||
}
|
||||
|
||||
|
||||
public int read(byte[] b) throws IOException {
|
||||
|
||||
return read(b, 0, b.length);
|
||||
}
|
||||
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
|
||||
// don't read fractional frames
|
||||
if( len%frameSize != 0 ) {
|
||||
len -= (len%frameSize);
|
||||
}
|
||||
|
||||
if (encode) {
|
||||
|
||||
short QUANT_MASK = 0xF;
|
||||
short SEG_SHIFT = 4;
|
||||
short mask;
|
||||
short seg;
|
||||
int adj;
|
||||
int i;
|
||||
|
||||
short sample;
|
||||
byte enc;
|
||||
|
||||
int readCount = 0;
|
||||
int currentPos = off;
|
||||
int readLeft = len*2;
|
||||
int readLen = ( (readLeft>tempBufferSize) ? tempBufferSize : readLeft );
|
||||
|
||||
while ((readCount = super.read(tempBuffer,0,readLen))>0) {
|
||||
|
||||
for (i = 0; i < readCount; i+=2) {
|
||||
|
||||
/* Get the sample from the tempBuffer */
|
||||
sample = (short)(( (tempBuffer[i + highByte]) << 8) & 0xFF00);
|
||||
sample |= (short)( (tempBuffer[i + lowByte]) & 0xFF);
|
||||
|
||||
if(sample >= 0) {
|
||||
mask = 0xD5;
|
||||
} else {
|
||||
mask = 0x55;
|
||||
sample = (short)(-sample - 8);
|
||||
}
|
||||
/* Convert the scaled magnitude to segment number. */
|
||||
seg = search(sample, seg_end, (short) 8);
|
||||
/*
|
||||
* Combine the sign, segment, quantization bits
|
||||
*/
|
||||
if (seg >= 8) { /* out of range, return maximum value. */
|
||||
enc = (byte) (0x7F ^ mask);
|
||||
} else {
|
||||
enc = (byte) (seg << SEG_SHIFT);
|
||||
if(seg < 2) {
|
||||
enc |= (byte) ( (sample >> 4) & QUANT_MASK);
|
||||
} else {
|
||||
enc |= (byte) ( (sample >> (seg + 3)) & QUANT_MASK );
|
||||
}
|
||||
enc ^= mask;
|
||||
}
|
||||
/* Now put the encoded sample where it belongs */
|
||||
b[currentPos] = enc;
|
||||
currentPos++;
|
||||
}
|
||||
/* And update pointers and counters for next iteration */
|
||||
readLeft -= readCount;
|
||||
readLen = ( (readLeft>tempBufferSize) ? tempBufferSize : readLeft );
|
||||
}
|
||||
|
||||
if( currentPos==off && readCount<0 ) { // EOF or error
|
||||
return readCount;
|
||||
}
|
||||
|
||||
return (currentPos - off); /* Number of bytes written to new buffer */
|
||||
|
||||
} else {
|
||||
|
||||
int i;
|
||||
int readLen = len/2;
|
||||
int readOffset = off + len/2;
|
||||
int readCount = super.read(b, readOffset, readLen);
|
||||
|
||||
for (i = off; i < (off + (readCount*2)); i+=2) {
|
||||
b[i] = (byte)tabByte1[b[readOffset] & 0xFF];
|
||||
b[i+1] = (byte)tabByte2[b[readOffset] & 0xFF];
|
||||
readOffset++;
|
||||
}
|
||||
|
||||
if( readCount<0 ) { // EOF or error
|
||||
return readCount;
|
||||
}
|
||||
|
||||
return (i - off);
|
||||
}
|
||||
}
|
||||
} // end class AlawCodecStream
|
||||
} // end class ALAW
|
||||
105
jdkSrc/jdk8/com/sun/media/sound/AuFileFormat.java
Normal file
105
jdkSrc/jdk8/com/sun/media/sound/AuFileFormat.java
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.media.sound;
|
||||
|
||||
|
||||
import javax.sound.sampled.AudioFileFormat;
|
||||
import javax.sound.sampled.AudioFormat;
|
||||
|
||||
|
||||
/**
|
||||
* AU file format.
|
||||
*
|
||||
* @author Jan Borgersen
|
||||
*/
|
||||
|
||||
final class AuFileFormat extends AudioFileFormat {
|
||||
|
||||
// magic numbers
|
||||
static final int AU_SUN_MAGIC = 0x2e736e64;
|
||||
static final int AU_SUN_INV_MAGIC = 0x646e732e;
|
||||
static final int AU_DEC_MAGIC = 0x2e736400;
|
||||
static final int AU_DEC_INV_MAGIC = 0x0064732e;
|
||||
|
||||
// encodings
|
||||
static final int AU_ULAW_8 = 1; /* 8-bit ISDN u-law */
|
||||
static final int AU_LINEAR_8 = 2; /* 8-bit linear PCM */
|
||||
static final int AU_LINEAR_16 = 3; /* 16-bit linear PCM */
|
||||
static final int AU_LINEAR_24 = 4; /* 24-bit linear PCM */
|
||||
static final int AU_LINEAR_32 = 5; /* 32-bit linear PCM */
|
||||
static final int AU_FLOAT = 6; /* 32-bit IEEE floating point */
|
||||
static final int AU_DOUBLE = 7; /* 64-bit IEEE floating point */
|
||||
static final int AU_ADPCM_G721 = 23; /* 4-bit CCITT g.721 ADPCM */
|
||||
static final int AU_ADPCM_G722 = 24; /* CCITT g.722 ADPCM */
|
||||
static final int AU_ADPCM_G723_3 = 25; /* CCITT g.723 3-bit ADPCM */
|
||||
static final int AU_ADPCM_G723_5 = 26; /* CCITT g.723 5-bit ADPCM */
|
||||
static final int AU_ALAW_8 = 27; /* 8-bit ISDN A-law */
|
||||
|
||||
static final int AU_HEADERSIZE = 24;
|
||||
|
||||
private int auType;
|
||||
|
||||
AuFileFormat( AudioFileFormat aff ) {
|
||||
|
||||
this( aff.getType(), aff.getByteLength(), aff.getFormat(), aff.getFrameLength() );
|
||||
}
|
||||
|
||||
AuFileFormat(AudioFileFormat.Type type, int lengthInBytes, AudioFormat format, int lengthInFrames) {
|
||||
|
||||
super(type,lengthInBytes,format,lengthInFrames);
|
||||
|
||||
AudioFormat.Encoding encoding = format.getEncoding();
|
||||
|
||||
auType = -1;
|
||||
|
||||
if( AudioFormat.Encoding.ALAW.equals(encoding) ) {
|
||||
if( format.getSampleSizeInBits()==8 ) {
|
||||
auType = AU_ALAW_8;
|
||||
}
|
||||
} else if( AudioFormat.Encoding.ULAW.equals(encoding) ) {
|
||||
if( format.getSampleSizeInBits()==8 ) {
|
||||
auType = AU_ULAW_8;
|
||||
}
|
||||
} else if( AudioFormat.Encoding.PCM_SIGNED.equals(encoding) ) {
|
||||
if( format.getSampleSizeInBits()==8 ) {
|
||||
auType = AU_LINEAR_8;
|
||||
} else if( format.getSampleSizeInBits()==16 ) {
|
||||
auType = AU_LINEAR_16;
|
||||
} else if( format.getSampleSizeInBits()==24 ) {
|
||||
auType = AU_LINEAR_24;
|
||||
} else if( format.getSampleSizeInBits()==32 ) {
|
||||
auType = AU_LINEAR_32;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public int getAuType() {
|
||||
|
||||
return auType;
|
||||
}
|
||||
|
||||
}
|
||||
372
jdkSrc/jdk8/com/sun/media/sound/AuFileReader.java
Normal file
372
jdkSrc/jdk8/com/sun/media/sound/AuFileReader.java
Normal file
@@ -0,0 +1,372 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
|
||||
import javax.sound.sampled.AudioFileFormat;
|
||||
import javax.sound.sampled.AudioFormat;
|
||||
import javax.sound.sampled.AudioInputStream;
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
import javax.sound.sampled.UnsupportedAudioFileException;
|
||||
|
||||
|
||||
/**
|
||||
* AU file reader.
|
||||
*
|
||||
* @author Kara Kytle
|
||||
* @author Jan Borgersen
|
||||
* @author Florian Bomers
|
||||
*/
|
||||
public final class AuFileReader extends SunFileReader {
|
||||
|
||||
// METHODS TO IMPLEMENT AudioFileReader
|
||||
|
||||
/**
|
||||
* Obtains the audio file format of the input stream provided. The stream must
|
||||
* point to valid audio file data. In general, audio file providers may
|
||||
* need to read some data from the stream before determining whether they
|
||||
* support it. These parsers must
|
||||
* be able to mark the stream, read enough data to determine whether they
|
||||
* support the stream, and, if not, reset the stream's read pointer to its original
|
||||
* position. If the input stream does not support this, this method may fail
|
||||
* with an IOException.
|
||||
* @param stream the input stream from which file format information should be
|
||||
* extracted
|
||||
* @return an <code>AudioFileFormat</code> object describing the audio file format
|
||||
* @throws UnsupportedAudioFileException if the stream does not point to valid audio
|
||||
* file data recognized by the system
|
||||
* @throws IOException if an I/O exception occurs
|
||||
* @see InputStream#markSupported
|
||||
* @see InputStream#mark
|
||||
*/
|
||||
public AudioFileFormat getAudioFileFormat(InputStream stream) throws UnsupportedAudioFileException, IOException {
|
||||
|
||||
AudioFormat format = null;
|
||||
AuFileFormat fileFormat = null;
|
||||
int maxReadLength = 28;
|
||||
boolean bigendian = false;
|
||||
int magic = -1;
|
||||
int headerSize = -1;
|
||||
int dataSize = -1;
|
||||
int encoding_local = -1;
|
||||
int sampleRate = -1;
|
||||
int frameRate = -1;
|
||||
int frameSize = -1;
|
||||
int channels = -1;
|
||||
final int sampleSizeInBits;
|
||||
int length = 0;
|
||||
int nread = 0;
|
||||
AudioFormat.Encoding encoding = null;
|
||||
|
||||
DataInputStream dis = new DataInputStream( stream );
|
||||
|
||||
dis.mark(maxReadLength);
|
||||
|
||||
magic = dis.readInt();
|
||||
|
||||
if (! (magic == AuFileFormat.AU_SUN_MAGIC) || (magic == AuFileFormat.AU_DEC_MAGIC) ||
|
||||
(magic == AuFileFormat.AU_SUN_INV_MAGIC) || (magic == AuFileFormat.AU_DEC_INV_MAGIC) ) {
|
||||
|
||||
// not AU, reset the stream, place into exception, throw exception
|
||||
dis.reset();
|
||||
throw new UnsupportedAudioFileException("not an AU file");
|
||||
}
|
||||
|
||||
if ((magic == AuFileFormat.AU_SUN_MAGIC) || (magic == AuFileFormat.AU_DEC_MAGIC)) {
|
||||
bigendian = true; // otherwise little-endian
|
||||
}
|
||||
|
||||
headerSize = (bigendian==true ? dis.readInt() : rllong(dis) ); nread += 4;
|
||||
dataSize = (bigendian==true ? dis.readInt() : rllong(dis) ); nread += 4;
|
||||
encoding_local = (bigendian==true ? dis.readInt() : rllong(dis) ); nread += 4;
|
||||
sampleRate = (bigendian==true ? dis.readInt() : rllong(dis) ); nread += 4;
|
||||
channels = (bigendian==true ? dis.readInt() : rllong(dis) ); nread += 4;
|
||||
if (channels <= 0) {
|
||||
dis.reset();
|
||||
throw new UnsupportedAudioFileException("Invalid number of channels");
|
||||
}
|
||||
|
||||
frameRate = sampleRate;
|
||||
|
||||
switch (encoding_local) {
|
||||
case AuFileFormat.AU_ULAW_8:
|
||||
encoding = AudioFormat.Encoding.ULAW;
|
||||
sampleSizeInBits = 8;
|
||||
break;
|
||||
case AuFileFormat.AU_ALAW_8:
|
||||
encoding = AudioFormat.Encoding.ALAW;
|
||||
sampleSizeInBits = 8;
|
||||
break;
|
||||
case AuFileFormat.AU_LINEAR_8:
|
||||
// $$jb: 04.29.99: 8bit linear is *signed*, not *unsigned*
|
||||
encoding = AudioFormat.Encoding.PCM_SIGNED;
|
||||
sampleSizeInBits = 8;
|
||||
break;
|
||||
case AuFileFormat.AU_LINEAR_16:
|
||||
encoding = AudioFormat.Encoding.PCM_SIGNED;
|
||||
sampleSizeInBits = 16;
|
||||
break;
|
||||
case AuFileFormat.AU_LINEAR_24:
|
||||
encoding = AudioFormat.Encoding.PCM_SIGNED;
|
||||
|
||||
sampleSizeInBits = 24;
|
||||
break;
|
||||
case AuFileFormat.AU_LINEAR_32:
|
||||
encoding = AudioFormat.Encoding.PCM_SIGNED;
|
||||
|
||||
sampleSizeInBits = 32;
|
||||
break;
|
||||
// $jb: 03.19.99: we don't support these ...
|
||||
/* case AuFileFormat.AU_FLOAT:
|
||||
encoding = new AudioFormat.FLOAT;
|
||||
sampleSizeInBits = 32;
|
||||
break;
|
||||
case AuFileFormat.AU_DOUBLE:
|
||||
encoding = new AudioFormat.DOUBLE;
|
||||
sampleSizeInBits = 8;
|
||||
break;
|
||||
case AuFileFormat.AU_ADPCM_G721:
|
||||
encoding = new AudioFormat.G721_ADPCM;
|
||||
sampleSizeInBits = 16;
|
||||
break;
|
||||
case AuFileFormat.AU_ADPCM_G723_3:
|
||||
encoding = new AudioFormat.G723_3;
|
||||
sampleSize = 24;
|
||||
SamplePerUnit = 8;
|
||||
break;
|
||||
case AuFileFormat.AU_ADPCM_G723_5:
|
||||
encoding = new AudioFormat.G723_5;
|
||||
sampleSize = 40;
|
||||
SamplePerUnit = 8;
|
||||
break;
|
||||
*/
|
||||
default:
|
||||
// unsupported filetype, throw exception
|
||||
dis.reset();
|
||||
throw new UnsupportedAudioFileException("not a valid AU file");
|
||||
}
|
||||
|
||||
frameSize = calculatePCMFrameSize(sampleSizeInBits, channels);
|
||||
//$$fb 2002-11-02: fix for 4629669: AU file reader: problems with empty files
|
||||
if( dataSize < 0 ) {
|
||||
length = AudioSystem.NOT_SPECIFIED;
|
||||
} else {
|
||||
//$$fb 2003-10-20: fix for 4940459: AudioInputStream.getFrameLength() returns 0 instead of NOT_SPECIFIED
|
||||
length = dataSize / frameSize;
|
||||
}
|
||||
|
||||
format = new AudioFormat( encoding, (float)sampleRate, sampleSizeInBits,
|
||||
channels, frameSize, (float)frameRate, bigendian);
|
||||
|
||||
fileFormat = new AuFileFormat( AudioFileFormat.Type.AU, dataSize+headerSize,
|
||||
format, length);
|
||||
|
||||
dis.reset(); // Throws IOException
|
||||
return fileFormat;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtains the audio file format of the URL provided. The URL must
|
||||
* point to valid audio file data.
|
||||
* @param url the URL from which file format information should be
|
||||
* extracted
|
||||
* @return an <code>AudioFileFormat</code> object describing the audio file format
|
||||
* @throws UnsupportedAudioFileException if the URL does not point to valid audio
|
||||
* file data recognized by the system
|
||||
* @throws IOException if an I/O exception occurs
|
||||
*/
|
||||
public AudioFileFormat getAudioFileFormat(URL url) throws UnsupportedAudioFileException, IOException {
|
||||
|
||||
InputStream urlStream = null;
|
||||
BufferedInputStream bis = null;
|
||||
AudioFileFormat fileFormat = null;
|
||||
AudioFormat format = null;
|
||||
|
||||
urlStream = url.openStream(); // throws IOException
|
||||
|
||||
try {
|
||||
bis = new BufferedInputStream( urlStream, bisBufferSize );
|
||||
|
||||
fileFormat = getAudioFileFormat( bis ); // throws UnsupportedAudioFileException
|
||||
} finally {
|
||||
urlStream.close();
|
||||
}
|
||||
|
||||
return fileFormat;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtains the audio file format of the File provided. The File must
|
||||
* point to valid audio file data.
|
||||
* @param file the File from which file format information should be
|
||||
* extracted
|
||||
* @return an <code>AudioFileFormat</code> object describing the audio file format
|
||||
* @throws UnsupportedAudioFileException if the File does not point to valid audio
|
||||
* file data recognized by the system
|
||||
* @throws IOException if an I/O exception occurs
|
||||
*/
|
||||
public AudioFileFormat getAudioFileFormat(File file) throws UnsupportedAudioFileException, IOException {
|
||||
|
||||
FileInputStream fis = null;
|
||||
BufferedInputStream bis = null;
|
||||
AudioFileFormat fileFormat = null;
|
||||
AudioFormat format = null;
|
||||
|
||||
fis = new FileInputStream( file ); // throws IOException
|
||||
// part of fix for 4325421
|
||||
try {
|
||||
bis = new BufferedInputStream( fis, bisBufferSize );
|
||||
fileFormat = getAudioFileFormat( bis ); // throws UnsupportedAudioFileException
|
||||
} finally {
|
||||
fis.close();
|
||||
}
|
||||
|
||||
return fileFormat;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtains an audio stream from the input stream provided. The stream must
|
||||
* point to valid audio file data. In general, audio file providers may
|
||||
* need to read some data from the stream before determining whether they
|
||||
* support it. These parsers must
|
||||
* be able to mark the stream, read enough data to determine whether they
|
||||
* support the stream, and, if not, reset the stream's read pointer to its original
|
||||
* position. If the input stream does not support this, this method may fail
|
||||
* with an IOException.
|
||||
* @param stream the input stream from which the <code>AudioInputStream</code> should be
|
||||
* constructed
|
||||
* @return an <code>AudioInputStream</code> object based on the audio file data contained
|
||||
* in the input stream.
|
||||
* @throws UnsupportedAudioFileException if the stream does not point to valid audio
|
||||
* file data recognized by the system
|
||||
* @throws IOException if an I/O exception occurs
|
||||
* @see InputStream#markSupported
|
||||
* @see InputStream#mark
|
||||
*/
|
||||
public AudioInputStream getAudioInputStream(InputStream stream) throws UnsupportedAudioFileException, IOException {
|
||||
|
||||
DataInputStream dis = null;
|
||||
int headerSize;
|
||||
AudioFileFormat fileFormat = null;
|
||||
AudioFormat format = null;
|
||||
|
||||
|
||||
fileFormat = getAudioFileFormat( stream ); // throws UnsupportedAudioFileException, IOException
|
||||
|
||||
// if we passed this call, we have an AU file.
|
||||
|
||||
format = fileFormat.getFormat();
|
||||
|
||||
dis = new DataInputStream(stream);
|
||||
|
||||
// now seek past the header
|
||||
|
||||
dis.readInt(); // magic
|
||||
headerSize = (format.isBigEndian()==true ? dis.readInt() : rllong(dis) );
|
||||
dis.skipBytes( headerSize - 8 );
|
||||
|
||||
|
||||
// we've got everything, and the stream should be at the
|
||||
// beginning of the data chunk, so return an AudioInputStream.
|
||||
|
||||
return new AudioInputStream(dis, format, fileFormat.getFrameLength());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtains an audio stream from the URL provided. The URL must
|
||||
* point to valid audio file data.
|
||||
* @param url the URL for which the <code>AudioInputStream</code> should be
|
||||
* constructed
|
||||
* @return an <code>AudioInputStream</code> object based on the audio file data pointed
|
||||
* to by the URL
|
||||
* @throws UnsupportedAudioFileException if the URL does not point to valid audio
|
||||
* file data recognized by the system
|
||||
* @throws IOException if an I/O exception occurs
|
||||
*/
|
||||
public AudioInputStream getAudioInputStream(URL url) throws UnsupportedAudioFileException, IOException {
|
||||
|
||||
InputStream urlStream = null;
|
||||
BufferedInputStream bis = null;
|
||||
AudioFileFormat fileFormat = null;
|
||||
|
||||
urlStream = url.openStream(); // throws IOException
|
||||
AudioInputStream result = null;
|
||||
try {
|
||||
bis = new BufferedInputStream( urlStream, bisBufferSize );
|
||||
result = getAudioInputStream( (InputStream)bis );
|
||||
} finally {
|
||||
if (result == null) {
|
||||
urlStream.close();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtains an audio stream from the File provided. The File must
|
||||
* point to valid audio file data.
|
||||
* @param file the File for which the <code>AudioInputStream</code> should be
|
||||
* constructed
|
||||
* @return an <code>AudioInputStream</code> object based on the audio file data pointed
|
||||
* to by the File
|
||||
* @throws UnsupportedAudioFileException if the File does not point to valid audio
|
||||
* file data recognized by the system
|
||||
* @throws IOException if an I/O exception occurs
|
||||
*/
|
||||
public AudioInputStream getAudioInputStream(File file) throws UnsupportedAudioFileException, IOException {
|
||||
|
||||
FileInputStream fis = null;
|
||||
BufferedInputStream bis = null;
|
||||
AudioFileFormat fileFormat = null;
|
||||
|
||||
fis = new FileInputStream( file ); // throws IOException
|
||||
AudioInputStream result = null;
|
||||
// part of fix for 4325421
|
||||
try {
|
||||
bis = new BufferedInputStream( fis, bisBufferSize );
|
||||
result = getAudioInputStream( (InputStream)bis );
|
||||
} finally {
|
||||
if (result == null) {
|
||||
fis.close();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
330
jdkSrc/jdk8/com/sun/media/sound/AuFileWriter.java
Normal file
330
jdkSrc/jdk8/com/sun/media/sound/AuFileWriter.java
Normal file
@@ -0,0 +1,330 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.io.SequenceInputStream;
|
||||
|
||||
import javax.sound.sampled.AudioFileFormat;
|
||||
import javax.sound.sampled.AudioInputStream;
|
||||
import javax.sound.sampled.AudioFormat;
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
|
||||
|
||||
/**
|
||||
* AU file writer.
|
||||
*
|
||||
* @author Jan Borgersen
|
||||
*/
|
||||
public final class AuFileWriter extends SunFileWriter {
|
||||
|
||||
//$$fb value for length field if length is not known
|
||||
public final static int UNKNOWN_SIZE=-1;
|
||||
|
||||
/**
|
||||
* Constructs a new AuFileWriter object.
|
||||
*/
|
||||
public AuFileWriter() {
|
||||
super(new AudioFileFormat.Type[]{AudioFileFormat.Type.AU});
|
||||
}
|
||||
|
||||
public AudioFileFormat.Type[] getAudioFileTypes(AudioInputStream stream) {
|
||||
|
||||
AudioFileFormat.Type[] filetypes = new AudioFileFormat.Type[types.length];
|
||||
System.arraycopy(types, 0, filetypes, 0, types.length);
|
||||
|
||||
// make sure we can write this stream
|
||||
AudioFormat format = stream.getFormat();
|
||||
AudioFormat.Encoding encoding = format.getEncoding();
|
||||
|
||||
if( (AudioFormat.Encoding.ALAW.equals(encoding)) ||
|
||||
(AudioFormat.Encoding.ULAW.equals(encoding)) ||
|
||||
(AudioFormat.Encoding.PCM_SIGNED.equals(encoding)) ||
|
||||
(AudioFormat.Encoding.PCM_UNSIGNED.equals(encoding)) ) {
|
||||
|
||||
return filetypes;
|
||||
}
|
||||
|
||||
return new AudioFileFormat.Type[0];
|
||||
}
|
||||
|
||||
|
||||
public int write(AudioInputStream stream, AudioFileFormat.Type fileType, OutputStream out) throws IOException {
|
||||
|
||||
// we must know the total data length to calculate the file length
|
||||
//$$fb 2001-07-13: fix for bug 4351296: do not throw an exception
|
||||
//if( stream.getFrameLength() == AudioSystem.NOT_SPECIFIED ) {
|
||||
// throw new IOException("stream length not specified");
|
||||
//}
|
||||
|
||||
// throws IllegalArgumentException if not supported
|
||||
AuFileFormat auFileFormat = (AuFileFormat)getAudioFileFormat(fileType, stream);
|
||||
|
||||
int bytesWritten = writeAuFile(stream, auFileFormat, out);
|
||||
return bytesWritten;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public int write(AudioInputStream stream, AudioFileFormat.Type fileType, File out) throws IOException {
|
||||
|
||||
// throws IllegalArgumentException if not supported
|
||||
AuFileFormat auFileFormat = (AuFileFormat)getAudioFileFormat(fileType, stream);
|
||||
|
||||
// first write the file without worrying about length fields
|
||||
FileOutputStream fos = new FileOutputStream( out ); // throws IOException
|
||||
BufferedOutputStream bos = new BufferedOutputStream( fos, bisBufferSize );
|
||||
int bytesWritten = writeAuFile(stream, auFileFormat, bos );
|
||||
bos.close();
|
||||
|
||||
// now, if length fields were not specified, calculate them,
|
||||
// open as a random access file, write the appropriate fields,
|
||||
// close again....
|
||||
if( auFileFormat.getByteLength()== AudioSystem.NOT_SPECIFIED ) {
|
||||
|
||||
// $$kk: 10.22.99: jan: please either implement this or throw an exception!
|
||||
// $$fb: 2001-07-13: done. Fixes Bug 4479981
|
||||
RandomAccessFile raf=new RandomAccessFile(out, "rw");
|
||||
if (raf.length()<=0x7FFFFFFFl) {
|
||||
// skip AU magic and data offset field
|
||||
raf.skipBytes(8);
|
||||
raf.writeInt(bytesWritten-AuFileFormat.AU_HEADERSIZE);
|
||||
// that's all
|
||||
}
|
||||
raf.close();
|
||||
}
|
||||
|
||||
return bytesWritten;
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the AudioFileFormat describing the file that will be written from this AudioInputStream.
|
||||
* Throws IllegalArgumentException if not supported.
|
||||
*/
|
||||
private AudioFileFormat getAudioFileFormat(AudioFileFormat.Type type, AudioInputStream stream) {
|
||||
|
||||
AudioFormat format = null;
|
||||
AuFileFormat fileFormat = null;
|
||||
AudioFormat.Encoding encoding = AudioFormat.Encoding.PCM_SIGNED;
|
||||
|
||||
AudioFormat streamFormat = stream.getFormat();
|
||||
AudioFormat.Encoding streamEncoding = streamFormat.getEncoding();
|
||||
|
||||
|
||||
float sampleRate;
|
||||
int sampleSizeInBits;
|
||||
int channels;
|
||||
int frameSize;
|
||||
float frameRate;
|
||||
int fileSize;
|
||||
|
||||
if( !types[0].equals(type) ) {
|
||||
throw new IllegalArgumentException("File type " + type + " not supported.");
|
||||
}
|
||||
|
||||
if( (AudioFormat.Encoding.ALAW.equals(streamEncoding)) ||
|
||||
(AudioFormat.Encoding.ULAW.equals(streamEncoding)) ) {
|
||||
|
||||
encoding = streamEncoding;
|
||||
sampleSizeInBits = streamFormat.getSampleSizeInBits();
|
||||
|
||||
} else if ( streamFormat.getSampleSizeInBits()==8 ) {
|
||||
|
||||
encoding = AudioFormat.Encoding.PCM_SIGNED;
|
||||
sampleSizeInBits=8;
|
||||
|
||||
} else {
|
||||
|
||||
encoding = AudioFormat.Encoding.PCM_SIGNED;
|
||||
sampleSizeInBits=streamFormat.getSampleSizeInBits();
|
||||
}
|
||||
|
||||
|
||||
format = new AudioFormat( encoding,
|
||||
streamFormat.getSampleRate(),
|
||||
sampleSizeInBits,
|
||||
streamFormat.getChannels(),
|
||||
streamFormat.getFrameSize(),
|
||||
streamFormat.getFrameRate(),
|
||||
true); // AU is always big endian
|
||||
|
||||
|
||||
if( stream.getFrameLength()!=AudioSystem.NOT_SPECIFIED ) {
|
||||
fileSize = (int)stream.getFrameLength()*streamFormat.getFrameSize() + AuFileFormat.AU_HEADERSIZE;
|
||||
} else {
|
||||
fileSize = AudioSystem.NOT_SPECIFIED;
|
||||
}
|
||||
|
||||
fileFormat = new AuFileFormat( AudioFileFormat.Type.AU,
|
||||
fileSize,
|
||||
format,
|
||||
(int)stream.getFrameLength() );
|
||||
|
||||
return fileFormat;
|
||||
}
|
||||
|
||||
|
||||
private InputStream getFileStream(AuFileFormat auFileFormat, InputStream audioStream) throws IOException {
|
||||
|
||||
// private method ... assumes auFileFormat is a supported file type
|
||||
|
||||
AudioFormat format = auFileFormat.getFormat();
|
||||
|
||||
int magic = AuFileFormat.AU_SUN_MAGIC;
|
||||
int headerSize = AuFileFormat.AU_HEADERSIZE;
|
||||
long dataSize = auFileFormat.getFrameLength();
|
||||
//$$fb fix for Bug 4351296
|
||||
//int dataSizeInBytes = dataSize * format.getFrameSize();
|
||||
long dataSizeInBytes = (dataSize==AudioSystem.NOT_SPECIFIED)?UNKNOWN_SIZE:dataSize * format.getFrameSize();
|
||||
if (dataSizeInBytes>0x7FFFFFFFl) {
|
||||
dataSizeInBytes=UNKNOWN_SIZE;
|
||||
}
|
||||
int encoding_local = auFileFormat.getAuType();
|
||||
int sampleRate = (int)format.getSampleRate();
|
||||
int channels = format.getChannels();
|
||||
//$$fb below is the fix for 4297100.
|
||||
//boolean bigendian = format.isBigEndian();
|
||||
boolean bigendian = true; // force bigendian
|
||||
|
||||
byte header[] = null;
|
||||
ByteArrayInputStream headerStream = null;
|
||||
ByteArrayOutputStream baos = null;
|
||||
DataOutputStream dos = null;
|
||||
SequenceInputStream auStream = null;
|
||||
|
||||
AudioFormat audioStreamFormat = null;
|
||||
AudioFormat.Encoding encoding = null;
|
||||
InputStream codedAudioStream = audioStream;
|
||||
|
||||
// if we need to do any format conversion, do it here.
|
||||
|
||||
codedAudioStream = audioStream;
|
||||
|
||||
if( audioStream instanceof AudioInputStream ) {
|
||||
|
||||
|
||||
audioStreamFormat = ((AudioInputStream)audioStream).getFormat();
|
||||
encoding = audioStreamFormat.getEncoding();
|
||||
|
||||
//$$ fb 2001-07-13: Bug 4391108
|
||||
if( (AudioFormat.Encoding.PCM_UNSIGNED.equals(encoding)) ||
|
||||
(AudioFormat.Encoding.PCM_SIGNED.equals(encoding)
|
||||
&& bigendian != audioStreamFormat.isBigEndian()) ) {
|
||||
|
||||
// plug in the transcoder to convert to PCM_SIGNED, bigendian
|
||||
// NOTE: little endian AU is not common, so we're always converting
|
||||
// to big endian unless the passed in audioFileFormat is little.
|
||||
// $$fb this NOTE is superseded. We always write big endian au files, this is by far the standard.
|
||||
codedAudioStream = AudioSystem.getAudioInputStream( new AudioFormat (
|
||||
AudioFormat.Encoding.PCM_SIGNED,
|
||||
audioStreamFormat.getSampleRate(),
|
||||
audioStreamFormat.getSampleSizeInBits(),
|
||||
audioStreamFormat.getChannels(),
|
||||
audioStreamFormat.getFrameSize(),
|
||||
audioStreamFormat.getFrameRate(),
|
||||
bigendian),
|
||||
(AudioInputStream)audioStream );
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
baos = new ByteArrayOutputStream();
|
||||
dos = new DataOutputStream(baos);
|
||||
|
||||
|
||||
if (bigendian) {
|
||||
dos.writeInt(AuFileFormat.AU_SUN_MAGIC);
|
||||
dos.writeInt(headerSize);
|
||||
dos.writeInt((int)dataSizeInBytes);
|
||||
dos.writeInt(encoding_local);
|
||||
dos.writeInt(sampleRate);
|
||||
dos.writeInt(channels);
|
||||
} else {
|
||||
dos.writeInt(AuFileFormat.AU_SUN_INV_MAGIC);
|
||||
dos.writeInt(big2little(headerSize));
|
||||
dos.writeInt(big2little((int)dataSizeInBytes));
|
||||
dos.writeInt(big2little(encoding_local));
|
||||
dos.writeInt(big2little(sampleRate));
|
||||
dos.writeInt(big2little(channels));
|
||||
}
|
||||
|
||||
// Now create a new InputStream from headerStream and the InputStream
|
||||
// in audioStream
|
||||
|
||||
dos.close();
|
||||
header = baos.toByteArray();
|
||||
headerStream = new ByteArrayInputStream( header );
|
||||
auStream = new SequenceInputStream(headerStream,
|
||||
new NoCloseInputStream(codedAudioStream));
|
||||
|
||||
return auStream;
|
||||
}
|
||||
|
||||
private int writeAuFile(InputStream in, AuFileFormat auFileFormat, OutputStream out) throws IOException {
|
||||
|
||||
int bytesRead = 0;
|
||||
int bytesWritten = 0;
|
||||
InputStream fileStream = getFileStream(auFileFormat, in);
|
||||
byte buffer[] = new byte[bisBufferSize];
|
||||
int maxLength = auFileFormat.getByteLength();
|
||||
|
||||
while( (bytesRead = fileStream.read( buffer )) >= 0 ) {
|
||||
if (maxLength>0) {
|
||||
if( bytesRead < maxLength ) {
|
||||
out.write( buffer, 0, (int)bytesRead );
|
||||
bytesWritten += bytesRead;
|
||||
maxLength -= bytesRead;
|
||||
} else {
|
||||
out.write( buffer, 0, (int)maxLength );
|
||||
bytesWritten += maxLength;
|
||||
maxLength = 0;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
out.write( buffer, 0, (int)bytesRead );
|
||||
bytesWritten += bytesRead;
|
||||
}
|
||||
}
|
||||
|
||||
return bytesWritten;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
144
jdkSrc/jdk8/com/sun/media/sound/AudioFileSoundbankReader.java
Normal file
144
jdkSrc/jdk8/com/sun/media/sound/AudioFileSoundbankReader.java
Normal file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
|
||||
import javax.sound.midi.InvalidMidiDataException;
|
||||
import javax.sound.midi.Soundbank;
|
||||
import javax.sound.midi.spi.SoundbankReader;
|
||||
import javax.sound.sampled.AudioInputStream;
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
import javax.sound.sampled.UnsupportedAudioFileException;
|
||||
|
||||
/**
|
||||
* Soundbank reader that uses audio files as soundbanks.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public final class AudioFileSoundbankReader extends SoundbankReader {
|
||||
|
||||
public Soundbank getSoundbank(URL url)
|
||||
throws InvalidMidiDataException, IOException {
|
||||
try {
|
||||
AudioInputStream ais = AudioSystem.getAudioInputStream(url);
|
||||
Soundbank sbk = getSoundbank(ais);
|
||||
ais.close();
|
||||
return sbk;
|
||||
} catch (UnsupportedAudioFileException e) {
|
||||
return null;
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Soundbank getSoundbank(InputStream stream)
|
||||
throws InvalidMidiDataException, IOException {
|
||||
stream.mark(512);
|
||||
try {
|
||||
AudioInputStream ais = AudioSystem.getAudioInputStream(stream);
|
||||
Soundbank sbk = getSoundbank(ais);
|
||||
if (sbk != null)
|
||||
return sbk;
|
||||
} catch (UnsupportedAudioFileException e) {
|
||||
} catch (IOException e) {
|
||||
}
|
||||
stream.reset();
|
||||
return null;
|
||||
}
|
||||
|
||||
public Soundbank getSoundbank(AudioInputStream ais)
|
||||
throws InvalidMidiDataException, IOException {
|
||||
int MEGABYTE = 1048576;
|
||||
int DEFAULT_BUFFER_SIZE = 65536;
|
||||
int MAX_FRAME_SIZE = 1024;
|
||||
try {
|
||||
byte[] buffer;
|
||||
int frameSize = ais.getFormat().getFrameSize();
|
||||
if (frameSize <= 0 || frameSize > MAX_FRAME_SIZE) {
|
||||
throw new InvalidMidiDataException("Formats with frame size "
|
||||
+ frameSize + " are not supported");
|
||||
}
|
||||
|
||||
long totalSize = ais.getFrameLength() * frameSize;
|
||||
if (totalSize >= Integer.MAX_VALUE - 2) {
|
||||
throw new InvalidMidiDataException(
|
||||
"Can not allocate enough memory to read audio data.");
|
||||
}
|
||||
|
||||
if (ais.getFrameLength() == -1 || totalSize > MEGABYTE) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
byte[] buff = new byte[DEFAULT_BUFFER_SIZE - (DEFAULT_BUFFER_SIZE % frameSize)];
|
||||
int ret;
|
||||
while ((ret = ais.read(buff)) != -1) {
|
||||
baos.write(buff, 0, ret);
|
||||
}
|
||||
ais.close();
|
||||
buffer = baos.toByteArray();
|
||||
} else {
|
||||
buffer = new byte[(int) totalSize];
|
||||
new DataInputStream(ais).readFully(buffer);
|
||||
}
|
||||
ModelByteBufferWavetable osc = new ModelByteBufferWavetable(
|
||||
new ModelByteBuffer(buffer), ais.getFormat(), -4800);
|
||||
ModelPerformer performer = new ModelPerformer();
|
||||
performer.getOscillators().add(osc);
|
||||
|
||||
SimpleSoundbank sbk = new SimpleSoundbank();
|
||||
SimpleInstrument ins = new SimpleInstrument();
|
||||
ins.add(performer);
|
||||
sbk.addInstrument(ins);
|
||||
return sbk;
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Soundbank getSoundbank(File file)
|
||||
throws InvalidMidiDataException, IOException {
|
||||
try {
|
||||
AudioInputStream ais = AudioSystem.getAudioInputStream(file);
|
||||
ais.close();
|
||||
ModelByteBufferWavetable osc = new ModelByteBufferWavetable(
|
||||
new ModelByteBuffer(file, 0, file.length()), -4800);
|
||||
ModelPerformer performer = new ModelPerformer();
|
||||
performer.getOscillators().add(osc);
|
||||
SimpleSoundbank sbk = new SimpleSoundbank();
|
||||
SimpleInstrument ins = new SimpleInstrument();
|
||||
ins.add(performer);
|
||||
sbk.addInstrument(ins);
|
||||
return sbk;
|
||||
} catch (UnsupportedAudioFileException e1) {
|
||||
return null;
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
1057
jdkSrc/jdk8/com/sun/media/sound/AudioFloatConverter.java
Normal file
1057
jdkSrc/jdk8/com/sun/media/sound/AudioFloatConverter.java
Normal file
File diff suppressed because it is too large
Load Diff
617
jdkSrc/jdk8/com/sun/media/sound/AudioFloatFormatConverter.java
Normal file
617
jdkSrc/jdk8/com/sun/media/sound/AudioFloatFormatConverter.java
Normal file
@@ -0,0 +1,617 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.sound.sampled.AudioFormat;
|
||||
import javax.sound.sampled.AudioInputStream;
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
import javax.sound.sampled.AudioFormat.Encoding;
|
||||
import javax.sound.sampled.spi.FormatConversionProvider;
|
||||
|
||||
/**
|
||||
* This class is used to convert between 8,16,24,32 bit signed/unsigned
|
||||
* big/litle endian fixed/floating stereo/mono/multi-channel audio streams and
|
||||
* perform sample-rate conversion if needed.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public final class AudioFloatFormatConverter extends FormatConversionProvider {
|
||||
|
||||
private static class AudioFloatFormatConverterInputStream extends
|
||||
InputStream {
|
||||
private final AudioFloatConverter converter;
|
||||
|
||||
private final AudioFloatInputStream stream;
|
||||
|
||||
private float[] readfloatbuffer;
|
||||
|
||||
private final int fsize;
|
||||
|
||||
AudioFloatFormatConverterInputStream(AudioFormat targetFormat,
|
||||
AudioFloatInputStream stream) {
|
||||
this.stream = stream;
|
||||
converter = AudioFloatConverter.getConverter(targetFormat);
|
||||
fsize = ((targetFormat.getSampleSizeInBits() + 7) / 8);
|
||||
}
|
||||
|
||||
public int read() throws IOException {
|
||||
byte[] b = new byte[1];
|
||||
int ret = read(b);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return b[0] & 0xFF;
|
||||
}
|
||||
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
|
||||
int flen = len / fsize;
|
||||
if (readfloatbuffer == null || readfloatbuffer.length < flen)
|
||||
readfloatbuffer = new float[flen];
|
||||
int ret = stream.read(readfloatbuffer, 0, flen);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
converter.toByteArray(readfloatbuffer, 0, ret, b, off);
|
||||
return ret * fsize;
|
||||
}
|
||||
|
||||
public int available() throws IOException {
|
||||
int ret = stream.available();
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return ret * fsize;
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
stream.close();
|
||||
}
|
||||
|
||||
public synchronized void mark(int readlimit) {
|
||||
stream.mark(readlimit * fsize);
|
||||
}
|
||||
|
||||
public boolean markSupported() {
|
||||
return stream.markSupported();
|
||||
}
|
||||
|
||||
public synchronized void reset() throws IOException {
|
||||
stream.reset();
|
||||
}
|
||||
|
||||
public long skip(long n) throws IOException {
|
||||
long ret = stream.skip(n / fsize);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return ret * fsize;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class AudioFloatInputStreamChannelMixer extends
|
||||
AudioFloatInputStream {
|
||||
|
||||
private final int targetChannels;
|
||||
|
||||
private final int sourceChannels;
|
||||
|
||||
private final AudioFloatInputStream ais;
|
||||
|
||||
private final AudioFormat targetFormat;
|
||||
|
||||
private float[] conversion_buffer;
|
||||
|
||||
AudioFloatInputStreamChannelMixer(AudioFloatInputStream ais,
|
||||
int targetChannels) {
|
||||
this.sourceChannels = ais.getFormat().getChannels();
|
||||
this.targetChannels = targetChannels;
|
||||
this.ais = ais;
|
||||
AudioFormat format = ais.getFormat();
|
||||
targetFormat = new AudioFormat(format.getEncoding(), format
|
||||
.getSampleRate(), format.getSampleSizeInBits(),
|
||||
targetChannels, (format.getFrameSize() / sourceChannels)
|
||||
* targetChannels, format.getFrameRate(), format
|
||||
.isBigEndian());
|
||||
}
|
||||
|
||||
public int available() throws IOException {
|
||||
return (ais.available() / sourceChannels) * targetChannels;
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
ais.close();
|
||||
}
|
||||
|
||||
public AudioFormat getFormat() {
|
||||
return targetFormat;
|
||||
}
|
||||
|
||||
public long getFrameLength() {
|
||||
return ais.getFrameLength();
|
||||
}
|
||||
|
||||
public void mark(int readlimit) {
|
||||
ais.mark((readlimit / targetChannels) * sourceChannels);
|
||||
}
|
||||
|
||||
public boolean markSupported() {
|
||||
return ais.markSupported();
|
||||
}
|
||||
|
||||
public int read(float[] b, int off, int len) throws IOException {
|
||||
int len2 = (len / targetChannels) * sourceChannels;
|
||||
if (conversion_buffer == null || conversion_buffer.length < len2)
|
||||
conversion_buffer = new float[len2];
|
||||
int ret = ais.read(conversion_buffer, 0, len2);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (sourceChannels == 1) {
|
||||
int cs = targetChannels;
|
||||
for (int c = 0; c < targetChannels; c++) {
|
||||
for (int i = 0, ix = off + c; i < len2; i++, ix += cs) {
|
||||
b[ix] = conversion_buffer[i];
|
||||
}
|
||||
}
|
||||
} else if (targetChannels == 1) {
|
||||
int cs = sourceChannels;
|
||||
for (int i = 0, ix = off; i < len2; i += cs, ix++) {
|
||||
b[ix] = conversion_buffer[i];
|
||||
}
|
||||
for (int c = 1; c < sourceChannels; c++) {
|
||||
for (int i = c, ix = off; i < len2; i += cs, ix++) {
|
||||
b[ix] += conversion_buffer[i];
|
||||
}
|
||||
}
|
||||
float vol = 1f / ((float) sourceChannels);
|
||||
for (int i = 0, ix = off; i < len2; i += cs, ix++) {
|
||||
b[ix] *= vol;
|
||||
}
|
||||
} else {
|
||||
int minChannels = Math.min(sourceChannels, targetChannels);
|
||||
int off_len = off + len;
|
||||
int ct = targetChannels;
|
||||
int cs = sourceChannels;
|
||||
for (int c = 0; c < minChannels; c++) {
|
||||
for (int i = off + c, ix = c; i < off_len; i += ct, ix += cs) {
|
||||
b[i] = conversion_buffer[ix];
|
||||
}
|
||||
}
|
||||
for (int c = minChannels; c < targetChannels; c++) {
|
||||
for (int i = off + c; i < off_len; i += ct) {
|
||||
b[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (ret / sourceChannels) * targetChannels;
|
||||
}
|
||||
|
||||
public void reset() throws IOException {
|
||||
ais.reset();
|
||||
}
|
||||
|
||||
public long skip(long len) throws IOException {
|
||||
long ret = ais.skip((len / targetChannels) * sourceChannels);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return (ret / sourceChannels) * targetChannels;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class AudioFloatInputStreamResampler extends
|
||||
AudioFloatInputStream {
|
||||
|
||||
private final AudioFloatInputStream ais;
|
||||
|
||||
private final AudioFormat targetFormat;
|
||||
|
||||
private float[] skipbuffer;
|
||||
|
||||
private SoftAbstractResampler resampler;
|
||||
|
||||
private final float[] pitch = new float[1];
|
||||
|
||||
private final float[] ibuffer2;
|
||||
|
||||
private final float[][] ibuffer;
|
||||
|
||||
private float ibuffer_index = 0;
|
||||
|
||||
private int ibuffer_len = 0;
|
||||
|
||||
private final int nrofchannels;
|
||||
|
||||
private float[][] cbuffer;
|
||||
|
||||
private final int buffer_len = 512;
|
||||
|
||||
private final int pad;
|
||||
|
||||
private final int pad2;
|
||||
|
||||
private final float[] ix = new float[1];
|
||||
|
||||
private final int[] ox = new int[1];
|
||||
|
||||
private float[][] mark_ibuffer = null;
|
||||
|
||||
private float mark_ibuffer_index = 0;
|
||||
|
||||
private int mark_ibuffer_len = 0;
|
||||
|
||||
AudioFloatInputStreamResampler(AudioFloatInputStream ais,
|
||||
AudioFormat format) {
|
||||
this.ais = ais;
|
||||
AudioFormat sourceFormat = ais.getFormat();
|
||||
targetFormat = new AudioFormat(sourceFormat.getEncoding(), format
|
||||
.getSampleRate(), sourceFormat.getSampleSizeInBits(),
|
||||
sourceFormat.getChannels(), sourceFormat.getFrameSize(),
|
||||
format.getSampleRate(), sourceFormat.isBigEndian());
|
||||
nrofchannels = targetFormat.getChannels();
|
||||
Object interpolation = format.getProperty("interpolation");
|
||||
if (interpolation != null && (interpolation instanceof String)) {
|
||||
String resamplerType = (String) interpolation;
|
||||
if (resamplerType.equalsIgnoreCase("point"))
|
||||
this.resampler = new SoftPointResampler();
|
||||
if (resamplerType.equalsIgnoreCase("linear"))
|
||||
this.resampler = new SoftLinearResampler2();
|
||||
if (resamplerType.equalsIgnoreCase("linear1"))
|
||||
this.resampler = new SoftLinearResampler();
|
||||
if (resamplerType.equalsIgnoreCase("linear2"))
|
||||
this.resampler = new SoftLinearResampler2();
|
||||
if (resamplerType.equalsIgnoreCase("cubic"))
|
||||
this.resampler = new SoftCubicResampler();
|
||||
if (resamplerType.equalsIgnoreCase("lanczos"))
|
||||
this.resampler = new SoftLanczosResampler();
|
||||
if (resamplerType.equalsIgnoreCase("sinc"))
|
||||
this.resampler = new SoftSincResampler();
|
||||
}
|
||||
if (resampler == null)
|
||||
resampler = new SoftLinearResampler2(); // new
|
||||
// SoftLinearResampler2();
|
||||
pitch[0] = sourceFormat.getSampleRate() / format.getSampleRate();
|
||||
pad = resampler.getPadding();
|
||||
pad2 = pad * 2;
|
||||
ibuffer = new float[nrofchannels][buffer_len + pad2];
|
||||
ibuffer2 = new float[nrofchannels * buffer_len];
|
||||
ibuffer_index = buffer_len + pad;
|
||||
ibuffer_len = buffer_len;
|
||||
}
|
||||
|
||||
public int available() throws IOException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
ais.close();
|
||||
}
|
||||
|
||||
public AudioFormat getFormat() {
|
||||
return targetFormat;
|
||||
}
|
||||
|
||||
public long getFrameLength() {
|
||||
return AudioSystem.NOT_SPECIFIED; // ais.getFrameLength();
|
||||
}
|
||||
|
||||
public void mark(int readlimit) {
|
||||
ais.mark((int) (readlimit * pitch[0]));
|
||||
mark_ibuffer_index = ibuffer_index;
|
||||
mark_ibuffer_len = ibuffer_len;
|
||||
if (mark_ibuffer == null) {
|
||||
mark_ibuffer = new float[ibuffer.length][ibuffer[0].length];
|
||||
}
|
||||
for (int c = 0; c < ibuffer.length; c++) {
|
||||
float[] from = ibuffer[c];
|
||||
float[] to = mark_ibuffer[c];
|
||||
for (int i = 0; i < to.length; i++) {
|
||||
to[i] = from[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean markSupported() {
|
||||
return ais.markSupported();
|
||||
}
|
||||
|
||||
private void readNextBuffer() throws IOException {
|
||||
|
||||
if (ibuffer_len == -1)
|
||||
return;
|
||||
|
||||
for (int c = 0; c < nrofchannels; c++) {
|
||||
float[] buff = ibuffer[c];
|
||||
int buffer_len_pad = ibuffer_len + pad2;
|
||||
for (int i = ibuffer_len, ix = 0; i < buffer_len_pad; i++, ix++) {
|
||||
buff[ix] = buff[i];
|
||||
}
|
||||
}
|
||||
|
||||
ibuffer_index -= (ibuffer_len);
|
||||
|
||||
ibuffer_len = ais.read(ibuffer2);
|
||||
if (ibuffer_len >= 0) {
|
||||
while (ibuffer_len < ibuffer2.length) {
|
||||
int ret = ais.read(ibuffer2, ibuffer_len, ibuffer2.length
|
||||
- ibuffer_len);
|
||||
if (ret == -1)
|
||||
break;
|
||||
ibuffer_len += ret;
|
||||
}
|
||||
Arrays.fill(ibuffer2, ibuffer_len, ibuffer2.length, 0);
|
||||
ibuffer_len /= nrofchannels;
|
||||
} else {
|
||||
Arrays.fill(ibuffer2, 0, ibuffer2.length, 0);
|
||||
}
|
||||
|
||||
int ibuffer2_len = ibuffer2.length;
|
||||
for (int c = 0; c < nrofchannels; c++) {
|
||||
float[] buff = ibuffer[c];
|
||||
for (int i = c, ix = pad2; i < ibuffer2_len; i += nrofchannels, ix++) {
|
||||
buff[ix] = ibuffer2[i];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public int read(float[] b, int off, int len) throws IOException {
|
||||
|
||||
if (cbuffer == null || cbuffer[0].length < len / nrofchannels) {
|
||||
cbuffer = new float[nrofchannels][len / nrofchannels];
|
||||
}
|
||||
if (ibuffer_len == -1)
|
||||
return -1;
|
||||
if (len < 0)
|
||||
return 0;
|
||||
int offlen = off + len;
|
||||
int remain = len / nrofchannels;
|
||||
int destPos = 0;
|
||||
int in_end = ibuffer_len;
|
||||
while (remain > 0) {
|
||||
if (ibuffer_len >= 0) {
|
||||
if (ibuffer_index >= (ibuffer_len + pad))
|
||||
readNextBuffer();
|
||||
in_end = ibuffer_len + pad;
|
||||
}
|
||||
|
||||
if (ibuffer_len < 0) {
|
||||
in_end = pad2;
|
||||
if (ibuffer_index >= in_end)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ibuffer_index < 0)
|
||||
break;
|
||||
int preDestPos = destPos;
|
||||
for (int c = 0; c < nrofchannels; c++) {
|
||||
ix[0] = ibuffer_index;
|
||||
ox[0] = destPos;
|
||||
float[] buff = ibuffer[c];
|
||||
resampler.interpolate(buff, ix, in_end, pitch, 0,
|
||||
cbuffer[c], ox, len / nrofchannels);
|
||||
}
|
||||
ibuffer_index = ix[0];
|
||||
destPos = ox[0];
|
||||
remain -= destPos - preDestPos;
|
||||
}
|
||||
for (int c = 0; c < nrofchannels; c++) {
|
||||
int ix = 0;
|
||||
float[] buff = cbuffer[c];
|
||||
for (int i = c + off; i < offlen; i += nrofchannels) {
|
||||
b[i] = buff[ix++];
|
||||
}
|
||||
}
|
||||
return len - remain * nrofchannels;
|
||||
}
|
||||
|
||||
public void reset() throws IOException {
|
||||
ais.reset();
|
||||
if (mark_ibuffer == null)
|
||||
return;
|
||||
ibuffer_index = mark_ibuffer_index;
|
||||
ibuffer_len = mark_ibuffer_len;
|
||||
for (int c = 0; c < ibuffer.length; c++) {
|
||||
float[] from = mark_ibuffer[c];
|
||||
float[] to = ibuffer[c];
|
||||
for (int i = 0; i < to.length; i++) {
|
||||
to[i] = from[i];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public long skip(long len) throws IOException {
|
||||
if (len < 0)
|
||||
return 0;
|
||||
if (skipbuffer == null)
|
||||
skipbuffer = new float[1024 * targetFormat.getFrameSize()];
|
||||
float[] l_skipbuffer = skipbuffer;
|
||||
long remain = len;
|
||||
while (remain > 0) {
|
||||
int ret = read(l_skipbuffer, 0, (int) Math.min(remain,
|
||||
skipbuffer.length));
|
||||
if (ret < 0) {
|
||||
if (remain == len)
|
||||
return ret;
|
||||
break;
|
||||
}
|
||||
remain -= ret;
|
||||
}
|
||||
return len - remain;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final Encoding[] formats = {Encoding.PCM_SIGNED,
|
||||
Encoding.PCM_UNSIGNED,
|
||||
Encoding.PCM_FLOAT};
|
||||
|
||||
public AudioInputStream getAudioInputStream(Encoding targetEncoding,
|
||||
AudioInputStream sourceStream) {
|
||||
if (sourceStream.getFormat().getEncoding().equals(targetEncoding))
|
||||
return sourceStream;
|
||||
AudioFormat format = sourceStream.getFormat();
|
||||
int channels = format.getChannels();
|
||||
Encoding encoding = targetEncoding;
|
||||
float samplerate = format.getSampleRate();
|
||||
int bits = format.getSampleSizeInBits();
|
||||
boolean bigendian = format.isBigEndian();
|
||||
if (targetEncoding.equals(Encoding.PCM_FLOAT))
|
||||
bits = 32;
|
||||
AudioFormat targetFormat = new AudioFormat(encoding, samplerate, bits,
|
||||
channels, channels * bits / 8, samplerate, bigendian);
|
||||
return getAudioInputStream(targetFormat, sourceStream);
|
||||
}
|
||||
|
||||
public AudioInputStream getAudioInputStream(AudioFormat targetFormat,
|
||||
AudioInputStream sourceStream) {
|
||||
if (!isConversionSupported(targetFormat, sourceStream.getFormat()))
|
||||
throw new IllegalArgumentException("Unsupported conversion: "
|
||||
+ sourceStream.getFormat().toString() + " to "
|
||||
+ targetFormat.toString());
|
||||
return getAudioInputStream(targetFormat, AudioFloatInputStream
|
||||
.getInputStream(sourceStream));
|
||||
}
|
||||
|
||||
public AudioInputStream getAudioInputStream(AudioFormat targetFormat,
|
||||
AudioFloatInputStream sourceStream) {
|
||||
|
||||
if (!isConversionSupported(targetFormat, sourceStream.getFormat()))
|
||||
throw new IllegalArgumentException("Unsupported conversion: "
|
||||
+ sourceStream.getFormat().toString() + " to "
|
||||
+ targetFormat.toString());
|
||||
if (targetFormat.getChannels() != sourceStream.getFormat()
|
||||
.getChannels())
|
||||
sourceStream = new AudioFloatInputStreamChannelMixer(sourceStream,
|
||||
targetFormat.getChannels());
|
||||
if (Math.abs(targetFormat.getSampleRate()
|
||||
- sourceStream.getFormat().getSampleRate()) > 0.000001)
|
||||
sourceStream = new AudioFloatInputStreamResampler(sourceStream,
|
||||
targetFormat);
|
||||
return new AudioInputStream(new AudioFloatFormatConverterInputStream(
|
||||
targetFormat, sourceStream), targetFormat, sourceStream
|
||||
.getFrameLength());
|
||||
}
|
||||
|
||||
public Encoding[] getSourceEncodings() {
|
||||
return new Encoding[] { Encoding.PCM_SIGNED, Encoding.PCM_UNSIGNED,
|
||||
Encoding.PCM_FLOAT };
|
||||
}
|
||||
|
||||
public Encoding[] getTargetEncodings() {
|
||||
return new Encoding[] { Encoding.PCM_SIGNED, Encoding.PCM_UNSIGNED,
|
||||
Encoding.PCM_FLOAT };
|
||||
}
|
||||
|
||||
public Encoding[] getTargetEncodings(AudioFormat sourceFormat) {
|
||||
if (AudioFloatConverter.getConverter(sourceFormat) == null)
|
||||
return new Encoding[0];
|
||||
return new Encoding[] { Encoding.PCM_SIGNED, Encoding.PCM_UNSIGNED,
|
||||
Encoding.PCM_FLOAT };
|
||||
}
|
||||
|
||||
public AudioFormat[] getTargetFormats(Encoding targetEncoding,
|
||||
AudioFormat sourceFormat) {
|
||||
if (AudioFloatConverter.getConverter(sourceFormat) == null)
|
||||
return new AudioFormat[0];
|
||||
int channels = sourceFormat.getChannels();
|
||||
|
||||
ArrayList<AudioFormat> formats = new ArrayList<AudioFormat>();
|
||||
|
||||
if (targetEncoding.equals(Encoding.PCM_SIGNED))
|
||||
formats.add(new AudioFormat(Encoding.PCM_SIGNED,
|
||||
AudioSystem.NOT_SPECIFIED, 8, channels, channels,
|
||||
AudioSystem.NOT_SPECIFIED, false));
|
||||
if (targetEncoding.equals(Encoding.PCM_UNSIGNED))
|
||||
formats.add(new AudioFormat(Encoding.PCM_UNSIGNED,
|
||||
AudioSystem.NOT_SPECIFIED, 8, channels, channels,
|
||||
AudioSystem.NOT_SPECIFIED, false));
|
||||
|
||||
for (int bits = 16; bits < 32; bits += 8) {
|
||||
if (targetEncoding.equals(Encoding.PCM_SIGNED)) {
|
||||
formats.add(new AudioFormat(Encoding.PCM_SIGNED,
|
||||
AudioSystem.NOT_SPECIFIED, bits, channels, channels
|
||||
* bits / 8, AudioSystem.NOT_SPECIFIED, false));
|
||||
formats.add(new AudioFormat(Encoding.PCM_SIGNED,
|
||||
AudioSystem.NOT_SPECIFIED, bits, channels, channels
|
||||
* bits / 8, AudioSystem.NOT_SPECIFIED, true));
|
||||
}
|
||||
if (targetEncoding.equals(Encoding.PCM_UNSIGNED)) {
|
||||
formats.add(new AudioFormat(Encoding.PCM_UNSIGNED,
|
||||
AudioSystem.NOT_SPECIFIED, bits, channels, channels
|
||||
* bits / 8, AudioSystem.NOT_SPECIFIED, true));
|
||||
formats.add(new AudioFormat(Encoding.PCM_UNSIGNED,
|
||||
AudioSystem.NOT_SPECIFIED, bits, channels, channels
|
||||
* bits / 8, AudioSystem.NOT_SPECIFIED, false));
|
||||
}
|
||||
}
|
||||
|
||||
if (targetEncoding.equals(Encoding.PCM_FLOAT)) {
|
||||
formats.add(new AudioFormat(Encoding.PCM_FLOAT,
|
||||
AudioSystem.NOT_SPECIFIED, 32, channels, channels * 4,
|
||||
AudioSystem.NOT_SPECIFIED, false));
|
||||
formats.add(new AudioFormat(Encoding.PCM_FLOAT,
|
||||
AudioSystem.NOT_SPECIFIED, 32, channels, channels * 4,
|
||||
AudioSystem.NOT_SPECIFIED, true));
|
||||
formats.add(new AudioFormat(Encoding.PCM_FLOAT,
|
||||
AudioSystem.NOT_SPECIFIED, 64, channels, channels * 8,
|
||||
AudioSystem.NOT_SPECIFIED, false));
|
||||
formats.add(new AudioFormat(Encoding.PCM_FLOAT,
|
||||
AudioSystem.NOT_SPECIFIED, 64, channels, channels * 8,
|
||||
AudioSystem.NOT_SPECIFIED, true));
|
||||
}
|
||||
|
||||
return formats.toArray(new AudioFormat[formats.size()]);
|
||||
}
|
||||
|
||||
public boolean isConversionSupported(AudioFormat targetFormat,
|
||||
AudioFormat sourceFormat) {
|
||||
if (AudioFloatConverter.getConverter(sourceFormat) == null)
|
||||
return false;
|
||||
if (AudioFloatConverter.getConverter(targetFormat) == null)
|
||||
return false;
|
||||
if (sourceFormat.getChannels() <= 0)
|
||||
return false;
|
||||
if (targetFormat.getChannels() <= 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isConversionSupported(Encoding targetEncoding,
|
||||
AudioFormat sourceFormat) {
|
||||
if (AudioFloatConverter.getConverter(sourceFormat) == null)
|
||||
return false;
|
||||
for (int i = 0; i < formats.length; i++) {
|
||||
if (targetEncoding.equals(formats[i]))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
281
jdkSrc/jdk8/com/sun/media/sound/AudioFloatInputStream.java
Normal file
281
jdkSrc/jdk8/com/sun/media/sound/AudioFloatInputStream.java
Normal file
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
|
||||
import javax.sound.sampled.AudioFormat;
|
||||
import javax.sound.sampled.AudioInputStream;
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
import javax.sound.sampled.UnsupportedAudioFileException;
|
||||
|
||||
/**
|
||||
* This class is used to create AudioFloatInputStream from AudioInputStream and
|
||||
* byte buffers.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public abstract class AudioFloatInputStream {
|
||||
|
||||
private static class BytaArrayAudioFloatInputStream
|
||||
extends AudioFloatInputStream {
|
||||
|
||||
private int pos = 0;
|
||||
private int markpos = 0;
|
||||
private final AudioFloatConverter converter;
|
||||
private final AudioFormat format;
|
||||
private final byte[] buffer;
|
||||
private final int buffer_offset;
|
||||
private final int buffer_len;
|
||||
private final int framesize_pc;
|
||||
|
||||
BytaArrayAudioFloatInputStream(AudioFloatConverter converter,
|
||||
byte[] buffer, int offset, int len) {
|
||||
this.converter = converter;
|
||||
this.format = converter.getFormat();
|
||||
this.buffer = buffer;
|
||||
this.buffer_offset = offset;
|
||||
framesize_pc = format.getFrameSize() / format.getChannels();
|
||||
this.buffer_len = len / framesize_pc;
|
||||
|
||||
}
|
||||
|
||||
public AudioFormat getFormat() {
|
||||
return format;
|
||||
}
|
||||
|
||||
public long getFrameLength() {
|
||||
return buffer_len;// / format.getFrameSize();
|
||||
}
|
||||
|
||||
public int read(float[] b, int off, int len) throws IOException {
|
||||
if (b == null)
|
||||
throw new NullPointerException();
|
||||
if (off < 0 || len < 0 || len > b.length - off)
|
||||
throw new IndexOutOfBoundsException();
|
||||
if (pos >= buffer_len)
|
||||
return -1;
|
||||
if (len == 0)
|
||||
return 0;
|
||||
if (pos + len > buffer_len)
|
||||
len = buffer_len - pos;
|
||||
converter.toFloatArray(buffer, buffer_offset + pos * framesize_pc,
|
||||
b, off, len);
|
||||
pos += len;
|
||||
return len;
|
||||
}
|
||||
|
||||
public long skip(long len) throws IOException {
|
||||
if (pos >= buffer_len)
|
||||
return -1;
|
||||
if (len <= 0)
|
||||
return 0;
|
||||
if (pos + len > buffer_len)
|
||||
len = buffer_len - pos;
|
||||
pos += len;
|
||||
return len;
|
||||
}
|
||||
|
||||
public int available() throws IOException {
|
||||
return buffer_len - pos;
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
}
|
||||
|
||||
public void mark(int readlimit) {
|
||||
markpos = pos;
|
||||
}
|
||||
|
||||
public boolean markSupported() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void reset() throws IOException {
|
||||
pos = markpos;
|
||||
}
|
||||
}
|
||||
|
||||
private static class DirectAudioFloatInputStream
|
||||
extends AudioFloatInputStream {
|
||||
|
||||
private final AudioInputStream stream;
|
||||
private AudioFloatConverter converter;
|
||||
private final int framesize_pc; // framesize / channels
|
||||
private byte[] buffer;
|
||||
|
||||
DirectAudioFloatInputStream(AudioInputStream stream) {
|
||||
converter = AudioFloatConverter.getConverter(stream.getFormat());
|
||||
if (converter == null) {
|
||||
AudioFormat format = stream.getFormat();
|
||||
AudioFormat newformat;
|
||||
|
||||
AudioFormat[] formats = AudioSystem.getTargetFormats(
|
||||
AudioFormat.Encoding.PCM_SIGNED, format);
|
||||
if (formats.length != 0) {
|
||||
newformat = formats[0];
|
||||
} else {
|
||||
float samplerate = format.getSampleRate();
|
||||
int samplesizeinbits = format.getSampleSizeInBits();
|
||||
int framesize = format.getFrameSize();
|
||||
float framerate = format.getFrameRate();
|
||||
samplesizeinbits = 16;
|
||||
framesize = format.getChannels() * (samplesizeinbits / 8);
|
||||
framerate = samplerate;
|
||||
|
||||
newformat = new AudioFormat(
|
||||
AudioFormat.Encoding.PCM_SIGNED, samplerate,
|
||||
samplesizeinbits, format.getChannels(), framesize,
|
||||
framerate, false);
|
||||
}
|
||||
|
||||
stream = AudioSystem.getAudioInputStream(newformat, stream);
|
||||
converter = AudioFloatConverter.getConverter(stream.getFormat());
|
||||
}
|
||||
framesize_pc = stream.getFormat().getFrameSize()
|
||||
/ stream.getFormat().getChannels();
|
||||
this.stream = stream;
|
||||
}
|
||||
|
||||
public AudioFormat getFormat() {
|
||||
return stream.getFormat();
|
||||
}
|
||||
|
||||
public long getFrameLength() {
|
||||
return stream.getFrameLength();
|
||||
}
|
||||
|
||||
public int read(float[] b, int off, int len) throws IOException {
|
||||
int b_len = len * framesize_pc;
|
||||
if (buffer == null || buffer.length < b_len)
|
||||
buffer = new byte[b_len];
|
||||
int ret = stream.read(buffer, 0, b_len);
|
||||
if (ret == -1)
|
||||
return -1;
|
||||
converter.toFloatArray(buffer, b, off, ret / framesize_pc);
|
||||
return ret / framesize_pc;
|
||||
}
|
||||
|
||||
public long skip(long len) throws IOException {
|
||||
long b_len = len * framesize_pc;
|
||||
long ret = stream.skip(b_len);
|
||||
if (ret == -1)
|
||||
return -1;
|
||||
return ret / framesize_pc;
|
||||
}
|
||||
|
||||
public int available() throws IOException {
|
||||
return stream.available() / framesize_pc;
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
stream.close();
|
||||
}
|
||||
|
||||
public void mark(int readlimit) {
|
||||
stream.mark(readlimit * framesize_pc);
|
||||
}
|
||||
|
||||
public boolean markSupported() {
|
||||
return stream.markSupported();
|
||||
}
|
||||
|
||||
public void reset() throws IOException {
|
||||
stream.reset();
|
||||
}
|
||||
}
|
||||
|
||||
public static AudioFloatInputStream getInputStream(URL url)
|
||||
throws UnsupportedAudioFileException, IOException {
|
||||
return new DirectAudioFloatInputStream(AudioSystem
|
||||
.getAudioInputStream(url));
|
||||
}
|
||||
|
||||
public static AudioFloatInputStream getInputStream(File file)
|
||||
throws UnsupportedAudioFileException, IOException {
|
||||
return new DirectAudioFloatInputStream(AudioSystem
|
||||
.getAudioInputStream(file));
|
||||
}
|
||||
|
||||
public static AudioFloatInputStream getInputStream(InputStream stream)
|
||||
throws UnsupportedAudioFileException, IOException {
|
||||
return new DirectAudioFloatInputStream(AudioSystem
|
||||
.getAudioInputStream(stream));
|
||||
}
|
||||
|
||||
public static AudioFloatInputStream getInputStream(
|
||||
AudioInputStream stream) {
|
||||
return new DirectAudioFloatInputStream(stream);
|
||||
}
|
||||
|
||||
public static AudioFloatInputStream getInputStream(AudioFormat format,
|
||||
byte[] buffer, int offset, int len) {
|
||||
AudioFloatConverter converter = AudioFloatConverter
|
||||
.getConverter(format);
|
||||
if (converter != null)
|
||||
return new BytaArrayAudioFloatInputStream(converter, buffer,
|
||||
offset, len);
|
||||
|
||||
InputStream stream = new ByteArrayInputStream(buffer, offset, len);
|
||||
long aLen = format.getFrameSize() == AudioSystem.NOT_SPECIFIED
|
||||
? AudioSystem.NOT_SPECIFIED : len / format.getFrameSize();
|
||||
AudioInputStream astream = new AudioInputStream(stream, format, aLen);
|
||||
return getInputStream(astream);
|
||||
}
|
||||
|
||||
public abstract AudioFormat getFormat();
|
||||
|
||||
public abstract long getFrameLength();
|
||||
|
||||
public abstract int read(float[] b, int off, int len) throws IOException;
|
||||
|
||||
public final int read(float[] b) throws IOException {
|
||||
return read(b, 0, b.length);
|
||||
}
|
||||
|
||||
public final float read() throws IOException {
|
||||
float[] b = new float[1];
|
||||
int ret = read(b, 0, 1);
|
||||
if (ret == -1 || ret == 0)
|
||||
return 0;
|
||||
return b[0];
|
||||
}
|
||||
|
||||
public abstract long skip(long len) throws IOException;
|
||||
|
||||
public abstract int available() throws IOException;
|
||||
|
||||
public abstract void close() throws IOException;
|
||||
|
||||
public abstract void mark(int readlimit);
|
||||
|
||||
public abstract boolean markSupported();
|
||||
|
||||
public abstract void reset() throws IOException;
|
||||
}
|
||||
128
jdkSrc/jdk8/com/sun/media/sound/AudioSynthesizer.java
Normal file
128
jdkSrc/jdk8/com/sun/media/sound/AudioSynthesizer.java
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.util.Map;
|
||||
import javax.sound.midi.MidiUnavailableException;
|
||||
import javax.sound.midi.Synthesizer;
|
||||
import javax.sound.sampled.AudioFormat;
|
||||
import javax.sound.sampled.AudioInputStream;
|
||||
import javax.sound.sampled.SourceDataLine;
|
||||
|
||||
/**
|
||||
* <code>AudioSynthesizer</code> is a <code>Synthesizer</code>
|
||||
* which renders it's output audio into <code>SourceDataLine</code>
|
||||
* or <code>AudioInputStream</code>.
|
||||
*
|
||||
* @see MidiSystem#getSynthesizer
|
||||
* @see Synthesizer
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public interface AudioSynthesizer extends Synthesizer {
|
||||
|
||||
/**
|
||||
* Obtains the current format (encoding, sample rate, number of channels,
|
||||
* etc.) of the synthesizer audio data.
|
||||
*
|
||||
* <p>If the synthesizer is not open and has never been opened, it returns
|
||||
* the default format.
|
||||
*
|
||||
* @return current audio data format
|
||||
* @see AudioFormat
|
||||
*/
|
||||
public AudioFormat getFormat();
|
||||
|
||||
/**
|
||||
* Gets information about the possible properties for the synthesizer.
|
||||
*
|
||||
* @param info a proposed list of tag/value pairs that will be sent on open.
|
||||
* @return an array of <code>AudioSynthesizerPropertyInfo</code> objects
|
||||
* describing possible properties. This array may be an empty array if
|
||||
* no properties are required.
|
||||
*/
|
||||
public AudioSynthesizerPropertyInfo[] getPropertyInfo(
|
||||
Map<String, Object> info);
|
||||
|
||||
/**
|
||||
* Opens the synthesizer and starts rendering audio into
|
||||
* <code>SourceDataLine</code>.
|
||||
*
|
||||
* <p>An application opening a synthesizer explicitly with this call
|
||||
* has to close the synthesizer by calling {@link #close}. This is
|
||||
* necessary to release system resources and allow applications to
|
||||
* exit cleanly.
|
||||
*
|
||||
* <p>Note that some synthesizers, once closed, cannot be reopened.
|
||||
* Attempts to reopen such a synthesizer will always result in
|
||||
* a <code>MidiUnavailableException</code>.
|
||||
*
|
||||
* @param line which <code>AudioSynthesizer</code> writes output audio into.
|
||||
* If <code>line</code> is null, then line from system default mixer is used.
|
||||
* @param info a <code>Map<String,Object></code> object containing
|
||||
* properties for additional configuration supported by synthesizer.
|
||||
* If <code>info</code> is null then default settings are used.
|
||||
*
|
||||
* @throws MidiUnavailableException thrown if the synthesizer cannot be
|
||||
* opened due to resource restrictions.
|
||||
* @throws SecurityException thrown if the synthesizer cannot be
|
||||
* opened due to security restrictions.
|
||||
*
|
||||
* @see #close
|
||||
* @see #isOpen
|
||||
*/
|
||||
public void open(SourceDataLine line, Map<String, Object> info)
|
||||
throws MidiUnavailableException;
|
||||
|
||||
/**
|
||||
* Opens the synthesizer and renders audio into returned
|
||||
* <code>AudioInputStream</code>.
|
||||
*
|
||||
* <p>An application opening a synthesizer explicitly with this call
|
||||
* has to close the synthesizer by calling {@link #close}. This is
|
||||
* necessary to release system resources and allow applications to
|
||||
* exit cleanly.
|
||||
*
|
||||
* <p>Note that some synthesizers, once closed, cannot be reopened.
|
||||
* Attempts to reopen such a synthesizer will always result in
|
||||
* a <code>MidiUnavailableException<code>.
|
||||
*
|
||||
* @param targetFormat specifies the <code>AudioFormat</code>
|
||||
* used in returned <code>AudioInputStream</code>.
|
||||
* @param info a <code>Map<String,Object></code> object containing
|
||||
* properties for additional configuration supported by synthesizer.
|
||||
* If <code>info</code> is null then default settings are used.
|
||||
*
|
||||
* @throws MidiUnavailableException thrown if the synthesizer cannot be
|
||||
* opened due to resource restrictions.
|
||||
* @throws SecurityException thrown if the synthesizer cannot be
|
||||
* opened due to security restrictions.
|
||||
*
|
||||
* @see #close
|
||||
* @see #isOpen
|
||||
*/
|
||||
public AudioInputStream openStream(AudioFormat targetFormat,
|
||||
Map<String, Object> info) throws MidiUnavailableException;
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
/**
|
||||
* Information about property used in opening <code>AudioSynthesizer</code>.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public final class AudioSynthesizerPropertyInfo {
|
||||
|
||||
/**
|
||||
* Constructs a <code>AudioSynthesizerPropertyInfo</code> object with a given
|
||||
* name and value. The <code>description</code> and <code>choices</code>
|
||||
* are initialized by <code>null</code> values.
|
||||
*
|
||||
* @param name the name of the property
|
||||
* @param value the current value or class used for values.
|
||||
*
|
||||
*/
|
||||
public AudioSynthesizerPropertyInfo(String name, Object value) {
|
||||
this.name = name;
|
||||
if (value instanceof Class)
|
||||
valueClass = (Class)value;
|
||||
else
|
||||
{
|
||||
this.value = value;
|
||||
if (value != null)
|
||||
valueClass = value.getClass();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* The name of the property.
|
||||
*/
|
||||
public String name;
|
||||
/**
|
||||
* A brief description of the property, which may be null.
|
||||
*/
|
||||
public String description = null;
|
||||
/**
|
||||
* The <code>value</code> field specifies the current value of
|
||||
* the property.
|
||||
*/
|
||||
public Object value = null;
|
||||
/**
|
||||
* The <code>valueClass</code> field specifies class
|
||||
* used in <code>value</code> field.
|
||||
*/
|
||||
public Class valueClass = null;
|
||||
/**
|
||||
* An array of possible values if the value for the field
|
||||
* <code>AudioSynthesizerPropertyInfo.value</code> may be selected
|
||||
* from a particular set of values; otherwise null.
|
||||
*/
|
||||
public Object[] choices = null;
|
||||
|
||||
}
|
||||
55
jdkSrc/jdk8/com/sun/media/sound/AutoClosingClip.java
Normal file
55
jdkSrc/jdk8/com/sun/media/sound/AutoClosingClip.java
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.media.sound;
|
||||
|
||||
import javax.sound.sampled.Clip;
|
||||
|
||||
/**
|
||||
* Interface for Clip objects that close themselves automatically
|
||||
*
|
||||
* @author Florian Bomers
|
||||
*/
|
||||
interface AutoClosingClip extends Clip {
|
||||
|
||||
/**
|
||||
* Indicates whether this clip instance is auto closing.
|
||||
* When the clip is auto closing, it calls the close()
|
||||
* method automatically after a short period of inactivity.<br>
|
||||
* <br>
|
||||
*
|
||||
* @return true if this clip is auto closing
|
||||
*/
|
||||
boolean isAutoClosing();
|
||||
|
||||
/**
|
||||
* Sets whether this Clip instance is auto closing or not.
|
||||
* If true, the close() method will be called automatically
|
||||
* after a short period of inactivity.
|
||||
*
|
||||
* @param value - true to set this clip to auto closing
|
||||
*/
|
||||
void setAutoClosing(boolean value);
|
||||
}
|
||||
46
jdkSrc/jdk8/com/sun/media/sound/AutoConnectSequencer.java
Normal file
46
jdkSrc/jdk8/com/sun/media/sound/AutoConnectSequencer.java
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.media.sound;
|
||||
|
||||
import javax.sound.midi.Receiver;
|
||||
|
||||
/**
|
||||
* Interface for Sequencers that are able to do the auto-connect
|
||||
* as required by MidiSystem.getSequencer()
|
||||
*
|
||||
* @author Florian Bomers
|
||||
*/
|
||||
public interface AutoConnectSequencer {
|
||||
|
||||
/**
|
||||
* Set the receiver that this device is
|
||||
* auto-connected. If non-null, the device
|
||||
* needs to re-connect itself to a suitable
|
||||
* device in open().
|
||||
*/
|
||||
public void setAutoConnect(Receiver autoConnectReceiver);
|
||||
|
||||
}
|
||||
109
jdkSrc/jdk8/com/sun/media/sound/DLSInfo.java
Normal file
109
jdkSrc/jdk8/com/sun/media/sound/DLSInfo.java
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
/**
|
||||
* This class is used to store information to describe soundbanks, instruments
|
||||
* and samples. It is stored inside a "INFO" List Chunk inside DLS files.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public final class DLSInfo {
|
||||
|
||||
/**
|
||||
* (INAM) Title or subject.
|
||||
*/
|
||||
public String name = "untitled";
|
||||
/**
|
||||
* (ICRD) Date of creation, the format is: YYYY-MM-DD.
|
||||
* For example 2007-01-01 for 1. january of year 2007.
|
||||
*/
|
||||
public String creationDate = null;
|
||||
/**
|
||||
* (IENG) Name of engineer who created the object.
|
||||
*/
|
||||
public String engineers = null;
|
||||
/**
|
||||
* (IPRD) Name of the product which the object is intended for.
|
||||
*/
|
||||
public String product = null;
|
||||
/**
|
||||
* (ICOP) Copyright information.
|
||||
*/
|
||||
public String copyright = null;
|
||||
/**
|
||||
* (ICMT) General comments. Doesn't contain newline characters.
|
||||
*/
|
||||
public String comments = null;
|
||||
/**
|
||||
* (ISFT) Name of software package used to create the file.
|
||||
*/
|
||||
public String tools = null;
|
||||
/**
|
||||
* (IARL) Where content is archived.
|
||||
*/
|
||||
public String archival_location = null;
|
||||
/**
|
||||
* (IART) Artists of original content.
|
||||
*/
|
||||
public String artist = null;
|
||||
/**
|
||||
* (ICMS) Names of persons or orginizations who commissioned the file.
|
||||
*/
|
||||
public String commissioned = null;
|
||||
/**
|
||||
* (IGNR) Genre of the work.
|
||||
* Example: jazz, classical, rock, etc.
|
||||
*/
|
||||
public String genre = null;
|
||||
/**
|
||||
* (IKEY) List of keyword that describe the content.
|
||||
* Examples: FX, bird, piano, etc.
|
||||
*/
|
||||
public String keywords = null;
|
||||
/**
|
||||
* (IMED) Describes original medium of the data.
|
||||
* For example: record, CD, etc.
|
||||
*/
|
||||
public String medium = null;
|
||||
/**
|
||||
* (ISBJ) Description of the content.
|
||||
*/
|
||||
public String subject = null;
|
||||
/**
|
||||
* (ISRC) Name of person or orginization who supplied
|
||||
* orginal material for the file.
|
||||
*/
|
||||
public String source = null;
|
||||
/**
|
||||
* (ISRF) Source media for sample data is from.
|
||||
* For example: CD, TV, etc.
|
||||
*/
|
||||
public String source_form = null;
|
||||
/**
|
||||
* (ITCH) Technician who sample the file/object.
|
||||
*/
|
||||
public String technician = null;
|
||||
}
|
||||
449
jdkSrc/jdk8/com/sun/media/sound/DLSInstrument.java
Normal file
449
jdkSrc/jdk8/com/sun/media/sound/DLSInstrument.java
Normal file
@@ -0,0 +1,449 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.sound.midi.Patch;
|
||||
|
||||
/**
|
||||
* This class is used to store information to describe instrument.
|
||||
* It contains list of regions and modulators.
|
||||
* It is stored inside a "ins " List Chunk inside DLS files.
|
||||
* In the DLS documentation a modulator is called articulator.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public final class DLSInstrument extends ModelInstrument {
|
||||
|
||||
int preset = 0;
|
||||
int bank = 0;
|
||||
boolean druminstrument = false;
|
||||
byte[] guid = null;
|
||||
DLSInfo info = new DLSInfo();
|
||||
List<DLSRegion> regions = new ArrayList<DLSRegion>();
|
||||
List<DLSModulator> modulators = new ArrayList<DLSModulator>();
|
||||
|
||||
public DLSInstrument() {
|
||||
super(null, null, null, null);
|
||||
}
|
||||
|
||||
public DLSInstrument(DLSSoundbank soundbank) {
|
||||
super(soundbank, null, null, null);
|
||||
}
|
||||
|
||||
public DLSInfo getInfo() {
|
||||
return info;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return info.name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
info.name = name;
|
||||
}
|
||||
|
||||
public ModelPatch getPatch() {
|
||||
return new ModelPatch(bank, preset, druminstrument);
|
||||
}
|
||||
|
||||
public void setPatch(Patch patch) {
|
||||
if (patch instanceof ModelPatch && ((ModelPatch)patch).isPercussion()) {
|
||||
druminstrument = true;
|
||||
bank = patch.getBank();
|
||||
preset = patch.getProgram();
|
||||
} else {
|
||||
druminstrument = false;
|
||||
bank = patch.getBank();
|
||||
preset = patch.getProgram();
|
||||
}
|
||||
}
|
||||
|
||||
public Object getData() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<DLSRegion> getRegions() {
|
||||
return regions;
|
||||
}
|
||||
|
||||
public List<DLSModulator> getModulators() {
|
||||
return modulators;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
if (druminstrument)
|
||||
return "Drumkit: " + info.name
|
||||
+ " bank #" + bank + " preset #" + preset;
|
||||
else
|
||||
return "Instrument: " + info.name
|
||||
+ " bank #" + bank + " preset #" + preset;
|
||||
}
|
||||
|
||||
private ModelIdentifier convertToModelDest(int dest) {
|
||||
if (dest == DLSModulator.CONN_DST_NONE)
|
||||
return null;
|
||||
if (dest == DLSModulator.CONN_DST_GAIN)
|
||||
return ModelDestination.DESTINATION_GAIN;
|
||||
if (dest == DLSModulator.CONN_DST_PITCH)
|
||||
return ModelDestination.DESTINATION_PITCH;
|
||||
if (dest == DLSModulator.CONN_DST_PAN)
|
||||
return ModelDestination.DESTINATION_PAN;
|
||||
|
||||
if (dest == DLSModulator.CONN_DST_LFO_FREQUENCY)
|
||||
return ModelDestination.DESTINATION_LFO1_FREQ;
|
||||
if (dest == DLSModulator.CONN_DST_LFO_STARTDELAY)
|
||||
return ModelDestination.DESTINATION_LFO1_DELAY;
|
||||
|
||||
if (dest == DLSModulator.CONN_DST_EG1_ATTACKTIME)
|
||||
return ModelDestination.DESTINATION_EG1_ATTACK;
|
||||
if (dest == DLSModulator.CONN_DST_EG1_DECAYTIME)
|
||||
return ModelDestination.DESTINATION_EG1_DECAY;
|
||||
if (dest == DLSModulator.CONN_DST_EG1_RELEASETIME)
|
||||
return ModelDestination.DESTINATION_EG1_RELEASE;
|
||||
if (dest == DLSModulator.CONN_DST_EG1_SUSTAINLEVEL)
|
||||
return ModelDestination.DESTINATION_EG1_SUSTAIN;
|
||||
|
||||
if (dest == DLSModulator.CONN_DST_EG2_ATTACKTIME)
|
||||
return ModelDestination.DESTINATION_EG2_ATTACK;
|
||||
if (dest == DLSModulator.CONN_DST_EG2_DECAYTIME)
|
||||
return ModelDestination.DESTINATION_EG2_DECAY;
|
||||
if (dest == DLSModulator.CONN_DST_EG2_RELEASETIME)
|
||||
return ModelDestination.DESTINATION_EG2_RELEASE;
|
||||
if (dest == DLSModulator.CONN_DST_EG2_SUSTAINLEVEL)
|
||||
return ModelDestination.DESTINATION_EG2_SUSTAIN;
|
||||
|
||||
// DLS2 Destinations
|
||||
if (dest == DLSModulator.CONN_DST_KEYNUMBER)
|
||||
return ModelDestination.DESTINATION_KEYNUMBER;
|
||||
|
||||
if (dest == DLSModulator.CONN_DST_CHORUS)
|
||||
return ModelDestination.DESTINATION_CHORUS;
|
||||
if (dest == DLSModulator.CONN_DST_REVERB)
|
||||
return ModelDestination.DESTINATION_REVERB;
|
||||
|
||||
if (dest == DLSModulator.CONN_DST_VIB_FREQUENCY)
|
||||
return ModelDestination.DESTINATION_LFO2_FREQ;
|
||||
if (dest == DLSModulator.CONN_DST_VIB_STARTDELAY)
|
||||
return ModelDestination.DESTINATION_LFO2_DELAY;
|
||||
|
||||
if (dest == DLSModulator.CONN_DST_EG1_DELAYTIME)
|
||||
return ModelDestination.DESTINATION_EG1_DELAY;
|
||||
if (dest == DLSModulator.CONN_DST_EG1_HOLDTIME)
|
||||
return ModelDestination.DESTINATION_EG1_HOLD;
|
||||
if (dest == DLSModulator.CONN_DST_EG1_SHUTDOWNTIME)
|
||||
return ModelDestination.DESTINATION_EG1_SHUTDOWN;
|
||||
|
||||
if (dest == DLSModulator.CONN_DST_EG2_DELAYTIME)
|
||||
return ModelDestination.DESTINATION_EG2_DELAY;
|
||||
if (dest == DLSModulator.CONN_DST_EG2_HOLDTIME)
|
||||
return ModelDestination.DESTINATION_EG2_HOLD;
|
||||
|
||||
if (dest == DLSModulator.CONN_DST_FILTER_CUTOFF)
|
||||
return ModelDestination.DESTINATION_FILTER_FREQ;
|
||||
if (dest == DLSModulator.CONN_DST_FILTER_Q)
|
||||
return ModelDestination.DESTINATION_FILTER_Q;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private ModelIdentifier convertToModelSrc(int src) {
|
||||
if (src == DLSModulator.CONN_SRC_NONE)
|
||||
return null;
|
||||
|
||||
if (src == DLSModulator.CONN_SRC_LFO)
|
||||
return ModelSource.SOURCE_LFO1;
|
||||
if (src == DLSModulator.CONN_SRC_KEYONVELOCITY)
|
||||
return ModelSource.SOURCE_NOTEON_VELOCITY;
|
||||
if (src == DLSModulator.CONN_SRC_KEYNUMBER)
|
||||
return ModelSource.SOURCE_NOTEON_KEYNUMBER;
|
||||
if (src == DLSModulator.CONN_SRC_EG1)
|
||||
return ModelSource.SOURCE_EG1;
|
||||
if (src == DLSModulator.CONN_SRC_EG2)
|
||||
return ModelSource.SOURCE_EG2;
|
||||
if (src == DLSModulator.CONN_SRC_PITCHWHEEL)
|
||||
return ModelSource.SOURCE_MIDI_PITCH;
|
||||
if (src == DLSModulator.CONN_SRC_CC1)
|
||||
return new ModelIdentifier("midi_cc", "1", 0);
|
||||
if (src == DLSModulator.CONN_SRC_CC7)
|
||||
return new ModelIdentifier("midi_cc", "7", 0);
|
||||
if (src == DLSModulator.CONN_SRC_CC10)
|
||||
return new ModelIdentifier("midi_cc", "10", 0);
|
||||
if (src == DLSModulator.CONN_SRC_CC11)
|
||||
return new ModelIdentifier("midi_cc", "11", 0);
|
||||
if (src == DLSModulator.CONN_SRC_RPN0)
|
||||
return new ModelIdentifier("midi_rpn", "0", 0);
|
||||
if (src == DLSModulator.CONN_SRC_RPN1)
|
||||
return new ModelIdentifier("midi_rpn", "1", 0);
|
||||
|
||||
if (src == DLSModulator.CONN_SRC_POLYPRESSURE)
|
||||
return ModelSource.SOURCE_MIDI_POLY_PRESSURE;
|
||||
if (src == DLSModulator.CONN_SRC_CHANNELPRESSURE)
|
||||
return ModelSource.SOURCE_MIDI_CHANNEL_PRESSURE;
|
||||
if (src == DLSModulator.CONN_SRC_VIBRATO)
|
||||
return ModelSource.SOURCE_LFO2;
|
||||
if (src == DLSModulator.CONN_SRC_MONOPRESSURE)
|
||||
return ModelSource.SOURCE_MIDI_CHANNEL_PRESSURE;
|
||||
|
||||
if (src == DLSModulator.CONN_SRC_CC91)
|
||||
return new ModelIdentifier("midi_cc", "91", 0);
|
||||
if (src == DLSModulator.CONN_SRC_CC93)
|
||||
return new ModelIdentifier("midi_cc", "93", 0);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private ModelConnectionBlock convertToModel(DLSModulator mod) {
|
||||
ModelIdentifier source = convertToModelSrc(mod.getSource());
|
||||
ModelIdentifier control = convertToModelSrc(mod.getControl());
|
||||
ModelIdentifier destination_id =
|
||||
convertToModelDest(mod.getDestination());
|
||||
|
||||
int scale = mod.getScale();
|
||||
double f_scale;
|
||||
if (scale == Integer.MIN_VALUE)
|
||||
f_scale = Double.NEGATIVE_INFINITY;
|
||||
else
|
||||
f_scale = scale / 65536.0;
|
||||
|
||||
if (destination_id != null) {
|
||||
ModelSource src = null;
|
||||
ModelSource ctrl = null;
|
||||
ModelConnectionBlock block = new ModelConnectionBlock();
|
||||
if (control != null) {
|
||||
ModelSource s = new ModelSource();
|
||||
if (control == ModelSource.SOURCE_MIDI_PITCH) {
|
||||
((ModelStandardTransform)s.getTransform()).setPolarity(
|
||||
ModelStandardTransform.POLARITY_BIPOLAR);
|
||||
} else if (control == ModelSource.SOURCE_LFO1
|
||||
|| control == ModelSource.SOURCE_LFO2) {
|
||||
((ModelStandardTransform)s.getTransform()).setPolarity(
|
||||
ModelStandardTransform.POLARITY_BIPOLAR);
|
||||
}
|
||||
s.setIdentifier(control);
|
||||
block.addSource(s);
|
||||
ctrl = s;
|
||||
}
|
||||
if (source != null) {
|
||||
ModelSource s = new ModelSource();
|
||||
if (source == ModelSource.SOURCE_MIDI_PITCH) {
|
||||
((ModelStandardTransform)s.getTransform()).setPolarity(
|
||||
ModelStandardTransform.POLARITY_BIPOLAR);
|
||||
} else if (source == ModelSource.SOURCE_LFO1
|
||||
|| source == ModelSource.SOURCE_LFO2) {
|
||||
((ModelStandardTransform)s.getTransform()).setPolarity(
|
||||
ModelStandardTransform.POLARITY_BIPOLAR);
|
||||
}
|
||||
s.setIdentifier(source);
|
||||
block.addSource(s);
|
||||
src = s;
|
||||
}
|
||||
ModelDestination destination = new ModelDestination();
|
||||
destination.setIdentifier(destination_id);
|
||||
block.setDestination(destination);
|
||||
|
||||
if (mod.getVersion() == 1) {
|
||||
//if (mod.getTransform() == DLSModulator.CONN_TRN_CONCAVE) {
|
||||
// ((ModelStandardTransform)destination.getTransform())
|
||||
// .setTransform(
|
||||
// ModelStandardTransform.TRANSFORM_CONCAVE);
|
||||
//}
|
||||
if (mod.getTransform() == DLSModulator.CONN_TRN_CONCAVE) {
|
||||
if (src != null) {
|
||||
((ModelStandardTransform)src.getTransform())
|
||||
.setTransform(
|
||||
ModelStandardTransform.TRANSFORM_CONCAVE);
|
||||
((ModelStandardTransform)src.getTransform())
|
||||
.setDirection(
|
||||
ModelStandardTransform.DIRECTION_MAX2MIN);
|
||||
}
|
||||
if (ctrl != null) {
|
||||
((ModelStandardTransform)ctrl.getTransform())
|
||||
.setTransform(
|
||||
ModelStandardTransform.TRANSFORM_CONCAVE);
|
||||
((ModelStandardTransform)ctrl.getTransform())
|
||||
.setDirection(
|
||||
ModelStandardTransform.DIRECTION_MAX2MIN);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (mod.getVersion() == 2) {
|
||||
int transform = mod.getTransform();
|
||||
int src_transform_invert = (transform >> 15) & 1;
|
||||
int src_transform_bipolar = (transform >> 14) & 1;
|
||||
int src_transform = (transform >> 10) & 8;
|
||||
int ctr_transform_invert = (transform >> 9) & 1;
|
||||
int ctr_transform_bipolar = (transform >> 8) & 1;
|
||||
int ctr_transform = (transform >> 4) & 8;
|
||||
|
||||
|
||||
if (src != null) {
|
||||
int trans = ModelStandardTransform.TRANSFORM_LINEAR;
|
||||
if (src_transform == DLSModulator.CONN_TRN_SWITCH)
|
||||
trans = ModelStandardTransform.TRANSFORM_SWITCH;
|
||||
if (src_transform == DLSModulator.CONN_TRN_CONCAVE)
|
||||
trans = ModelStandardTransform.TRANSFORM_CONCAVE;
|
||||
if (src_transform == DLSModulator.CONN_TRN_CONVEX)
|
||||
trans = ModelStandardTransform.TRANSFORM_CONVEX;
|
||||
((ModelStandardTransform)src.getTransform())
|
||||
.setTransform(trans);
|
||||
((ModelStandardTransform)src.getTransform())
|
||||
.setPolarity(src_transform_bipolar == 1);
|
||||
((ModelStandardTransform)src.getTransform())
|
||||
.setDirection(src_transform_invert == 1);
|
||||
|
||||
}
|
||||
|
||||
if (ctrl != null) {
|
||||
int trans = ModelStandardTransform.TRANSFORM_LINEAR;
|
||||
if (ctr_transform == DLSModulator.CONN_TRN_SWITCH)
|
||||
trans = ModelStandardTransform.TRANSFORM_SWITCH;
|
||||
if (ctr_transform == DLSModulator.CONN_TRN_CONCAVE)
|
||||
trans = ModelStandardTransform.TRANSFORM_CONCAVE;
|
||||
if (ctr_transform == DLSModulator.CONN_TRN_CONVEX)
|
||||
trans = ModelStandardTransform.TRANSFORM_CONVEX;
|
||||
((ModelStandardTransform)ctrl.getTransform())
|
||||
.setTransform(trans);
|
||||
((ModelStandardTransform)ctrl.getTransform())
|
||||
.setPolarity(ctr_transform_bipolar == 1);
|
||||
((ModelStandardTransform)ctrl.getTransform())
|
||||
.setDirection(ctr_transform_invert == 1);
|
||||
}
|
||||
|
||||
/* No output transforms are defined the DLS Level 2
|
||||
int out_transform = transform % 8;
|
||||
int trans = ModelStandardTransform.TRANSFORM_LINEAR;
|
||||
if (out_transform == DLSModulator.CONN_TRN_SWITCH)
|
||||
trans = ModelStandardTransform.TRANSFORM_SWITCH;
|
||||
if (out_transform == DLSModulator.CONN_TRN_CONCAVE)
|
||||
trans = ModelStandardTransform.TRANSFORM_CONCAVE;
|
||||
if (out_transform == DLSModulator.CONN_TRN_CONVEX)
|
||||
trans = ModelStandardTransform.TRANSFORM_CONVEX;
|
||||
if (ctrl != null) {
|
||||
((ModelStandardTransform)destination.getTransform())
|
||||
.setTransform(trans);
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
block.setScale(f_scale);
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public ModelPerformer[] getPerformers() {
|
||||
List<ModelPerformer> performers = new ArrayList<ModelPerformer>();
|
||||
|
||||
Map<String, DLSModulator> modmap = new HashMap<String, DLSModulator>();
|
||||
for (DLSModulator mod: getModulators()) {
|
||||
modmap.put(mod.getSource() + "x" + mod.getControl() + "=" +
|
||||
mod.getDestination(), mod);
|
||||
}
|
||||
|
||||
Map<String, DLSModulator> insmodmap =
|
||||
new HashMap<String, DLSModulator>();
|
||||
|
||||
for (DLSRegion zone: regions) {
|
||||
ModelPerformer performer = new ModelPerformer();
|
||||
performer.setName(zone.getSample().getName());
|
||||
performer.setSelfNonExclusive((zone.getFusoptions() &
|
||||
DLSRegion.OPTION_SELFNONEXCLUSIVE) != 0);
|
||||
performer.setExclusiveClass(zone.getExclusiveClass());
|
||||
performer.setKeyFrom(zone.getKeyfrom());
|
||||
performer.setKeyTo(zone.getKeyto());
|
||||
performer.setVelFrom(zone.getVelfrom());
|
||||
performer.setVelTo(zone.getVelto());
|
||||
|
||||
insmodmap.clear();
|
||||
insmodmap.putAll(modmap);
|
||||
for (DLSModulator mod: zone.getModulators()) {
|
||||
insmodmap.put(mod.getSource() + "x" + mod.getControl() + "=" +
|
||||
mod.getDestination(), mod);
|
||||
}
|
||||
|
||||
List<ModelConnectionBlock> blocks = performer.getConnectionBlocks();
|
||||
for (DLSModulator mod: insmodmap.values()) {
|
||||
ModelConnectionBlock p = convertToModel(mod);
|
||||
if (p != null)
|
||||
blocks.add(p);
|
||||
}
|
||||
|
||||
|
||||
DLSSample sample = zone.getSample();
|
||||
DLSSampleOptions sampleopt = zone.getSampleoptions();
|
||||
if (sampleopt == null)
|
||||
sampleopt = sample.getSampleoptions();
|
||||
|
||||
ModelByteBuffer buff = sample.getDataBuffer();
|
||||
|
||||
float pitchcorrection = (-sampleopt.unitynote * 100) +
|
||||
sampleopt.finetune;
|
||||
|
||||
ModelByteBufferWavetable osc = new ModelByteBufferWavetable(buff,
|
||||
sample.getFormat(), pitchcorrection);
|
||||
osc.setAttenuation(osc.getAttenuation() / 65536f);
|
||||
if (sampleopt.getLoops().size() != 0) {
|
||||
DLSSampleLoop loop = sampleopt.getLoops().get(0);
|
||||
osc.setLoopStart((int)loop.getStart());
|
||||
osc.setLoopLength((int)loop.getLength());
|
||||
if (loop.getType() == DLSSampleLoop.LOOP_TYPE_FORWARD)
|
||||
osc.setLoopType(ModelWavetable.LOOP_TYPE_FORWARD);
|
||||
if (loop.getType() == DLSSampleLoop.LOOP_TYPE_RELEASE)
|
||||
osc.setLoopType(ModelWavetable.LOOP_TYPE_RELEASE);
|
||||
else
|
||||
osc.setLoopType(ModelWavetable.LOOP_TYPE_FORWARD);
|
||||
}
|
||||
|
||||
performer.getConnectionBlocks().add(
|
||||
new ModelConnectionBlock(SoftFilter.FILTERTYPE_LP12,
|
||||
new ModelDestination(
|
||||
new ModelIdentifier("filter", "type", 1))));
|
||||
|
||||
performer.getOscillators().add(osc);
|
||||
|
||||
performers.add(performer);
|
||||
|
||||
}
|
||||
|
||||
return performers.toArray(new ModelPerformer[performers.size()]);
|
||||
}
|
||||
|
||||
public byte[] getGuid() {
|
||||
return guid == null ? null : Arrays.copyOf(guid, guid.length);
|
||||
}
|
||||
|
||||
public void setGuid(byte[] guid) {
|
||||
this.guid = guid == null ? null : Arrays.copyOf(guid, guid.length);
|
||||
}
|
||||
}
|
||||
351
jdkSrc/jdk8/com/sun/media/sound/DLSModulator.java
Normal file
351
jdkSrc/jdk8/com/sun/media/sound/DLSModulator.java
Normal file
@@ -0,0 +1,351 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
/**
|
||||
* This class is used to store modulator/artiuclation data.
|
||||
* A modulator connects one synthesizer source to
|
||||
* a destination. For example a note on velocity
|
||||
* can be mapped to the gain of the synthesized voice.
|
||||
* It is stored as a "art1" or "art2" chunk inside DLS files.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public final class DLSModulator {
|
||||
|
||||
// DLS1 Destinations
|
||||
public static final int CONN_DST_NONE = 0x000; // 0
|
||||
public static final int CONN_DST_GAIN = 0x001; // cB
|
||||
public static final int CONN_DST_PITCH = 0x003; // cent
|
||||
public static final int CONN_DST_PAN = 0x004; // 0.1%
|
||||
public static final int CONN_DST_LFO_FREQUENCY = 0x104; // cent (default 5 Hz)
|
||||
public static final int CONN_DST_LFO_STARTDELAY = 0x105; // timecent
|
||||
public static final int CONN_DST_EG1_ATTACKTIME = 0x206; // timecent
|
||||
public static final int CONN_DST_EG1_DECAYTIME = 0x207; // timecent
|
||||
public static final int CONN_DST_EG1_RELEASETIME = 0x209; // timecent
|
||||
public static final int CONN_DST_EG1_SUSTAINLEVEL = 0x20A; // 0.1%
|
||||
public static final int CONN_DST_EG2_ATTACKTIME = 0x30A; // timecent
|
||||
public static final int CONN_DST_EG2_DECAYTIME = 0x30B; // timecent
|
||||
public static final int CONN_DST_EG2_RELEASETIME = 0x30D; // timecent
|
||||
public static final int CONN_DST_EG2_SUSTAINLEVEL = 0x30E; // 0.1%
|
||||
// DLS2 Destinations
|
||||
public static final int CONN_DST_KEYNUMBER = 0x005;
|
||||
public static final int CONN_DST_LEFT = 0x010; // 0.1%
|
||||
public static final int CONN_DST_RIGHT = 0x011; // 0.1%
|
||||
public static final int CONN_DST_CENTER = 0x012; // 0.1%
|
||||
public static final int CONN_DST_LEFTREAR = 0x013; // 0.1%
|
||||
public static final int CONN_DST_RIGHTREAR = 0x014; // 0.1%
|
||||
public static final int CONN_DST_LFE_CHANNEL = 0x015; // 0.1%
|
||||
public static final int CONN_DST_CHORUS = 0x080; // 0.1%
|
||||
public static final int CONN_DST_REVERB = 0x081; // 0.1%
|
||||
public static final int CONN_DST_VIB_FREQUENCY = 0x114; // cent
|
||||
public static final int CONN_DST_VIB_STARTDELAY = 0x115; // dB
|
||||
public static final int CONN_DST_EG1_DELAYTIME = 0x20B; // timecent
|
||||
public static final int CONN_DST_EG1_HOLDTIME = 0x20C; // timecent
|
||||
public static final int CONN_DST_EG1_SHUTDOWNTIME = 0x20D; // timecent
|
||||
public static final int CONN_DST_EG2_DELAYTIME = 0x30F; // timecent
|
||||
public static final int CONN_DST_EG2_HOLDTIME = 0x310; // timecent
|
||||
public static final int CONN_DST_FILTER_CUTOFF = 0x500; // cent
|
||||
public static final int CONN_DST_FILTER_Q = 0x501; // dB
|
||||
|
||||
// DLS1 Sources
|
||||
public static final int CONN_SRC_NONE = 0x000; // 1
|
||||
public static final int CONN_SRC_LFO = 0x001; // linear (sine wave)
|
||||
public static final int CONN_SRC_KEYONVELOCITY = 0x002; // ??db or velocity??
|
||||
public static final int CONN_SRC_KEYNUMBER = 0x003; // ??cent or keynumber??
|
||||
public static final int CONN_SRC_EG1 = 0x004; // linear direct from eg
|
||||
public static final int CONN_SRC_EG2 = 0x005; // linear direct from eg
|
||||
public static final int CONN_SRC_PITCHWHEEL = 0x006; // linear -1..1
|
||||
public static final int CONN_SRC_CC1 = 0x081; // linear 0..1
|
||||
public static final int CONN_SRC_CC7 = 0x087; // linear 0..1
|
||||
public static final int CONN_SRC_CC10 = 0x08A; // linear 0..1
|
||||
public static final int CONN_SRC_CC11 = 0x08B; // linear 0..1
|
||||
public static final int CONN_SRC_RPN0 = 0x100; // ?? // Pitch Bend Range
|
||||
public static final int CONN_SRC_RPN1 = 0x101; // ?? // Fine Tune
|
||||
public static final int CONN_SRC_RPN2 = 0x102; // ?? // Course Tune
|
||||
// DLS2 Sources
|
||||
public static final int CONN_SRC_POLYPRESSURE = 0x007; // linear 0..1
|
||||
public static final int CONN_SRC_CHANNELPRESSURE = 0x008; // linear 0..1
|
||||
public static final int CONN_SRC_VIBRATO = 0x009; // linear 0..1
|
||||
public static final int CONN_SRC_MONOPRESSURE = 0x00A; // linear 0..1
|
||||
public static final int CONN_SRC_CC91 = 0x0DB; // linear 0..1
|
||||
public static final int CONN_SRC_CC93 = 0x0DD; // linear 0..1
|
||||
// DLS1 Transforms
|
||||
public static final int CONN_TRN_NONE = 0x000;
|
||||
public static final int CONN_TRN_CONCAVE = 0x001;
|
||||
// DLS2 Transforms
|
||||
public static final int CONN_TRN_CONVEX = 0x002;
|
||||
public static final int CONN_TRN_SWITCH = 0x003;
|
||||
public static final int DST_FORMAT_CB = 1;
|
||||
public static final int DST_FORMAT_CENT = 1;
|
||||
public static final int DST_FORMAT_TIMECENT = 2;
|
||||
public static final int DST_FORMAT_PERCENT = 3;
|
||||
int source;
|
||||
int control;
|
||||
int destination;
|
||||
int transform;
|
||||
int scale;
|
||||
int version = 1;
|
||||
|
||||
public int getControl() {
|
||||
return control;
|
||||
}
|
||||
|
||||
public void setControl(int control) {
|
||||
this.control = control;
|
||||
}
|
||||
|
||||
public static int getDestinationFormat(int destination) {
|
||||
|
||||
if (destination == CONN_DST_GAIN)
|
||||
return DST_FORMAT_CB;
|
||||
if (destination == CONN_DST_PITCH)
|
||||
return DST_FORMAT_CENT;
|
||||
if (destination == CONN_DST_PAN)
|
||||
return DST_FORMAT_PERCENT;
|
||||
|
||||
if (destination == CONN_DST_LFO_FREQUENCY)
|
||||
return DST_FORMAT_CENT;
|
||||
if (destination == CONN_DST_LFO_STARTDELAY)
|
||||
return DST_FORMAT_TIMECENT;
|
||||
|
||||
if (destination == CONN_DST_EG1_ATTACKTIME)
|
||||
return DST_FORMAT_TIMECENT;
|
||||
if (destination == CONN_DST_EG1_DECAYTIME)
|
||||
return DST_FORMAT_TIMECENT;
|
||||
if (destination == CONN_DST_EG1_RELEASETIME)
|
||||
return DST_FORMAT_TIMECENT;
|
||||
if (destination == CONN_DST_EG1_SUSTAINLEVEL)
|
||||
return DST_FORMAT_PERCENT;
|
||||
|
||||
if (destination == CONN_DST_EG2_ATTACKTIME)
|
||||
return DST_FORMAT_TIMECENT;
|
||||
if (destination == CONN_DST_EG2_DECAYTIME)
|
||||
return DST_FORMAT_TIMECENT;
|
||||
if (destination == CONN_DST_EG2_RELEASETIME)
|
||||
return DST_FORMAT_TIMECENT;
|
||||
if (destination == CONN_DST_EG2_SUSTAINLEVEL)
|
||||
return DST_FORMAT_PERCENT;
|
||||
|
||||
if (destination == CONN_DST_KEYNUMBER)
|
||||
return DST_FORMAT_CENT; // NOT SURE WITHOUT DLS 2 SPEC
|
||||
if (destination == CONN_DST_LEFT)
|
||||
return DST_FORMAT_CB;
|
||||
if (destination == CONN_DST_RIGHT)
|
||||
return DST_FORMAT_CB;
|
||||
if (destination == CONN_DST_CENTER)
|
||||
return DST_FORMAT_CB;
|
||||
if (destination == CONN_DST_LEFTREAR)
|
||||
return DST_FORMAT_CB;
|
||||
if (destination == CONN_DST_RIGHTREAR)
|
||||
return DST_FORMAT_CB;
|
||||
if (destination == CONN_DST_LFE_CHANNEL)
|
||||
return DST_FORMAT_CB;
|
||||
if (destination == CONN_DST_CHORUS)
|
||||
return DST_FORMAT_PERCENT;
|
||||
if (destination == CONN_DST_REVERB)
|
||||
return DST_FORMAT_PERCENT;
|
||||
|
||||
if (destination == CONN_DST_VIB_FREQUENCY)
|
||||
return DST_FORMAT_CENT;
|
||||
if (destination == CONN_DST_VIB_STARTDELAY)
|
||||
return DST_FORMAT_TIMECENT;
|
||||
|
||||
if (destination == CONN_DST_EG1_DELAYTIME)
|
||||
return DST_FORMAT_TIMECENT;
|
||||
if (destination == CONN_DST_EG1_HOLDTIME)
|
||||
return DST_FORMAT_TIMECENT;
|
||||
if (destination == CONN_DST_EG1_SHUTDOWNTIME)
|
||||
return DST_FORMAT_TIMECENT;
|
||||
|
||||
if (destination == CONN_DST_EG2_DELAYTIME)
|
||||
return DST_FORMAT_TIMECENT;
|
||||
if (destination == CONN_DST_EG2_HOLDTIME)
|
||||
return DST_FORMAT_TIMECENT;
|
||||
|
||||
if (destination == CONN_DST_FILTER_CUTOFF)
|
||||
return DST_FORMAT_CENT;
|
||||
if (destination == CONN_DST_FILTER_Q)
|
||||
return DST_FORMAT_CB;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static String getDestinationName(int destination) {
|
||||
|
||||
if (destination == CONN_DST_GAIN)
|
||||
return "gain";
|
||||
if (destination == CONN_DST_PITCH)
|
||||
return "pitch";
|
||||
if (destination == CONN_DST_PAN)
|
||||
return "pan";
|
||||
|
||||
if (destination == CONN_DST_LFO_FREQUENCY)
|
||||
return "lfo1.freq";
|
||||
if (destination == CONN_DST_LFO_STARTDELAY)
|
||||
return "lfo1.delay";
|
||||
|
||||
if (destination == CONN_DST_EG1_ATTACKTIME)
|
||||
return "eg1.attack";
|
||||
if (destination == CONN_DST_EG1_DECAYTIME)
|
||||
return "eg1.decay";
|
||||
if (destination == CONN_DST_EG1_RELEASETIME)
|
||||
return "eg1.release";
|
||||
if (destination == CONN_DST_EG1_SUSTAINLEVEL)
|
||||
return "eg1.sustain";
|
||||
|
||||
if (destination == CONN_DST_EG2_ATTACKTIME)
|
||||
return "eg2.attack";
|
||||
if (destination == CONN_DST_EG2_DECAYTIME)
|
||||
return "eg2.decay";
|
||||
if (destination == CONN_DST_EG2_RELEASETIME)
|
||||
return "eg2.release";
|
||||
if (destination == CONN_DST_EG2_SUSTAINLEVEL)
|
||||
return "eg2.sustain";
|
||||
|
||||
if (destination == CONN_DST_KEYNUMBER)
|
||||
return "keynumber";
|
||||
if (destination == CONN_DST_LEFT)
|
||||
return "left";
|
||||
if (destination == CONN_DST_RIGHT)
|
||||
return "right";
|
||||
if (destination == CONN_DST_CENTER)
|
||||
return "center";
|
||||
if (destination == CONN_DST_LEFTREAR)
|
||||
return "leftrear";
|
||||
if (destination == CONN_DST_RIGHTREAR)
|
||||
return "rightrear";
|
||||
if (destination == CONN_DST_LFE_CHANNEL)
|
||||
return "lfe_channel";
|
||||
if (destination == CONN_DST_CHORUS)
|
||||
return "chorus";
|
||||
if (destination == CONN_DST_REVERB)
|
||||
return "reverb";
|
||||
|
||||
if (destination == CONN_DST_VIB_FREQUENCY)
|
||||
return "vib.freq";
|
||||
if (destination == CONN_DST_VIB_STARTDELAY)
|
||||
return "vib.delay";
|
||||
|
||||
if (destination == CONN_DST_EG1_DELAYTIME)
|
||||
return "eg1.delay";
|
||||
if (destination == CONN_DST_EG1_HOLDTIME)
|
||||
return "eg1.hold";
|
||||
if (destination == CONN_DST_EG1_SHUTDOWNTIME)
|
||||
return "eg1.shutdown";
|
||||
|
||||
if (destination == CONN_DST_EG2_DELAYTIME)
|
||||
return "eg2.delay";
|
||||
if (destination == CONN_DST_EG2_HOLDTIME)
|
||||
return "eg.2hold";
|
||||
|
||||
if (destination == CONN_DST_FILTER_CUTOFF)
|
||||
return "filter.cutoff"; // NOT SURE WITHOUT DLS 2 SPEC
|
||||
if (destination == CONN_DST_FILTER_Q)
|
||||
return "filter.q"; // NOT SURE WITHOUT DLS 2 SPEC
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String getSourceName(int source) {
|
||||
|
||||
if (source == CONN_SRC_NONE)
|
||||
return "none";
|
||||
if (source == CONN_SRC_LFO)
|
||||
return "lfo";
|
||||
if (source == CONN_SRC_KEYONVELOCITY)
|
||||
return "keyonvelocity";
|
||||
if (source == CONN_SRC_KEYNUMBER)
|
||||
return "keynumber";
|
||||
if (source == CONN_SRC_EG1)
|
||||
return "eg1";
|
||||
if (source == CONN_SRC_EG2)
|
||||
return "eg2";
|
||||
if (source == CONN_SRC_PITCHWHEEL)
|
||||
return "pitchweel";
|
||||
if (source == CONN_SRC_CC1)
|
||||
return "cc1";
|
||||
if (source == CONN_SRC_CC7)
|
||||
return "cc7";
|
||||
if (source == CONN_SRC_CC10)
|
||||
return "c10";
|
||||
if (source == CONN_SRC_CC11)
|
||||
return "cc11";
|
||||
|
||||
if (source == CONN_SRC_POLYPRESSURE)
|
||||
return "polypressure";
|
||||
if (source == CONN_SRC_CHANNELPRESSURE)
|
||||
return "channelpressure";
|
||||
if (source == CONN_SRC_VIBRATO)
|
||||
return "vibrato";
|
||||
if (source == CONN_SRC_MONOPRESSURE)
|
||||
return "monopressure";
|
||||
if (source == CONN_SRC_CC91)
|
||||
return "cc91";
|
||||
if (source == CONN_SRC_CC93)
|
||||
return "cc93";
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getDestination() {
|
||||
return destination;
|
||||
}
|
||||
|
||||
public void setDestination(int destination) {
|
||||
this.destination = destination;
|
||||
}
|
||||
|
||||
public int getScale() {
|
||||
return scale;
|
||||
}
|
||||
|
||||
public void setScale(int scale) {
|
||||
this.scale = scale;
|
||||
}
|
||||
|
||||
public int getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
public void setSource(int source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public int getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(int version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public int getTransform() {
|
||||
return transform;
|
||||
}
|
||||
|
||||
public void setTransform(int transform) {
|
||||
this.transform = transform;
|
||||
}
|
||||
}
|
||||
150
jdkSrc/jdk8/com/sun/media/sound/DLSRegion.java
Normal file
150
jdkSrc/jdk8/com/sun/media/sound/DLSRegion.java
Normal file
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class is used to store region parts for instrument.
|
||||
* A region has a velocity and key range which it response to.
|
||||
* And it has a list of modulators/articulators which
|
||||
* is used how to synthesize a single voice.
|
||||
* It is stored inside a "rgn " List Chunk inside DLS files.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public final class DLSRegion {
|
||||
|
||||
public final static int OPTION_SELFNONEXCLUSIVE = 0x0001;
|
||||
List<DLSModulator> modulators = new ArrayList<DLSModulator>();
|
||||
int keyfrom;
|
||||
int keyto;
|
||||
int velfrom;
|
||||
int velto;
|
||||
int options;
|
||||
int exclusiveClass;
|
||||
int fusoptions;
|
||||
int phasegroup;
|
||||
long channel;
|
||||
DLSSample sample = null;
|
||||
DLSSampleOptions sampleoptions;
|
||||
|
||||
public List<DLSModulator> getModulators() {
|
||||
return modulators;
|
||||
}
|
||||
|
||||
public long getChannel() {
|
||||
return channel;
|
||||
}
|
||||
|
||||
public void setChannel(long channel) {
|
||||
this.channel = channel;
|
||||
}
|
||||
|
||||
public int getExclusiveClass() {
|
||||
return exclusiveClass;
|
||||
}
|
||||
|
||||
public void setExclusiveClass(int exclusiveClass) {
|
||||
this.exclusiveClass = exclusiveClass;
|
||||
}
|
||||
|
||||
public int getFusoptions() {
|
||||
return fusoptions;
|
||||
}
|
||||
|
||||
public void setFusoptions(int fusoptions) {
|
||||
this.fusoptions = fusoptions;
|
||||
}
|
||||
|
||||
public int getKeyfrom() {
|
||||
return keyfrom;
|
||||
}
|
||||
|
||||
public void setKeyfrom(int keyfrom) {
|
||||
this.keyfrom = keyfrom;
|
||||
}
|
||||
|
||||
public int getKeyto() {
|
||||
return keyto;
|
||||
}
|
||||
|
||||
public void setKeyto(int keyto) {
|
||||
this.keyto = keyto;
|
||||
}
|
||||
|
||||
public int getOptions() {
|
||||
return options;
|
||||
}
|
||||
|
||||
public void setOptions(int options) {
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
public int getPhasegroup() {
|
||||
return phasegroup;
|
||||
}
|
||||
|
||||
public void setPhasegroup(int phasegroup) {
|
||||
this.phasegroup = phasegroup;
|
||||
}
|
||||
|
||||
public DLSSample getSample() {
|
||||
return sample;
|
||||
}
|
||||
|
||||
public void setSample(DLSSample sample) {
|
||||
this.sample = sample;
|
||||
}
|
||||
|
||||
public int getVelfrom() {
|
||||
return velfrom;
|
||||
}
|
||||
|
||||
public void setVelfrom(int velfrom) {
|
||||
this.velfrom = velfrom;
|
||||
}
|
||||
|
||||
public int getVelto() {
|
||||
return velto;
|
||||
}
|
||||
|
||||
public void setVelto(int velto) {
|
||||
this.velto = velto;
|
||||
}
|
||||
|
||||
public void setModulators(List<DLSModulator> modulators) {
|
||||
this.modulators = modulators;
|
||||
}
|
||||
|
||||
public DLSSampleOptions getSampleoptions() {
|
||||
return sampleoptions;
|
||||
}
|
||||
|
||||
public void setSampleoptions(DLSSampleOptions sampleOptions) {
|
||||
this.sampleoptions = sampleOptions;
|
||||
}
|
||||
}
|
||||
123
jdkSrc/jdk8/com/sun/media/sound/DLSSample.java
Normal file
123
jdkSrc/jdk8/com/sun/media/sound/DLSSample.java
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
import javax.sound.midi.Soundbank;
|
||||
import javax.sound.midi.SoundbankResource;
|
||||
import javax.sound.sampled.AudioFormat;
|
||||
import javax.sound.sampled.AudioInputStream;
|
||||
|
||||
/**
|
||||
* This class is used to store the sample data itself.
|
||||
* A sample is encoded as PCM audio stream
|
||||
* and in DLS Level 1 files it is always a mono 8/16 bit stream.
|
||||
* They are stored just like RIFF WAVE files are stored.
|
||||
* It is stored inside a "wave" List Chunk inside DLS files.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public final class DLSSample extends SoundbankResource {
|
||||
|
||||
byte[] guid = null;
|
||||
DLSInfo info = new DLSInfo();
|
||||
DLSSampleOptions sampleoptions;
|
||||
ModelByteBuffer data;
|
||||
AudioFormat format;
|
||||
|
||||
public DLSSample(Soundbank soundBank) {
|
||||
super(soundBank, null, AudioInputStream.class);
|
||||
}
|
||||
|
||||
public DLSSample() {
|
||||
super(null, null, AudioInputStream.class);
|
||||
}
|
||||
|
||||
public DLSInfo getInfo() {
|
||||
return info;
|
||||
}
|
||||
|
||||
public Object getData() {
|
||||
AudioFormat format = getFormat();
|
||||
|
||||
InputStream is = data.getInputStream();
|
||||
if (is == null)
|
||||
return null;
|
||||
return new AudioInputStream(is, format, data.capacity());
|
||||
}
|
||||
|
||||
public ModelByteBuffer getDataBuffer() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public AudioFormat getFormat() {
|
||||
return format;
|
||||
}
|
||||
|
||||
public void setFormat(AudioFormat format) {
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
public void setData(ModelByteBuffer data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public void setData(byte[] data) {
|
||||
this.data = new ModelByteBuffer(data);
|
||||
}
|
||||
|
||||
public void setData(byte[] data, int offset, int length) {
|
||||
this.data = new ModelByteBuffer(data, offset, length);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return info.name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
info.name = name;
|
||||
}
|
||||
|
||||
public DLSSampleOptions getSampleoptions() {
|
||||
return sampleoptions;
|
||||
}
|
||||
|
||||
public void setSampleoptions(DLSSampleOptions sampleOptions) {
|
||||
this.sampleoptions = sampleOptions;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "Sample: " + info.name;
|
||||
}
|
||||
|
||||
public byte[] getGuid() {
|
||||
return guid == null ? null : Arrays.copyOf(guid, guid.length);
|
||||
}
|
||||
|
||||
public void setGuid(byte[] guid) {
|
||||
this.guid = guid == null ? null : Arrays.copyOf(guid, guid.length);
|
||||
}
|
||||
}
|
||||
63
jdkSrc/jdk8/com/sun/media/sound/DLSSampleLoop.java
Normal file
63
jdkSrc/jdk8/com/sun/media/sound/DLSSampleLoop.java
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
/**
|
||||
* This class is used to store loop points inside DLSSampleOptions class.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public final class DLSSampleLoop {
|
||||
|
||||
public final static int LOOP_TYPE_FORWARD = 0;
|
||||
public final static int LOOP_TYPE_RELEASE = 1;
|
||||
long type;
|
||||
long start;
|
||||
long length;
|
||||
|
||||
public long getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
public void setLength(long length) {
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
public long getStart() {
|
||||
return start;
|
||||
}
|
||||
|
||||
public void setStart(long start) {
|
||||
this.start = start;
|
||||
}
|
||||
|
||||
public long getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(long type) {
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
80
jdkSrc/jdk8/com/sun/media/sound/DLSSampleOptions.java
Normal file
80
jdkSrc/jdk8/com/sun/media/sound/DLSSampleOptions.java
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class stores options how to playback sampled data like pitch/tuning,
|
||||
* attenuation and loops.
|
||||
* It is stored as a "wsmp" chunk inside DLS files.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public final class DLSSampleOptions {
|
||||
|
||||
int unitynote;
|
||||
short finetune;
|
||||
int attenuation;
|
||||
long options;
|
||||
List<DLSSampleLoop> loops = new ArrayList<DLSSampleLoop>();
|
||||
|
||||
public int getAttenuation() {
|
||||
return attenuation;
|
||||
}
|
||||
|
||||
public void setAttenuation(int attenuation) {
|
||||
this.attenuation = attenuation;
|
||||
}
|
||||
|
||||
public short getFinetune() {
|
||||
return finetune;
|
||||
}
|
||||
|
||||
public void setFinetune(short finetune) {
|
||||
this.finetune = finetune;
|
||||
}
|
||||
|
||||
public List<DLSSampleLoop> getLoops() {
|
||||
return loops;
|
||||
}
|
||||
|
||||
public long getOptions() {
|
||||
return options;
|
||||
}
|
||||
|
||||
public void setOptions(long options) {
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
public int getUnitynote() {
|
||||
return unitynote;
|
||||
}
|
||||
|
||||
public void setUnitynote(int unitynote) {
|
||||
this.unitynote = unitynote;
|
||||
}
|
||||
}
|
||||
1287
jdkSrc/jdk8/com/sun/media/sound/DLSSoundbank.java
Normal file
1287
jdkSrc/jdk8/com/sun/media/sound/DLSSoundbank.java
Normal file
File diff suppressed because it is too large
Load Diff
74
jdkSrc/jdk8/com/sun/media/sound/DLSSoundbankReader.java
Normal file
74
jdkSrc/jdk8/com/sun/media/sound/DLSSoundbankReader.java
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import javax.sound.midi.InvalidMidiDataException;
|
||||
import javax.sound.midi.Soundbank;
|
||||
import javax.sound.midi.spi.SoundbankReader;
|
||||
|
||||
/**
|
||||
* This class is used to connect the DLSSoundBank class
|
||||
* to the SoundbankReader SPI interface.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public final class DLSSoundbankReader extends SoundbankReader {
|
||||
|
||||
public Soundbank getSoundbank(URL url)
|
||||
throws InvalidMidiDataException, IOException {
|
||||
try {
|
||||
return new DLSSoundbank(url);
|
||||
} catch (RIFFInvalidFormatException e) {
|
||||
return null;
|
||||
} catch(IOException ioe) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Soundbank getSoundbank(InputStream stream)
|
||||
throws InvalidMidiDataException, IOException {
|
||||
try {
|
||||
stream.mark(512);
|
||||
return new DLSSoundbank(stream);
|
||||
} catch (RIFFInvalidFormatException e) {
|
||||
stream.reset();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Soundbank getSoundbank(File file)
|
||||
throws InvalidMidiDataException, IOException {
|
||||
try {
|
||||
return new DLSSoundbank(file);
|
||||
} catch (RIFFInvalidFormatException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
246
jdkSrc/jdk8/com/sun/media/sound/DataPusher.java
Normal file
246
jdkSrc/jdk8/com/sun/media/sound/DataPusher.java
Normal file
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.sound.sampled.*;
|
||||
|
||||
/**
|
||||
* Class to write an AudioInputStream to a SourceDataLine.
|
||||
* Was previously an inner class in various classes like JavaSoundAudioClip
|
||||
* and sun.audio.AudioDevice.
|
||||
* It auto-opens and closes the SourceDataLine.
|
||||
*
|
||||
* @author Kara Kytle
|
||||
* @author Florian Bomers
|
||||
*/
|
||||
|
||||
public final class DataPusher implements Runnable {
|
||||
|
||||
private static final int AUTO_CLOSE_TIME = 5000;
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private final SourceDataLine source;
|
||||
private final AudioFormat format;
|
||||
|
||||
// stream as source data
|
||||
private final AudioInputStream ais;
|
||||
|
||||
// byte array as source data
|
||||
private final byte[] audioData;
|
||||
private final int audioDataByteLength;
|
||||
private int pos;
|
||||
private int newPos = -1;
|
||||
private boolean looping;
|
||||
|
||||
private Thread pushThread = null;
|
||||
private int wantedState;
|
||||
private int threadState;
|
||||
|
||||
private final int STATE_NONE = 0;
|
||||
private final int STATE_PLAYING = 1;
|
||||
private final int STATE_WAITING = 2;
|
||||
private final int STATE_STOPPING = 3;
|
||||
private final int STATE_STOPPED = 4;
|
||||
private final int BUFFER_SIZE = 16384;
|
||||
|
||||
public DataPusher(SourceDataLine sourceLine, AudioFormat format, byte[] audioData, int byteLength) {
|
||||
this(sourceLine, format, null, audioData, byteLength);
|
||||
}
|
||||
|
||||
public DataPusher(SourceDataLine sourceLine, AudioInputStream ais) {
|
||||
this(sourceLine, ais.getFormat(), ais, null, 0);
|
||||
}
|
||||
|
||||
private DataPusher(final SourceDataLine source, final AudioFormat format,
|
||||
final AudioInputStream ais, final byte[] audioData,
|
||||
final int audioDataByteLength) {
|
||||
this.source = source;
|
||||
this.format = format;
|
||||
this.ais = ais;
|
||||
this.audioDataByteLength = audioDataByteLength;
|
||||
this.audioData = audioData == null ? null : Arrays.copyOf(audioData,
|
||||
audioData.length);
|
||||
}
|
||||
|
||||
public synchronized void start() {
|
||||
start(false);
|
||||
}
|
||||
|
||||
public synchronized void start(boolean loop) {
|
||||
if (DEBUG || Printer.debug) Printer.debug("> DataPusher.start(loop="+loop+")");
|
||||
try {
|
||||
if (threadState == STATE_STOPPING) {
|
||||
// wait that the thread has finished stopping
|
||||
if (DEBUG || Printer.trace)Printer.trace("DataPusher.start(): calling stop()");
|
||||
stop();
|
||||
}
|
||||
looping = loop;
|
||||
newPos = 0;
|
||||
wantedState = STATE_PLAYING;
|
||||
if (!source.isOpen()) {
|
||||
if (DEBUG || Printer.trace)Printer.trace("DataPusher: source.open()");
|
||||
source.open(format);
|
||||
}
|
||||
if (DEBUG || Printer.trace)Printer.trace("DataPusher: source.flush()");
|
||||
source.flush();
|
||||
if (DEBUG || Printer.trace)Printer.trace("DataPusher: source.start()");
|
||||
source.start();
|
||||
if (pushThread == null) {
|
||||
if (DEBUG || Printer.debug) Printer.debug("DataPusher.start(): Starting push");
|
||||
pushThread = JSSecurityManager.createThread(this,
|
||||
null, // name
|
||||
false, // daemon
|
||||
-1, // priority
|
||||
true); // doStart
|
||||
}
|
||||
notifyAll();
|
||||
} catch (Exception e) {
|
||||
if (DEBUG || Printer.err) e.printStackTrace();
|
||||
}
|
||||
if (DEBUG || Printer.debug) Printer.debug("< DataPusher.start(loop="+loop+")");
|
||||
}
|
||||
|
||||
|
||||
public synchronized void stop() {
|
||||
if (DEBUG || Printer.debug) Printer.debug("> DataPusher.stop()");
|
||||
if (threadState == STATE_STOPPING
|
||||
|| threadState == STATE_STOPPED
|
||||
|| pushThread == null) {
|
||||
if (DEBUG || Printer.debug) Printer.debug("DataPusher.stop(): nothing to do");
|
||||
return;
|
||||
}
|
||||
if (DEBUG || Printer.debug) Printer.debug("DataPusher.stop(): Stopping push");
|
||||
|
||||
wantedState = STATE_WAITING;
|
||||
if (source != null) {
|
||||
if (DEBUG || Printer.trace)Printer.trace("DataPusher: source.flush()");
|
||||
source.flush();
|
||||
}
|
||||
notifyAll();
|
||||
int maxWaitCount = 50; // 5 seconds
|
||||
while ((maxWaitCount-- >= 0) && (threadState == STATE_PLAYING)) {
|
||||
try {
|
||||
wait(100);
|
||||
} catch (InterruptedException e) { }
|
||||
}
|
||||
if (DEBUG || Printer.debug) Printer.debug("< DataPusher.stop()");
|
||||
}
|
||||
|
||||
synchronized void close() {
|
||||
if (source != null) {
|
||||
if (DEBUG || Printer.trace)Printer.trace("DataPusher.close(): source.close()");
|
||||
source.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write data to the source data line.
|
||||
*/
|
||||
public void run() {
|
||||
byte[] buffer = null;
|
||||
boolean useStream = (ais != null);
|
||||
if (useStream) {
|
||||
buffer = new byte[BUFFER_SIZE];
|
||||
} else {
|
||||
buffer = audioData;
|
||||
}
|
||||
while (wantedState != STATE_STOPPING) {
|
||||
//try {
|
||||
if (wantedState == STATE_WAITING) {
|
||||
// wait for 5 seconds - maybe the clip is to be played again
|
||||
if (DEBUG || Printer.debug)Printer.debug("DataPusher.run(): waiting 5 seconds");
|
||||
try {
|
||||
synchronized(this) {
|
||||
threadState = STATE_WAITING;
|
||||
wantedState = STATE_STOPPING;
|
||||
wait(AUTO_CLOSE_TIME);
|
||||
}
|
||||
} catch (InterruptedException ie) {}
|
||||
if (DEBUG || Printer.debug)Printer.debug("DataPusher.run(): waiting finished");
|
||||
continue;
|
||||
}
|
||||
if (newPos >= 0) {
|
||||
pos = newPos;
|
||||
newPos = -1;
|
||||
}
|
||||
threadState = STATE_PLAYING;
|
||||
int toWrite = BUFFER_SIZE;
|
||||
if (useStream) {
|
||||
try {
|
||||
pos = 0; // always write from beginning of buffer
|
||||
// don't use read(byte[]), because some streams
|
||||
// may not override that method
|
||||
toWrite = ais.read(buffer, 0, buffer.length);
|
||||
} catch (java.io.IOException ioe) {
|
||||
// end of stream
|
||||
toWrite = -1;
|
||||
}
|
||||
} else {
|
||||
if (toWrite > audioDataByteLength - pos) {
|
||||
toWrite = audioDataByteLength - pos;
|
||||
}
|
||||
if (toWrite == 0) {
|
||||
toWrite = -1; // end of "stream"
|
||||
}
|
||||
}
|
||||
if (toWrite < 0) {
|
||||
if (DEBUG || Printer.debug) Printer.debug("DataPusher.run(): Found end of stream");
|
||||
if (!useStream && looping) {
|
||||
if (DEBUG || Printer.debug)Printer.debug("DataPusher.run(): setting pos back to 0");
|
||||
pos = 0;
|
||||
continue;
|
||||
}
|
||||
if (DEBUG || Printer.debug)Printer.debug("DataPusher.run(): calling drain()");
|
||||
wantedState = STATE_WAITING;
|
||||
source.drain();
|
||||
continue;
|
||||
}
|
||||
if (DEBUG || Printer.debug) Printer.debug("> DataPusher.run(): Writing " + toWrite + " bytes");
|
||||
int bytesWritten = source.write(buffer, pos, toWrite);
|
||||
pos += bytesWritten;
|
||||
if (DEBUG || Printer.debug) Printer.debug("< DataPusher.run(): Wrote " + bytesWritten + " bytes");
|
||||
}
|
||||
threadState = STATE_STOPPING;
|
||||
if (DEBUG || Printer.debug)Printer.debug("DataPusher: closing device");
|
||||
if (Printer.trace)Printer.trace("DataPusher: source.flush()");
|
||||
source.flush();
|
||||
if (DEBUG || Printer.trace)Printer.trace("DataPusher: source.stop()");
|
||||
source.stop();
|
||||
if (DEBUG || Printer.trace)Printer.trace("DataPusher: source.flush()");
|
||||
source.flush();
|
||||
if (DEBUG || Printer.trace)Printer.trace("DataPusher: source.close()");
|
||||
source.close();
|
||||
threadState = STATE_STOPPED;
|
||||
synchronized (this) {
|
||||
pushThread = null;
|
||||
notifyAll();
|
||||
}
|
||||
if (DEBUG || Printer.debug)Printer.debug("DataPusher:end of thread");
|
||||
}
|
||||
|
||||
} // class DataPusher
|
||||
1512
jdkSrc/jdk8/com/sun/media/sound/DirectAudioDevice.java
Normal file
1512
jdkSrc/jdk8/com/sun/media/sound/DirectAudioDevice.java
Normal file
File diff suppressed because it is too large
Load Diff
177
jdkSrc/jdk8/com/sun/media/sound/DirectAudioDeviceProvider.java
Normal file
177
jdkSrc/jdk8/com/sun/media/sound/DirectAudioDeviceProvider.java
Normal file
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.media.sound;
|
||||
|
||||
import javax.sound.sampled.Mixer;
|
||||
import javax.sound.sampled.spi.MixerProvider;
|
||||
|
||||
|
||||
/**
|
||||
* DirectAudioDevice provider.
|
||||
*
|
||||
* @author Florian Bomers
|
||||
*/
|
||||
public final class DirectAudioDeviceProvider extends MixerProvider {
|
||||
|
||||
// STATIC VARIABLES
|
||||
|
||||
/**
|
||||
* Set of info objects for all port input devices on the system.
|
||||
*/
|
||||
private static DirectAudioDeviceInfo[] infos;
|
||||
|
||||
/**
|
||||
* Set of all port input devices on the system.
|
||||
*/
|
||||
private static DirectAudioDevice[] devices;
|
||||
|
||||
|
||||
// STATIC
|
||||
|
||||
static {
|
||||
// initialize
|
||||
Platform.initialize();
|
||||
}
|
||||
|
||||
|
||||
// CONSTRUCTOR
|
||||
|
||||
|
||||
/**
|
||||
* Required public no-arg constructor.
|
||||
*/
|
||||
public DirectAudioDeviceProvider() {
|
||||
synchronized (DirectAudioDeviceProvider.class) {
|
||||
if (Platform.isDirectAudioEnabled()) {
|
||||
init();
|
||||
} else {
|
||||
infos = new DirectAudioDeviceInfo[0];
|
||||
devices = new DirectAudioDevice[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void init() {
|
||||
// get the number of input devices
|
||||
int numDevices = nGetNumDevices();
|
||||
|
||||
if (infos == null || infos.length != numDevices) {
|
||||
if (Printer.trace) Printer.trace("DirectAudioDeviceProvider: init()");
|
||||
// initialize the arrays
|
||||
infos = new DirectAudioDeviceInfo[numDevices];
|
||||
devices = new DirectAudioDevice[numDevices];
|
||||
|
||||
// fill in the info objects now.
|
||||
for (int i = 0; i < infos.length; i++) {
|
||||
infos[i] = nNewDirectAudioDeviceInfo(i);
|
||||
}
|
||||
if (Printer.trace) Printer.trace("DirectAudioDeviceProvider: init(): found numDevices: " + numDevices);
|
||||
}
|
||||
}
|
||||
|
||||
public Mixer.Info[] getMixerInfo() {
|
||||
synchronized (DirectAudioDeviceProvider.class) {
|
||||
Mixer.Info[] localArray = new Mixer.Info[infos.length];
|
||||
System.arraycopy(infos, 0, localArray, 0, infos.length);
|
||||
return localArray;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Mixer getMixer(Mixer.Info info) {
|
||||
synchronized (DirectAudioDeviceProvider.class) {
|
||||
// if the default device is asked, we provide the mixer
|
||||
// with SourceDataLine's
|
||||
if (info == null) {
|
||||
for (int i = 0; i < infos.length; i++) {
|
||||
Mixer mixer = getDevice(infos[i]);
|
||||
if (mixer.getSourceLineInfo().length > 0) {
|
||||
return mixer;
|
||||
}
|
||||
}
|
||||
}
|
||||
// otherwise get the first mixer that matches
|
||||
// the requested info object
|
||||
for (int i = 0; i < infos.length; i++) {
|
||||
if (infos[i].equals(info)) {
|
||||
return getDevice(infos[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Mixer " + info.toString() + " not supported by this provider.");
|
||||
}
|
||||
|
||||
|
||||
private static Mixer getDevice(DirectAudioDeviceInfo info) {
|
||||
int index = info.getIndex();
|
||||
if (devices[index] == null) {
|
||||
devices[index] = new DirectAudioDevice(info);
|
||||
}
|
||||
return devices[index];
|
||||
}
|
||||
|
||||
// INNER CLASSES
|
||||
|
||||
|
||||
/**
|
||||
* Info class for DirectAudioDevices. Adds an index value and a string for
|
||||
* making native references to a particular device.
|
||||
* This constructor is called from native.
|
||||
*/
|
||||
static final class DirectAudioDeviceInfo extends Mixer.Info {
|
||||
private final int index;
|
||||
private final int maxSimulLines;
|
||||
|
||||
// For ALSA, the deviceID contains the encoded card index, device index, and sub-device-index
|
||||
private final int deviceID;
|
||||
|
||||
private DirectAudioDeviceInfo(int index, int deviceID, int maxSimulLines,
|
||||
String name, String vendor,
|
||||
String description, String version) {
|
||||
super(name, vendor, "Direct Audio Device: "+description, version);
|
||||
this.index = index;
|
||||
this.maxSimulLines = maxSimulLines;
|
||||
this.deviceID = deviceID;
|
||||
}
|
||||
|
||||
int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
int getMaxSimulLines() {
|
||||
return maxSimulLines;
|
||||
}
|
||||
|
||||
int getDeviceID() {
|
||||
return deviceID;
|
||||
}
|
||||
} // class DirectAudioDeviceInfo
|
||||
|
||||
// NATIVE METHODS
|
||||
private static native int nGetNumDevices();
|
||||
// index: [0..nGetNumDevices()-1]
|
||||
private static native DirectAudioDeviceInfo nNewDirectAudioDeviceInfo(int deviceIndex);
|
||||
}
|
||||
2695
jdkSrc/jdk8/com/sun/media/sound/EmergencySoundbank.java
Normal file
2695
jdkSrc/jdk8/com/sun/media/sound/EmergencySoundbank.java
Normal file
File diff suppressed because it is too large
Load Diff
457
jdkSrc/jdk8/com/sun/media/sound/EventDispatcher.java
Normal file
457
jdkSrc/jdk8/com/sun/media/sound/EventDispatcher.java
Normal file
@@ -0,0 +1,457 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.sound.midi.ControllerEventListener;
|
||||
import javax.sound.midi.MetaEventListener;
|
||||
import javax.sound.midi.MetaMessage;
|
||||
import javax.sound.midi.ShortMessage;
|
||||
import javax.sound.sampled.LineEvent;
|
||||
import javax.sound.sampled.LineListener;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* EventDispatcher. Used by various classes in the Java Sound implementation
|
||||
* to send events.
|
||||
*
|
||||
* @author David Rivas
|
||||
* @author Kara Kytle
|
||||
* @author Florian Bomers
|
||||
*/
|
||||
final class EventDispatcher implements Runnable {
|
||||
|
||||
/**
|
||||
* time of inactivity until the auto closing clips
|
||||
* are closed
|
||||
*/
|
||||
private static final int AUTO_CLOSE_TIME = 5000;
|
||||
|
||||
|
||||
/**
|
||||
* List of events
|
||||
*/
|
||||
private final ArrayList eventQueue = new ArrayList();
|
||||
|
||||
|
||||
/**
|
||||
* Thread object for this EventDispatcher instance
|
||||
*/
|
||||
private Thread thread = null;
|
||||
|
||||
|
||||
/*
|
||||
* support for auto-closing Clips
|
||||
*/
|
||||
private final ArrayList<ClipInfo> autoClosingClips = new ArrayList<ClipInfo>();
|
||||
|
||||
/*
|
||||
* support for monitoring data lines
|
||||
*/
|
||||
private final ArrayList<LineMonitor> lineMonitors = new ArrayList<LineMonitor>();
|
||||
|
||||
/**
|
||||
* Approximate interval between calls to LineMonitor.checkLine
|
||||
*/
|
||||
static final int LINE_MONITOR_TIME = 400;
|
||||
|
||||
|
||||
/**
|
||||
* This start() method starts an event thread if one is not already active.
|
||||
*/
|
||||
synchronized void start() {
|
||||
|
||||
if(thread == null) {
|
||||
thread = JSSecurityManager.createThread(this,
|
||||
"Java Sound Event Dispatcher", // name
|
||||
true, // daemon
|
||||
-1, // priority
|
||||
true); // doStart
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Invoked when there is at least one event in the queue.
|
||||
* Implement this as a callback to process one event.
|
||||
*/
|
||||
void processEvent(EventInfo eventInfo) {
|
||||
int count = eventInfo.getListenerCount();
|
||||
|
||||
// process an LineEvent
|
||||
if (eventInfo.getEvent() instanceof LineEvent) {
|
||||
LineEvent event = (LineEvent) eventInfo.getEvent();
|
||||
if (Printer.debug) Printer.debug("Sending "+event+" to "+count+" listeners");
|
||||
for (int i = 0; i < count; i++) {
|
||||
try {
|
||||
((LineListener) eventInfo.getListener(i)).update(event);
|
||||
} catch (Throwable t) {
|
||||
if (Printer.err) t.printStackTrace();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// process a MetaMessage
|
||||
if (eventInfo.getEvent() instanceof MetaMessage) {
|
||||
MetaMessage event = (MetaMessage)eventInfo.getEvent();
|
||||
for (int i = 0; i < count; i++) {
|
||||
try {
|
||||
((MetaEventListener) eventInfo.getListener(i)).meta(event);
|
||||
} catch (Throwable t) {
|
||||
if (Printer.err) t.printStackTrace();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// process a Controller or Mode Event
|
||||
if (eventInfo.getEvent() instanceof ShortMessage) {
|
||||
ShortMessage event = (ShortMessage)eventInfo.getEvent();
|
||||
int status = event.getStatus();
|
||||
|
||||
// Controller and Mode events have status byte 0xBc, where
|
||||
// c is the channel they are sent on.
|
||||
if ((status & 0xF0) == 0xB0) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
try {
|
||||
((ControllerEventListener) eventInfo.getListener(i)).controlChange(event);
|
||||
} catch (Throwable t) {
|
||||
if (Printer.err) t.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Printer.err("Unknown event type: " + eventInfo.getEvent());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Wait until there is something in the event queue to process. Then
|
||||
* dispatch the event to the listeners.The entire method does not
|
||||
* need to be synchronized since this includes taking the event out
|
||||
* from the queue and processing the event. We only need to provide
|
||||
* exclusive access over the code where an event is removed from the
|
||||
*queue.
|
||||
*/
|
||||
void dispatchEvents() {
|
||||
|
||||
EventInfo eventInfo = null;
|
||||
|
||||
synchronized (this) {
|
||||
|
||||
// Wait till there is an event in the event queue.
|
||||
try {
|
||||
|
||||
if (eventQueue.size() == 0) {
|
||||
if (autoClosingClips.size() > 0 || lineMonitors.size() > 0) {
|
||||
int waitTime = AUTO_CLOSE_TIME;
|
||||
if (lineMonitors.size() > 0) {
|
||||
waitTime = LINE_MONITOR_TIME;
|
||||
}
|
||||
wait(waitTime);
|
||||
} else {
|
||||
wait();
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
if (eventQueue.size() > 0) {
|
||||
// Remove the event from the queue and dispatch it to the listeners.
|
||||
eventInfo = (EventInfo) eventQueue.remove(0);
|
||||
}
|
||||
|
||||
} // end of synchronized
|
||||
if (eventInfo != null) {
|
||||
processEvent(eventInfo);
|
||||
} else {
|
||||
if (autoClosingClips.size() > 0) {
|
||||
closeAutoClosingClips();
|
||||
}
|
||||
if (lineMonitors.size() > 0) {
|
||||
monitorLines();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Queue the given event in the event queue.
|
||||
*/
|
||||
private synchronized void postEvent(EventInfo eventInfo) {
|
||||
eventQueue.add(eventInfo);
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A loop to dispatch events.
|
||||
*/
|
||||
public void run() {
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
dispatchEvents();
|
||||
} catch (Throwable t) {
|
||||
if (Printer.err) t.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send audio and MIDI events.
|
||||
*/
|
||||
void sendAudioEvents(Object event, List listeners) {
|
||||
if ((listeners == null)
|
||||
|| (listeners.size() == 0)) {
|
||||
// nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
start();
|
||||
|
||||
EventInfo eventInfo = new EventInfo(event, listeners);
|
||||
postEvent(eventInfo);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* go through the list of registered auto-closing
|
||||
* Clip instances and close them, if appropriate
|
||||
*
|
||||
* This method is called in regular intervals
|
||||
*/
|
||||
private void closeAutoClosingClips() {
|
||||
synchronized(autoClosingClips) {
|
||||
if (Printer.debug)Printer.debug("> EventDispatcher.closeAutoClosingClips ("+autoClosingClips.size()+" clips)");
|
||||
long currTime = System.currentTimeMillis();
|
||||
for (int i = autoClosingClips.size()-1; i >= 0 ; i--) {
|
||||
ClipInfo info = autoClosingClips.get(i);
|
||||
if (info.isExpired(currTime)) {
|
||||
AutoClosingClip clip = info.getClip();
|
||||
// sanity check
|
||||
if (!clip.isOpen() || !clip.isAutoClosing()) {
|
||||
if (Printer.debug)Printer.debug("EventDispatcher: removing clip "+clip+" isOpen:"+clip.isOpen());
|
||||
autoClosingClips.remove(i);
|
||||
}
|
||||
else if (!clip.isRunning() && !clip.isActive() && clip.isAutoClosing()) {
|
||||
if (Printer.debug)Printer.debug("EventDispatcher: closing clip "+clip);
|
||||
clip.close();
|
||||
} else {
|
||||
if (Printer.debug)Printer.debug("Doing nothing with clip "+clip+":");
|
||||
if (Printer.debug)Printer.debug(" open="+clip.isOpen()+", autoclosing="+clip.isAutoClosing());
|
||||
if (Printer.debug)Printer.debug(" isRunning="+clip.isRunning()+", isActive="+clip.isActive());
|
||||
}
|
||||
} else {
|
||||
if (Printer.debug)Printer.debug("EventDispatcher: clip "+info.getClip()+" not yet expired");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Printer.debug)Printer.debug("< EventDispatcher.closeAutoClosingClips ("+autoClosingClips.size()+" clips)");
|
||||
}
|
||||
|
||||
private int getAutoClosingClipIndex(AutoClosingClip clip) {
|
||||
synchronized(autoClosingClips) {
|
||||
for (int i = autoClosingClips.size()-1; i >= 0; i--) {
|
||||
if (clip.equals(autoClosingClips.get(i).getClip())) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* called from auto-closing clips when one of their open() method is called
|
||||
*/
|
||||
void autoClosingClipOpened(AutoClosingClip clip) {
|
||||
if (Printer.debug)Printer.debug("> EventDispatcher.autoClosingClipOpened ");
|
||||
int index = 0;
|
||||
synchronized(autoClosingClips) {
|
||||
index = getAutoClosingClipIndex(clip);
|
||||
if (index == -1) {
|
||||
if (Printer.debug)Printer.debug("EventDispatcher: adding auto-closing clip "+clip);
|
||||
autoClosingClips.add(new ClipInfo(clip));
|
||||
}
|
||||
}
|
||||
if (index == -1) {
|
||||
synchronized (this) {
|
||||
// this is only for the case that the first clip is set to autoclosing,
|
||||
// and it is already open, and nothing is done with it.
|
||||
// EventDispatcher.process() method would block in wait() and
|
||||
// never close this first clip, keeping the device open.
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
if (Printer.debug)Printer.debug("< EventDispatcher.autoClosingClipOpened finished("+autoClosingClips.size()+" clips)");
|
||||
}
|
||||
|
||||
/**
|
||||
* called from auto-closing clips when their closed() method is called
|
||||
*/
|
||||
void autoClosingClipClosed(AutoClosingClip clip) {
|
||||
synchronized(autoClosingClips) {
|
||||
int index = getAutoClosingClipIndex(clip);
|
||||
if (index != -1) {
|
||||
autoClosingClips.remove(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ////////////////////////// Line Monitoring Support /////////////////// //
|
||||
/*
|
||||
* go through the list of registered line monitors
|
||||
* and call their checkLine method
|
||||
*
|
||||
* This method is called in regular intervals
|
||||
*/
|
||||
private void monitorLines() {
|
||||
synchronized(lineMonitors) {
|
||||
if (Printer.debug)Printer.debug("> EventDispatcher.monitorLines ("+lineMonitors.size()+" monitors)");
|
||||
for (int i = 0; i < lineMonitors.size(); i++) {
|
||||
lineMonitors.get(i).checkLine();
|
||||
}
|
||||
}
|
||||
if (Printer.debug)Printer.debug("< EventDispatcher.monitorLines("+lineMonitors.size()+" monitors)");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add this LineMonitor instance to the list of monitors
|
||||
*/
|
||||
void addLineMonitor(LineMonitor lm) {
|
||||
if (Printer.trace)Printer.trace("> EventDispatcher.addLineMonitor("+lm+")");
|
||||
synchronized(lineMonitors) {
|
||||
if (lineMonitors.indexOf(lm) >= 0) {
|
||||
if (Printer.trace)Printer.trace("< EventDispatcher.addLineMonitor finished -- this monitor already exists!");
|
||||
return;
|
||||
}
|
||||
if (Printer.debug)Printer.debug("EventDispatcher: adding line monitor "+lm);
|
||||
lineMonitors.add(lm);
|
||||
}
|
||||
synchronized (this) {
|
||||
// need to interrupt the infinite wait()
|
||||
notifyAll();
|
||||
}
|
||||
if (Printer.debug)Printer.debug("< EventDispatcher.addLineMonitor finished -- now ("+lineMonitors.size()+" monitors)");
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove this LineMonitor instance from the list of monitors
|
||||
*/
|
||||
void removeLineMonitor(LineMonitor lm) {
|
||||
if (Printer.trace)Printer.trace("> EventDispatcher.removeLineMonitor("+lm+")");
|
||||
synchronized(lineMonitors) {
|
||||
if (lineMonitors.indexOf(lm) < 0) {
|
||||
if (Printer.trace)Printer.trace("< EventDispatcher.removeLineMonitor finished -- this monitor does not exist!");
|
||||
return;
|
||||
}
|
||||
if (Printer.debug)Printer.debug("EventDispatcher: removing line monitor "+lm);
|
||||
lineMonitors.remove(lm);
|
||||
}
|
||||
if (Printer.debug)Printer.debug("< EventDispatcher.removeLineMonitor finished -- now ("+lineMonitors.size()+" monitors)");
|
||||
}
|
||||
|
||||
// /////////////////////////////////// INNER CLASSES ////////////////////////////////////////// //
|
||||
|
||||
/**
|
||||
* Container for an event and a set of listeners to deliver it to.
|
||||
*/
|
||||
private class EventInfo {
|
||||
|
||||
private final Object event;
|
||||
private final Object[] listeners;
|
||||
|
||||
/**
|
||||
* Create a new instance of this event Info class
|
||||
* @param event the event to be dispatched
|
||||
* @param listeners listener list; will be copied
|
||||
*/
|
||||
EventInfo(Object event, List listeners) {
|
||||
this.event = event;
|
||||
this.listeners = listeners.toArray();
|
||||
}
|
||||
|
||||
Object getEvent() {
|
||||
return event;
|
||||
}
|
||||
|
||||
int getListenerCount() {
|
||||
return listeners.length;
|
||||
}
|
||||
|
||||
Object getListener(int index) {
|
||||
return listeners[index];
|
||||
}
|
||||
|
||||
} // class EventInfo
|
||||
|
||||
|
||||
/**
|
||||
* Container for a clip with its expiration time
|
||||
*/
|
||||
private class ClipInfo {
|
||||
|
||||
private final AutoClosingClip clip;
|
||||
private final long expiration;
|
||||
|
||||
/**
|
||||
* Create a new instance of this clip Info class
|
||||
*/
|
||||
ClipInfo(AutoClosingClip clip) {
|
||||
this.clip = clip;
|
||||
this.expiration = System.currentTimeMillis() + AUTO_CLOSE_TIME;
|
||||
}
|
||||
|
||||
AutoClosingClip getClip() {
|
||||
return clip;
|
||||
}
|
||||
|
||||
boolean isExpired(long currTime) {
|
||||
return currTime > expiration;
|
||||
}
|
||||
} // class ClipInfo
|
||||
|
||||
|
||||
/**
|
||||
* Interface that a class that wants to get regular
|
||||
* line monitor events implements
|
||||
*/
|
||||
interface LineMonitor {
|
||||
/**
|
||||
* Called by event dispatcher in regular intervals
|
||||
*/
|
||||
public void checkLine();
|
||||
}
|
||||
|
||||
} // class EventDispatcher
|
||||
748
jdkSrc/jdk8/com/sun/media/sound/FFT.java
Normal file
748
jdkSrc/jdk8/com/sun/media/sound/FFT.java
Normal file
@@ -0,0 +1,748 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
/**
|
||||
* Fast Fourier Transformer.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public final class FFT {
|
||||
|
||||
private final double[] w;
|
||||
private final int fftFrameSize;
|
||||
private final int sign;
|
||||
private final int[] bitm_array;
|
||||
private final int fftFrameSize2;
|
||||
|
||||
// Sign = -1 is FFT, 1 is IFFT (inverse FFT)
|
||||
// Data = Interlaced double array to be transformed.
|
||||
// The order is: real (sin), complex (cos)
|
||||
// Framesize must be power of 2
|
||||
public FFT(int fftFrameSize, int sign) {
|
||||
w = computeTwiddleFactors(fftFrameSize, sign);
|
||||
|
||||
this.fftFrameSize = fftFrameSize;
|
||||
this.sign = sign;
|
||||
fftFrameSize2 = fftFrameSize << 1;
|
||||
|
||||
// Pre-process Bit-Reversal
|
||||
bitm_array = new int[fftFrameSize2];
|
||||
for (int i = 2; i < fftFrameSize2; i += 2) {
|
||||
int j;
|
||||
int bitm;
|
||||
for (bitm = 2, j = 0; bitm < fftFrameSize2; bitm <<= 1) {
|
||||
if ((i & bitm) != 0)
|
||||
j++;
|
||||
j <<= 1;
|
||||
}
|
||||
bitm_array[i] = j;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void transform(double[] data) {
|
||||
bitreversal(data);
|
||||
calc(fftFrameSize, data, sign, w);
|
||||
}
|
||||
|
||||
private final static double[] computeTwiddleFactors(int fftFrameSize,
|
||||
int sign) {
|
||||
|
||||
int imax = (int) (Math.log(fftFrameSize) / Math.log(2.));
|
||||
|
||||
double[] warray = new double[(fftFrameSize - 1) * 4];
|
||||
int w_index = 0;
|
||||
|
||||
for (int i = 0, nstep = 2; i < imax; i++) {
|
||||
int jmax = nstep;
|
||||
nstep <<= 1;
|
||||
|
||||
double wr = 1.0;
|
||||
double wi = 0.0;
|
||||
|
||||
double arg = Math.PI / (jmax >> 1);
|
||||
double wfr = Math.cos(arg);
|
||||
double wfi = sign * Math.sin(arg);
|
||||
|
||||
for (int j = 0; j < jmax; j += 2) {
|
||||
warray[w_index++] = wr;
|
||||
warray[w_index++] = wi;
|
||||
|
||||
double tempr = wr;
|
||||
wr = tempr * wfr - wi * wfi;
|
||||
wi = tempr * wfi + wi * wfr;
|
||||
}
|
||||
}
|
||||
|
||||
// PRECOMPUTATION of wwr1, wwi1 for factor 4 Decomposition (3 * complex
|
||||
// operators and 8 +/- complex operators)
|
||||
{
|
||||
w_index = 0;
|
||||
int w_index2 = warray.length >> 1;
|
||||
for (int i = 0, nstep = 2; i < (imax - 1); i++) {
|
||||
int jmax = nstep;
|
||||
nstep *= 2;
|
||||
|
||||
int ii = w_index + jmax;
|
||||
for (int j = 0; j < jmax; j += 2) {
|
||||
double wr = warray[w_index++];
|
||||
double wi = warray[w_index++];
|
||||
double wr1 = warray[ii++];
|
||||
double wi1 = warray[ii++];
|
||||
warray[w_index2++] = wr * wr1 - wi * wi1;
|
||||
warray[w_index2++] = wr * wi1 + wi * wr1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return warray;
|
||||
}
|
||||
|
||||
private final static void calc(int fftFrameSize, double[] data, int sign,
|
||||
double[] w) {
|
||||
|
||||
final int fftFrameSize2 = fftFrameSize << 1;
|
||||
|
||||
int nstep = 2;
|
||||
|
||||
if (nstep >= fftFrameSize2)
|
||||
return;
|
||||
int i = nstep - 2;
|
||||
if (sign == -1)
|
||||
calcF4F(fftFrameSize, data, i, nstep, w);
|
||||
else
|
||||
calcF4I(fftFrameSize, data, i, nstep, w);
|
||||
|
||||
}
|
||||
|
||||
private final static void calcF2E(int fftFrameSize, double[] data, int i,
|
||||
int nstep, double[] w) {
|
||||
int jmax = nstep;
|
||||
for (int n = 0; n < jmax; n += 2) {
|
||||
double wr = w[i++];
|
||||
double wi = w[i++];
|
||||
int m = n + jmax;
|
||||
double datam_r = data[m];
|
||||
double datam_i = data[m + 1];
|
||||
double datan_r = data[n];
|
||||
double datan_i = data[n + 1];
|
||||
double tempr = datam_r * wr - datam_i * wi;
|
||||
double tempi = datam_r * wi + datam_i * wr;
|
||||
data[m] = datan_r - tempr;
|
||||
data[m + 1] = datan_i - tempi;
|
||||
data[n] = datan_r + tempr;
|
||||
data[n + 1] = datan_i + tempi;
|
||||
}
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
// Perform Factor-4 Decomposition with 3 * complex operators and 8 +/-
|
||||
// complex operators
|
||||
private final static void calcF4F(int fftFrameSize, double[] data, int i,
|
||||
int nstep, double[] w) {
|
||||
final int fftFrameSize2 = fftFrameSize << 1; // 2*fftFrameSize;
|
||||
// Factor-4 Decomposition
|
||||
|
||||
int w_len = w.length >> 1;
|
||||
while (nstep < fftFrameSize2) {
|
||||
|
||||
if (nstep << 2 == fftFrameSize2) {
|
||||
// Goto Factor-4 Final Decomposition
|
||||
// calcF4E(data, i, nstep, -1, w);
|
||||
calcF4FE(fftFrameSize, data, i, nstep, w);
|
||||
return;
|
||||
}
|
||||
int jmax = nstep;
|
||||
int nnstep = nstep << 1;
|
||||
if (nnstep == fftFrameSize2) {
|
||||
// Factor-4 Decomposition not possible
|
||||
calcF2E(fftFrameSize, data, i, nstep, w);
|
||||
return;
|
||||
}
|
||||
nstep <<= 2;
|
||||
int ii = i + jmax;
|
||||
int iii = i + w_len;
|
||||
|
||||
{
|
||||
i += 2;
|
||||
ii += 2;
|
||||
iii += 2;
|
||||
|
||||
for (int n = 0; n < fftFrameSize2; n += nstep) {
|
||||
int m = n + jmax;
|
||||
|
||||
double datam1_r = data[m];
|
||||
double datam1_i = data[m + 1];
|
||||
double datan1_r = data[n];
|
||||
double datan1_i = data[n + 1];
|
||||
|
||||
n += nnstep;
|
||||
m += nnstep;
|
||||
double datam2_r = data[m];
|
||||
double datam2_i = data[m + 1];
|
||||
double datan2_r = data[n];
|
||||
double datan2_i = data[n + 1];
|
||||
|
||||
double tempr = datam1_r;
|
||||
double tempi = datam1_i;
|
||||
|
||||
datam1_r = datan1_r - tempr;
|
||||
datam1_i = datan1_i - tempi;
|
||||
datan1_r = datan1_r + tempr;
|
||||
datan1_i = datan1_i + tempi;
|
||||
|
||||
double n2w1r = datan2_r;
|
||||
double n2w1i = datan2_i;
|
||||
double m2ww1r = datam2_r;
|
||||
double m2ww1i = datam2_i;
|
||||
|
||||
tempr = m2ww1r - n2w1r;
|
||||
tempi = m2ww1i - n2w1i;
|
||||
|
||||
datam2_r = datam1_r + tempi;
|
||||
datam2_i = datam1_i - tempr;
|
||||
datam1_r = datam1_r - tempi;
|
||||
datam1_i = datam1_i + tempr;
|
||||
|
||||
tempr = n2w1r + m2ww1r;
|
||||
tempi = n2w1i + m2ww1i;
|
||||
|
||||
datan2_r = datan1_r - tempr;
|
||||
datan2_i = datan1_i - tempi;
|
||||
datan1_r = datan1_r + tempr;
|
||||
datan1_i = datan1_i + tempi;
|
||||
|
||||
data[m] = datam2_r;
|
||||
data[m + 1] = datam2_i;
|
||||
data[n] = datan2_r;
|
||||
data[n + 1] = datan2_i;
|
||||
|
||||
n -= nnstep;
|
||||
m -= nnstep;
|
||||
data[m] = datam1_r;
|
||||
data[m + 1] = datam1_i;
|
||||
data[n] = datan1_r;
|
||||
data[n + 1] = datan1_i;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 2; j < jmax; j += 2) {
|
||||
double wr = w[i++];
|
||||
double wi = w[i++];
|
||||
double wr1 = w[ii++];
|
||||
double wi1 = w[ii++];
|
||||
double wwr1 = w[iii++];
|
||||
double wwi1 = w[iii++];
|
||||
// double wwr1 = wr * wr1 - wi * wi1; // these numbers can be
|
||||
// precomputed!!!
|
||||
// double wwi1 = wr * wi1 + wi * wr1;
|
||||
|
||||
for (int n = j; n < fftFrameSize2; n += nstep) {
|
||||
int m = n + jmax;
|
||||
|
||||
double datam1_r = data[m];
|
||||
double datam1_i = data[m + 1];
|
||||
double datan1_r = data[n];
|
||||
double datan1_i = data[n + 1];
|
||||
|
||||
n += nnstep;
|
||||
m += nnstep;
|
||||
double datam2_r = data[m];
|
||||
double datam2_i = data[m + 1];
|
||||
double datan2_r = data[n];
|
||||
double datan2_i = data[n + 1];
|
||||
|
||||
double tempr = datam1_r * wr - datam1_i * wi;
|
||||
double tempi = datam1_r * wi + datam1_i * wr;
|
||||
|
||||
datam1_r = datan1_r - tempr;
|
||||
datam1_i = datan1_i - tempi;
|
||||
datan1_r = datan1_r + tempr;
|
||||
datan1_i = datan1_i + tempi;
|
||||
|
||||
double n2w1r = datan2_r * wr1 - datan2_i * wi1;
|
||||
double n2w1i = datan2_r * wi1 + datan2_i * wr1;
|
||||
double m2ww1r = datam2_r * wwr1 - datam2_i * wwi1;
|
||||
double m2ww1i = datam2_r * wwi1 + datam2_i * wwr1;
|
||||
|
||||
tempr = m2ww1r - n2w1r;
|
||||
tempi = m2ww1i - n2w1i;
|
||||
|
||||
datam2_r = datam1_r + tempi;
|
||||
datam2_i = datam1_i - tempr;
|
||||
datam1_r = datam1_r - tempi;
|
||||
datam1_i = datam1_i + tempr;
|
||||
|
||||
tempr = n2w1r + m2ww1r;
|
||||
tempi = n2w1i + m2ww1i;
|
||||
|
||||
datan2_r = datan1_r - tempr;
|
||||
datan2_i = datan1_i - tempi;
|
||||
datan1_r = datan1_r + tempr;
|
||||
datan1_i = datan1_i + tempi;
|
||||
|
||||
data[m] = datam2_r;
|
||||
data[m + 1] = datam2_i;
|
||||
data[n] = datan2_r;
|
||||
data[n + 1] = datan2_i;
|
||||
|
||||
n -= nnstep;
|
||||
m -= nnstep;
|
||||
data[m] = datam1_r;
|
||||
data[m + 1] = datam1_i;
|
||||
data[n] = datan1_r;
|
||||
data[n + 1] = datan1_i;
|
||||
}
|
||||
}
|
||||
|
||||
i += jmax << 1;
|
||||
|
||||
}
|
||||
|
||||
calcF2E(fftFrameSize, data, i, nstep, w);
|
||||
|
||||
}
|
||||
|
||||
// Perform Factor-4 Decomposition with 3 * complex operators and 8 +/-
|
||||
// complex operators
|
||||
private final static void calcF4I(int fftFrameSize, double[] data, int i,
|
||||
int nstep, double[] w) {
|
||||
final int fftFrameSize2 = fftFrameSize << 1; // 2*fftFrameSize;
|
||||
// Factor-4 Decomposition
|
||||
|
||||
int w_len = w.length >> 1;
|
||||
while (nstep < fftFrameSize2) {
|
||||
|
||||
if (nstep << 2 == fftFrameSize2) {
|
||||
// Goto Factor-4 Final Decomposition
|
||||
// calcF4E(data, i, nstep, 1, w);
|
||||
calcF4IE(fftFrameSize, data, i, nstep, w);
|
||||
return;
|
||||
}
|
||||
int jmax = nstep;
|
||||
int nnstep = nstep << 1;
|
||||
if (nnstep == fftFrameSize2) {
|
||||
// Factor-4 Decomposition not possible
|
||||
calcF2E(fftFrameSize, data, i, nstep, w);
|
||||
return;
|
||||
}
|
||||
nstep <<= 2;
|
||||
int ii = i + jmax;
|
||||
int iii = i + w_len;
|
||||
{
|
||||
i += 2;
|
||||
ii += 2;
|
||||
iii += 2;
|
||||
|
||||
for (int n = 0; n < fftFrameSize2; n += nstep) {
|
||||
int m = n + jmax;
|
||||
|
||||
double datam1_r = data[m];
|
||||
double datam1_i = data[m + 1];
|
||||
double datan1_r = data[n];
|
||||
double datan1_i = data[n + 1];
|
||||
|
||||
n += nnstep;
|
||||
m += nnstep;
|
||||
double datam2_r = data[m];
|
||||
double datam2_i = data[m + 1];
|
||||
double datan2_r = data[n];
|
||||
double datan2_i = data[n + 1];
|
||||
|
||||
double tempr = datam1_r;
|
||||
double tempi = datam1_i;
|
||||
|
||||
datam1_r = datan1_r - tempr;
|
||||
datam1_i = datan1_i - tempi;
|
||||
datan1_r = datan1_r + tempr;
|
||||
datan1_i = datan1_i + tempi;
|
||||
|
||||
double n2w1r = datan2_r;
|
||||
double n2w1i = datan2_i;
|
||||
double m2ww1r = datam2_r;
|
||||
double m2ww1i = datam2_i;
|
||||
|
||||
tempr = n2w1r - m2ww1r;
|
||||
tempi = n2w1i - m2ww1i;
|
||||
|
||||
datam2_r = datam1_r + tempi;
|
||||
datam2_i = datam1_i - tempr;
|
||||
datam1_r = datam1_r - tempi;
|
||||
datam1_i = datam1_i + tempr;
|
||||
|
||||
tempr = n2w1r + m2ww1r;
|
||||
tempi = n2w1i + m2ww1i;
|
||||
|
||||
datan2_r = datan1_r - tempr;
|
||||
datan2_i = datan1_i - tempi;
|
||||
datan1_r = datan1_r + tempr;
|
||||
datan1_i = datan1_i + tempi;
|
||||
|
||||
data[m] = datam2_r;
|
||||
data[m + 1] = datam2_i;
|
||||
data[n] = datan2_r;
|
||||
data[n + 1] = datan2_i;
|
||||
|
||||
n -= nnstep;
|
||||
m -= nnstep;
|
||||
data[m] = datam1_r;
|
||||
data[m + 1] = datam1_i;
|
||||
data[n] = datan1_r;
|
||||
data[n + 1] = datan1_i;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
for (int j = 2; j < jmax; j += 2) {
|
||||
double wr = w[i++];
|
||||
double wi = w[i++];
|
||||
double wr1 = w[ii++];
|
||||
double wi1 = w[ii++];
|
||||
double wwr1 = w[iii++];
|
||||
double wwi1 = w[iii++];
|
||||
// double wwr1 = wr * wr1 - wi * wi1; // these numbers can be
|
||||
// precomputed!!!
|
||||
// double wwi1 = wr * wi1 + wi * wr1;
|
||||
|
||||
for (int n = j; n < fftFrameSize2; n += nstep) {
|
||||
int m = n + jmax;
|
||||
|
||||
double datam1_r = data[m];
|
||||
double datam1_i = data[m + 1];
|
||||
double datan1_r = data[n];
|
||||
double datan1_i = data[n + 1];
|
||||
|
||||
n += nnstep;
|
||||
m += nnstep;
|
||||
double datam2_r = data[m];
|
||||
double datam2_i = data[m + 1];
|
||||
double datan2_r = data[n];
|
||||
double datan2_i = data[n + 1];
|
||||
|
||||
double tempr = datam1_r * wr - datam1_i * wi;
|
||||
double tempi = datam1_r * wi + datam1_i * wr;
|
||||
|
||||
datam1_r = datan1_r - tempr;
|
||||
datam1_i = datan1_i - tempi;
|
||||
datan1_r = datan1_r + tempr;
|
||||
datan1_i = datan1_i + tempi;
|
||||
|
||||
double n2w1r = datan2_r * wr1 - datan2_i * wi1;
|
||||
double n2w1i = datan2_r * wi1 + datan2_i * wr1;
|
||||
double m2ww1r = datam2_r * wwr1 - datam2_i * wwi1;
|
||||
double m2ww1i = datam2_r * wwi1 + datam2_i * wwr1;
|
||||
|
||||
tempr = n2w1r - m2ww1r;
|
||||
tempi = n2w1i - m2ww1i;
|
||||
|
||||
datam2_r = datam1_r + tempi;
|
||||
datam2_i = datam1_i - tempr;
|
||||
datam1_r = datam1_r - tempi;
|
||||
datam1_i = datam1_i + tempr;
|
||||
|
||||
tempr = n2w1r + m2ww1r;
|
||||
tempi = n2w1i + m2ww1i;
|
||||
|
||||
datan2_r = datan1_r - tempr;
|
||||
datan2_i = datan1_i - tempi;
|
||||
datan1_r = datan1_r + tempr;
|
||||
datan1_i = datan1_i + tempi;
|
||||
|
||||
data[m] = datam2_r;
|
||||
data[m + 1] = datam2_i;
|
||||
data[n] = datan2_r;
|
||||
data[n + 1] = datan2_i;
|
||||
|
||||
n -= nnstep;
|
||||
m -= nnstep;
|
||||
data[m] = datam1_r;
|
||||
data[m + 1] = datam1_i;
|
||||
data[n] = datan1_r;
|
||||
data[n + 1] = datan1_i;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
i += jmax << 1;
|
||||
|
||||
}
|
||||
|
||||
calcF2E(fftFrameSize, data, i, nstep, w);
|
||||
|
||||
}
|
||||
|
||||
// Perform Factor-4 Decomposition with 3 * complex operators and 8 +/-
|
||||
// complex operators
|
||||
private final static void calcF4FE(int fftFrameSize, double[] data, int i,
|
||||
int nstep, double[] w) {
|
||||
final int fftFrameSize2 = fftFrameSize << 1; // 2*fftFrameSize;
|
||||
// Factor-4 Decomposition
|
||||
|
||||
int w_len = w.length >> 1;
|
||||
while (nstep < fftFrameSize2) {
|
||||
|
||||
int jmax = nstep;
|
||||
int nnstep = nstep << 1;
|
||||
if (nnstep == fftFrameSize2) {
|
||||
// Factor-4 Decomposition not possible
|
||||
calcF2E(fftFrameSize, data, i, nstep, w);
|
||||
return;
|
||||
}
|
||||
nstep <<= 2;
|
||||
int ii = i + jmax;
|
||||
int iii = i + w_len;
|
||||
for (int n = 0; n < jmax; n += 2) {
|
||||
double wr = w[i++];
|
||||
double wi = w[i++];
|
||||
double wr1 = w[ii++];
|
||||
double wi1 = w[ii++];
|
||||
double wwr1 = w[iii++];
|
||||
double wwi1 = w[iii++];
|
||||
// double wwr1 = wr * wr1 - wi * wi1; // these numbers can be
|
||||
// precomputed!!!
|
||||
// double wwi1 = wr * wi1 + wi * wr1;
|
||||
|
||||
int m = n + jmax;
|
||||
|
||||
double datam1_r = data[m];
|
||||
double datam1_i = data[m + 1];
|
||||
double datan1_r = data[n];
|
||||
double datan1_i = data[n + 1];
|
||||
|
||||
n += nnstep;
|
||||
m += nnstep;
|
||||
double datam2_r = data[m];
|
||||
double datam2_i = data[m + 1];
|
||||
double datan2_r = data[n];
|
||||
double datan2_i = data[n + 1];
|
||||
|
||||
double tempr = datam1_r * wr - datam1_i * wi;
|
||||
double tempi = datam1_r * wi + datam1_i * wr;
|
||||
|
||||
datam1_r = datan1_r - tempr;
|
||||
datam1_i = datan1_i - tempi;
|
||||
datan1_r = datan1_r + tempr;
|
||||
datan1_i = datan1_i + tempi;
|
||||
|
||||
double n2w1r = datan2_r * wr1 - datan2_i * wi1;
|
||||
double n2w1i = datan2_r * wi1 + datan2_i * wr1;
|
||||
double m2ww1r = datam2_r * wwr1 - datam2_i * wwi1;
|
||||
double m2ww1i = datam2_r * wwi1 + datam2_i * wwr1;
|
||||
|
||||
tempr = m2ww1r - n2w1r;
|
||||
tempi = m2ww1i - n2w1i;
|
||||
|
||||
datam2_r = datam1_r + tempi;
|
||||
datam2_i = datam1_i - tempr;
|
||||
datam1_r = datam1_r - tempi;
|
||||
datam1_i = datam1_i + tempr;
|
||||
|
||||
tempr = n2w1r + m2ww1r;
|
||||
tempi = n2w1i + m2ww1i;
|
||||
|
||||
datan2_r = datan1_r - tempr;
|
||||
datan2_i = datan1_i - tempi;
|
||||
datan1_r = datan1_r + tempr;
|
||||
datan1_i = datan1_i + tempi;
|
||||
|
||||
data[m] = datam2_r;
|
||||
data[m + 1] = datam2_i;
|
||||
data[n] = datan2_r;
|
||||
data[n + 1] = datan2_i;
|
||||
|
||||
n -= nnstep;
|
||||
m -= nnstep;
|
||||
data[m] = datam1_r;
|
||||
data[m + 1] = datam1_i;
|
||||
data[n] = datan1_r;
|
||||
data[n + 1] = datan1_i;
|
||||
|
||||
}
|
||||
|
||||
i += jmax << 1;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Perform Factor-4 Decomposition with 3 * complex operators and 8 +/-
|
||||
// complex operators
|
||||
private final static void calcF4IE(int fftFrameSize, double[] data, int i,
|
||||
int nstep, double[] w) {
|
||||
final int fftFrameSize2 = fftFrameSize << 1; // 2*fftFrameSize;
|
||||
// Factor-4 Decomposition
|
||||
|
||||
int w_len = w.length >> 1;
|
||||
while (nstep < fftFrameSize2) {
|
||||
|
||||
int jmax = nstep;
|
||||
int nnstep = nstep << 1;
|
||||
if (nnstep == fftFrameSize2) {
|
||||
// Factor-4 Decomposition not possible
|
||||
calcF2E(fftFrameSize, data, i, nstep, w);
|
||||
return;
|
||||
}
|
||||
nstep <<= 2;
|
||||
int ii = i + jmax;
|
||||
int iii = i + w_len;
|
||||
for (int n = 0; n < jmax; n += 2) {
|
||||
double wr = w[i++];
|
||||
double wi = w[i++];
|
||||
double wr1 = w[ii++];
|
||||
double wi1 = w[ii++];
|
||||
double wwr1 = w[iii++];
|
||||
double wwi1 = w[iii++];
|
||||
// double wwr1 = wr * wr1 - wi * wi1; // these numbers can be
|
||||
// precomputed!!!
|
||||
// double wwi1 = wr * wi1 + wi * wr1;
|
||||
|
||||
int m = n + jmax;
|
||||
|
||||
double datam1_r = data[m];
|
||||
double datam1_i = data[m + 1];
|
||||
double datan1_r = data[n];
|
||||
double datan1_i = data[n + 1];
|
||||
|
||||
n += nnstep;
|
||||
m += nnstep;
|
||||
double datam2_r = data[m];
|
||||
double datam2_i = data[m + 1];
|
||||
double datan2_r = data[n];
|
||||
double datan2_i = data[n + 1];
|
||||
|
||||
double tempr = datam1_r * wr - datam1_i * wi;
|
||||
double tempi = datam1_r * wi + datam1_i * wr;
|
||||
|
||||
datam1_r = datan1_r - tempr;
|
||||
datam1_i = datan1_i - tempi;
|
||||
datan1_r = datan1_r + tempr;
|
||||
datan1_i = datan1_i + tempi;
|
||||
|
||||
double n2w1r = datan2_r * wr1 - datan2_i * wi1;
|
||||
double n2w1i = datan2_r * wi1 + datan2_i * wr1;
|
||||
double m2ww1r = datam2_r * wwr1 - datam2_i * wwi1;
|
||||
double m2ww1i = datam2_r * wwi1 + datam2_i * wwr1;
|
||||
|
||||
tempr = n2w1r - m2ww1r;
|
||||
tempi = n2w1i - m2ww1i;
|
||||
|
||||
datam2_r = datam1_r + tempi;
|
||||
datam2_i = datam1_i - tempr;
|
||||
datam1_r = datam1_r - tempi;
|
||||
datam1_i = datam1_i + tempr;
|
||||
|
||||
tempr = n2w1r + m2ww1r;
|
||||
tempi = n2w1i + m2ww1i;
|
||||
|
||||
datan2_r = datan1_r - tempr;
|
||||
datan2_i = datan1_i - tempi;
|
||||
datan1_r = datan1_r + tempr;
|
||||
datan1_i = datan1_i + tempi;
|
||||
|
||||
data[m] = datam2_r;
|
||||
data[m + 1] = datam2_i;
|
||||
data[n] = datan2_r;
|
||||
data[n + 1] = datan2_i;
|
||||
|
||||
n -= nnstep;
|
||||
m -= nnstep;
|
||||
data[m] = datam1_r;
|
||||
data[m + 1] = datam1_i;
|
||||
data[n] = datan1_r;
|
||||
data[n + 1] = datan1_i;
|
||||
|
||||
}
|
||||
|
||||
i += jmax << 1;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final void bitreversal(double[] data) {
|
||||
if (fftFrameSize < 4)
|
||||
return;
|
||||
|
||||
int inverse = fftFrameSize2 - 2;
|
||||
for (int i = 0; i < fftFrameSize; i += 4) {
|
||||
int j = bitm_array[i];
|
||||
|
||||
// Performing Bit-Reversal, even v.s. even, O(2N)
|
||||
if (i < j) {
|
||||
|
||||
int n = i;
|
||||
int m = j;
|
||||
|
||||
// COMPLEX: SWAP(data[n], data[m])
|
||||
// Real Part
|
||||
double tempr = data[n];
|
||||
data[n] = data[m];
|
||||
data[m] = tempr;
|
||||
// Imagery Part
|
||||
n++;
|
||||
m++;
|
||||
double tempi = data[n];
|
||||
data[n] = data[m];
|
||||
data[m] = tempi;
|
||||
|
||||
n = inverse - i;
|
||||
m = inverse - j;
|
||||
|
||||
// COMPLEX: SWAP(data[n], data[m])
|
||||
// Real Part
|
||||
tempr = data[n];
|
||||
data[n] = data[m];
|
||||
data[m] = tempr;
|
||||
// Imagery Part
|
||||
n++;
|
||||
m++;
|
||||
tempi = data[n];
|
||||
data[n] = data[m];
|
||||
data[m] = tempi;
|
||||
}
|
||||
|
||||
// Performing Bit-Reversal, odd v.s. even, O(N)
|
||||
|
||||
int m = j + fftFrameSize; // bitm_array[i+2];
|
||||
// COMPLEX: SWAP(data[n], data[m])
|
||||
// Real Part
|
||||
int n = i + 2;
|
||||
double tempr = data[n];
|
||||
data[n] = data[m];
|
||||
data[m] = tempr;
|
||||
// Imagery Part
|
||||
n++;
|
||||
m++;
|
||||
double tempi = data[n];
|
||||
data[n] = data[m];
|
||||
data[m] = tempi;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
141
jdkSrc/jdk8/com/sun/media/sound/FastShortMessage.java
Normal file
141
jdkSrc/jdk8/com/sun/media/sound/FastShortMessage.java
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.media.sound;
|
||||
|
||||
import javax.sound.midi.*;
|
||||
|
||||
/**
|
||||
* an optimized ShortMessage that does not need an array
|
||||
*
|
||||
* @author Florian Bomers
|
||||
*/
|
||||
final class FastShortMessage extends ShortMessage {
|
||||
private int packedMsg;
|
||||
|
||||
FastShortMessage(int packedMsg) throws InvalidMidiDataException {
|
||||
this.packedMsg = packedMsg;
|
||||
getDataLength(packedMsg & 0xFF); // to check for validity
|
||||
}
|
||||
|
||||
/** Creates a FastShortMessage from this ShortMessage */
|
||||
FastShortMessage(ShortMessage msg) {
|
||||
this.packedMsg = msg.getStatus()
|
||||
| (msg.getData1() << 8)
|
||||
| (msg.getData2() << 16);
|
||||
}
|
||||
|
||||
int getPackedMsg() {
|
||||
return packedMsg;
|
||||
}
|
||||
|
||||
public byte[] getMessage() {
|
||||
int length = 0;
|
||||
try {
|
||||
// fix for bug 4851018: MidiMessage.getLength and .getData return wrong values
|
||||
// fix for bug 4890405: Reading MidiMessage byte array fails in 1.4.2
|
||||
length = getDataLength(packedMsg & 0xFF) + 1;
|
||||
} catch (InvalidMidiDataException imde) {
|
||||
// should never happen
|
||||
}
|
||||
byte[] returnedArray = new byte[length];
|
||||
if (length>0) {
|
||||
returnedArray[0] = (byte) (packedMsg & 0xFF);
|
||||
if (length>1) {
|
||||
returnedArray[1] = (byte) ((packedMsg & 0xFF00) >> 8);
|
||||
if (length>2) {
|
||||
returnedArray[2] = (byte) ((packedMsg & 0xFF0000) >> 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
return returnedArray;
|
||||
}
|
||||
|
||||
public int getLength() {
|
||||
try {
|
||||
return getDataLength(packedMsg & 0xFF) + 1;
|
||||
} catch (InvalidMidiDataException imde) {
|
||||
// should never happen
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setMessage(int status) throws InvalidMidiDataException {
|
||||
// check for valid values
|
||||
int dataLength = getDataLength(status); // can throw InvalidMidiDataException
|
||||
if (dataLength != 0) {
|
||||
super.setMessage(status); // throws Exception
|
||||
}
|
||||
packedMsg = (packedMsg & 0xFFFF00) | (status & 0xFF);
|
||||
}
|
||||
|
||||
|
||||
public void setMessage(int status, int data1, int data2) throws InvalidMidiDataException {
|
||||
getDataLength(status); // can throw InvalidMidiDataException
|
||||
packedMsg = (status & 0xFF) | ((data1 & 0xFF) << 8) | ((data2 & 0xFF) << 16);
|
||||
}
|
||||
|
||||
|
||||
public void setMessage(int command, int channel, int data1, int data2) throws InvalidMidiDataException {
|
||||
getDataLength(command); // can throw InvalidMidiDataException
|
||||
packedMsg = (command & 0xF0) | (channel & 0x0F) | ((data1 & 0xFF) << 8) | ((data2 & 0xFF) << 16);
|
||||
}
|
||||
|
||||
|
||||
public int getChannel() {
|
||||
return packedMsg & 0x0F;
|
||||
}
|
||||
|
||||
public int getCommand() {
|
||||
return packedMsg & 0xF0;
|
||||
}
|
||||
|
||||
public int getData1() {
|
||||
return (packedMsg & 0xFF00) >> 8;
|
||||
}
|
||||
|
||||
public int getData2() {
|
||||
return (packedMsg & 0xFF0000) >> 16;
|
||||
}
|
||||
|
||||
public int getStatus() {
|
||||
return packedMsg & 0xFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new object of the same class and with the same contents
|
||||
* as this object.
|
||||
* @return a clone of this instance.
|
||||
*/
|
||||
public Object clone() {
|
||||
try {
|
||||
return new FastShortMessage(packedMsg);
|
||||
} catch (InvalidMidiDataException imde) {
|
||||
// should never happen
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
} // class FastShortMsg
|
||||
63
jdkSrc/jdk8/com/sun/media/sound/FastSysexMessage.java
Normal file
63
jdkSrc/jdk8/com/sun/media/sound/FastSysexMessage.java
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.media.sound;
|
||||
|
||||
import javax.sound.midi.*;
|
||||
|
||||
/**
|
||||
* optimized FastSysexMessage that doesn't copy the array upon instantiation
|
||||
*
|
||||
* @author Florian Bomers
|
||||
*/
|
||||
final class FastSysexMessage extends SysexMessage {
|
||||
|
||||
FastSysexMessage(byte[] data) throws InvalidMidiDataException {
|
||||
super(data);
|
||||
if (data.length==0 || (((data[0] & 0xFF) != 0xF0) && ((data[0] & 0xFF) != 0xF7))) {
|
||||
super.setMessage(data, data.length); // will throw Exception
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The returned array may be larger than this message is.
|
||||
* Use getLength() to get the real length of the message.
|
||||
*/
|
||||
byte[] getReadOnlyMessage() {
|
||||
return data;
|
||||
}
|
||||
|
||||
// overwrite this method so that the original data array,
|
||||
// which is shared among all transmitters, cannot be modified
|
||||
public void setMessage(byte[] data, int length) throws InvalidMidiDataException {
|
||||
if ((data.length == 0) || (((data[0] & 0xFF) != 0xF0) && ((data[0] & 0xFF) != 0xF7))) {
|
||||
super.setMessage(data, data.length); // will throw Exception
|
||||
}
|
||||
this.length = length;
|
||||
this.data = new byte[this.length];
|
||||
System.arraycopy(data, 0, this.data, 0, length);
|
||||
}
|
||||
|
||||
} // class FastSysexMessage
|
||||
45
jdkSrc/jdk8/com/sun/media/sound/InvalidDataException.java
Normal file
45
jdkSrc/jdk8/com/sun/media/sound/InvalidDataException.java
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* This exception is used when a file contains illegal or unexpected data.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public class InvalidDataException extends IOException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public InvalidDataException() {
|
||||
super("Invalid Data!");
|
||||
}
|
||||
|
||||
public InvalidDataException(String s) {
|
||||
super(s);
|
||||
}
|
||||
}
|
||||
44
jdkSrc/jdk8/com/sun/media/sound/InvalidFormatException.java
Normal file
44
jdkSrc/jdk8/com/sun/media/sound/InvalidFormatException.java
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
/**
|
||||
* This exception is used when a reader is used to read file of a format
|
||||
* it doesn't unterstand or support.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public class InvalidFormatException extends InvalidDataException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public InvalidFormatException() {
|
||||
super("Invalid format!");
|
||||
}
|
||||
|
||||
public InvalidFormatException(String s) {
|
||||
super(s);
|
||||
}
|
||||
}
|
||||
138
jdkSrc/jdk8/com/sun/media/sound/JARSoundbankReader.java
Normal file
138
jdkSrc/jdk8/com/sun/media/sound/JARSoundbankReader.java
Normal file
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.security.AccessController;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Objects;
|
||||
import javax.sound.midi.InvalidMidiDataException;
|
||||
import javax.sound.midi.Soundbank;
|
||||
import javax.sound.midi.spi.SoundbankReader;
|
||||
|
||||
import sun.reflect.misc.ReflectUtil;
|
||||
import sun.security.action.GetBooleanAction;
|
||||
|
||||
/**
|
||||
* JarSoundbankReader is used to read soundbank object from jar files.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public final class JARSoundbankReader extends SoundbankReader {
|
||||
|
||||
/**
|
||||
* Value of the system property that enables the Jar soundbank loading
|
||||
* {@code true} if jar sound bank is allowed to be loaded default is
|
||||
* {@code false}.
|
||||
*/
|
||||
@SuppressWarnings("removal")
|
||||
private static final boolean JAR_SOUNDBANK_ENABLED =
|
||||
AccessController.doPrivileged(
|
||||
new GetBooleanAction("jdk.sound.jarsoundbank"));
|
||||
|
||||
private static boolean isZIP(URL url) {
|
||||
boolean ok = false;
|
||||
try {
|
||||
InputStream stream = url.openStream();
|
||||
try {
|
||||
byte[] buff = new byte[4];
|
||||
ok = stream.read(buff) == 4;
|
||||
if (ok) {
|
||||
ok = (buff[0] == 0x50
|
||||
&& buff[1] == 0x4b
|
||||
&& buff[2] == 0x03
|
||||
&& buff[3] == 0x04);
|
||||
}
|
||||
} finally {
|
||||
stream.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
public Soundbank getSoundbank(URL url)
|
||||
throws InvalidMidiDataException, IOException {
|
||||
Objects.requireNonNull(url);
|
||||
if (!JAR_SOUNDBANK_ENABLED || !isZIP(url))
|
||||
return null;
|
||||
|
||||
ArrayList<Soundbank> soundbanks = new ArrayList<Soundbank>();
|
||||
URLClassLoader ucl = URLClassLoader.newInstance(new URL[]{url});
|
||||
InputStream stream = ucl.getResourceAsStream(
|
||||
"META-INF/services/javax.sound.midi.Soundbank");
|
||||
if (stream == null)
|
||||
return null;
|
||||
try
|
||||
{
|
||||
BufferedReader r = new BufferedReader(new InputStreamReader(stream));
|
||||
String line = r.readLine();
|
||||
while (line != null) {
|
||||
if (!line.startsWith("#")) {
|
||||
try {
|
||||
Class<?> c = Class.forName(line.trim(), false, ucl);
|
||||
if (Soundbank.class.isAssignableFrom(c)) {
|
||||
Object o = ReflectUtil.newInstance(c);
|
||||
soundbanks.add((Soundbank) o);
|
||||
}
|
||||
} catch (ClassNotFoundException ignored) {
|
||||
} catch (InstantiationException ignored) {
|
||||
} catch (IllegalAccessException ignored) {
|
||||
}
|
||||
}
|
||||
line = r.readLine();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
stream.close();
|
||||
}
|
||||
if (soundbanks.size() == 0)
|
||||
return null;
|
||||
if (soundbanks.size() == 1)
|
||||
return soundbanks.get(0);
|
||||
SimpleSoundbank sbk = new SimpleSoundbank();
|
||||
for (Soundbank soundbank : soundbanks)
|
||||
sbk.addAllInstruments(soundbank);
|
||||
return sbk;
|
||||
}
|
||||
|
||||
public Soundbank getSoundbank(InputStream stream)
|
||||
throws InvalidMidiDataException, IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Soundbank getSoundbank(File file)
|
||||
throws InvalidMidiDataException, IOException {
|
||||
Objects.requireNonNull(file);
|
||||
return getSoundbank(file.toURI().toURL());
|
||||
}
|
||||
}
|
||||
205
jdkSrc/jdk8/com/sun/media/sound/JDK13Services.java
Normal file
205
jdkSrc/jdk8/com/sun/media/sound/JDK13Services.java
Normal file
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.sound.midi.Receiver;
|
||||
import javax.sound.midi.Sequencer;
|
||||
import javax.sound.midi.Synthesizer;
|
||||
import javax.sound.midi.Transmitter;
|
||||
import javax.sound.midi.spi.MidiDeviceProvider;
|
||||
import javax.sound.midi.spi.MidiFileReader;
|
||||
import javax.sound.midi.spi.MidiFileWriter;
|
||||
import javax.sound.midi.spi.SoundbankReader;
|
||||
import javax.sound.sampled.Clip;
|
||||
import javax.sound.sampled.Port;
|
||||
import javax.sound.sampled.SourceDataLine;
|
||||
import javax.sound.sampled.TargetDataLine;
|
||||
import javax.sound.sampled.spi.AudioFileReader;
|
||||
import javax.sound.sampled.spi.AudioFileWriter;
|
||||
import javax.sound.sampled.spi.FormatConversionProvider;
|
||||
import javax.sound.sampled.spi.MixerProvider;
|
||||
|
||||
|
||||
/**
|
||||
* JDK13Services uses the Service class in JDK 1.3 to discover a list of service
|
||||
* providers installed in the system.
|
||||
* <p>
|
||||
* This class is public because it is called from javax.sound.midi.MidiSystem
|
||||
* and javax.sound.sampled.AudioSystem. The alternative would be to make
|
||||
* JSSecurityManager public, which is considered worse.
|
||||
*
|
||||
* @author Matthias Pfisterer
|
||||
*/
|
||||
public final class JDK13Services {
|
||||
|
||||
/**
|
||||
* Filename of the properties file for default provider properties. This
|
||||
* file is searched in the subdirectory "lib" of the JRE directory (this
|
||||
* behaviour is hardcoded).
|
||||
*/
|
||||
private static final String PROPERTIES_FILENAME = "sound.properties";
|
||||
|
||||
/**
|
||||
* Properties loaded from the properties file for default provider
|
||||
* properties.
|
||||
*/
|
||||
private static Properties properties;
|
||||
|
||||
/**
|
||||
* Private, no-args constructor to ensure against instantiation.
|
||||
*/
|
||||
private JDK13Services() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a List containing installed instances of the providers for the
|
||||
* requested service. The returned List is immutable.
|
||||
*
|
||||
* @param serviceClass The type of providers requested. This should be one
|
||||
* of AudioFileReader.class, AudioFileWriter.class,
|
||||
* FormatConversionProvider.class, MixerProvider.class,
|
||||
* MidiDeviceProvider.class, MidiFileReader.class,
|
||||
* MidiFileWriter.class or SoundbankReader.class.
|
||||
*
|
||||
* @return A List of providers of the requested type. This List is
|
||||
* immutable.
|
||||
*/
|
||||
public static List<?> getProviders(final Class<?> serviceClass) {
|
||||
final List<?> providers;
|
||||
if (!MixerProvider.class.equals(serviceClass)
|
||||
&& !FormatConversionProvider.class.equals(serviceClass)
|
||||
&& !AudioFileReader.class.equals(serviceClass)
|
||||
&& !AudioFileWriter.class.equals(serviceClass)
|
||||
&& !MidiDeviceProvider.class.equals(serviceClass)
|
||||
&& !SoundbankReader.class.equals(serviceClass)
|
||||
&& !MidiFileWriter.class.equals(serviceClass)
|
||||
&& !MidiFileReader.class.equals(serviceClass)) {
|
||||
providers = new ArrayList<>(0);
|
||||
} else {
|
||||
providers = JSSecurityManager.getProviders(serviceClass);
|
||||
}
|
||||
return Collections.unmodifiableList(providers);
|
||||
}
|
||||
|
||||
/** Obtain the provider class name part of a default provider property.
|
||||
@param typeClass The type of the default provider property. This
|
||||
should be one of Receiver.class, Transmitter.class, Sequencer.class,
|
||||
Synthesizer.class, SourceDataLine.class, TargetDataLine.class,
|
||||
Clip.class or Port.class.
|
||||
@return The value of the provider class name part of the property
|
||||
(the part before the hash sign), if available. If the property is
|
||||
not set or the value has no provider class name part, null is returned.
|
||||
*/
|
||||
public static synchronized String getDefaultProviderClassName(Class typeClass) {
|
||||
String value = null;
|
||||
String defaultProviderSpec = getDefaultProvider(typeClass);
|
||||
if (defaultProviderSpec != null) {
|
||||
int hashpos = defaultProviderSpec.indexOf('#');
|
||||
if (hashpos == 0) {
|
||||
// instance name only; leave value as null
|
||||
} else if (hashpos > 0) {
|
||||
value = defaultProviderSpec.substring(0, hashpos);
|
||||
} else {
|
||||
value = defaultProviderSpec;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
/** Obtain the instance name part of a default provider property.
|
||||
@param typeClass The type of the default provider property. This
|
||||
should be one of Receiver.class, Transmitter.class, Sequencer.class,
|
||||
Synthesizer.class, SourceDataLine.class, TargetDataLine.class,
|
||||
Clip.class or Port.class.
|
||||
@return The value of the instance name part of the property (the
|
||||
part after the hash sign), if available. If the property is not set
|
||||
or the value has no instance name part, null is returned.
|
||||
*/
|
||||
public static synchronized String getDefaultInstanceName(Class typeClass) {
|
||||
String value = null;
|
||||
String defaultProviderSpec = getDefaultProvider(typeClass);
|
||||
if (defaultProviderSpec != null) {
|
||||
int hashpos = defaultProviderSpec.indexOf('#');
|
||||
if (hashpos >= 0 && hashpos < defaultProviderSpec.length() - 1) {
|
||||
value = defaultProviderSpec.substring(hashpos + 1);
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
/** Obtain the value of a default provider property.
|
||||
@param typeClass The type of the default provider property. This
|
||||
should be one of Receiver.class, Transmitter.class, Sequencer.class,
|
||||
Synthesizer.class, SourceDataLine.class, TargetDataLine.class,
|
||||
Clip.class or Port.class.
|
||||
@return The complete value of the property, if available.
|
||||
If the property is not set, null is returned.
|
||||
*/
|
||||
private static synchronized String getDefaultProvider(Class typeClass) {
|
||||
if (!SourceDataLine.class.equals(typeClass)
|
||||
&& !TargetDataLine.class.equals(typeClass)
|
||||
&& !Clip.class.equals(typeClass)
|
||||
&& !Port.class.equals(typeClass)
|
||||
&& !Receiver.class.equals(typeClass)
|
||||
&& !Transmitter.class.equals(typeClass)
|
||||
&& !Synthesizer.class.equals(typeClass)
|
||||
&& !Sequencer.class.equals(typeClass)) {
|
||||
return null;
|
||||
}
|
||||
String name = typeClass.getName();
|
||||
String value = AccessController.doPrivileged(
|
||||
(PrivilegedAction<String>) () -> System.getProperty(name));
|
||||
if (value == null) {
|
||||
value = getProperties().getProperty(name);
|
||||
}
|
||||
if ("".equals(value)) {
|
||||
value = null;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
/** Obtain a properties bundle containing property values from the
|
||||
properties file. If the properties file could not be loaded,
|
||||
the properties bundle is empty.
|
||||
*/
|
||||
private static synchronized Properties getProperties() {
|
||||
if (properties == null) {
|
||||
properties = new Properties();
|
||||
JSSecurityManager.loadProperties(properties, PROPERTIES_FILENAME);
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
}
|
||||
204
jdkSrc/jdk8/com/sun/media/sound/JSSecurityManager.java
Normal file
204
jdkSrc/jdk8/com/sun/media/sound/JSSecurityManager.java
Normal file
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
import javax.sound.sampled.AudioPermission;
|
||||
|
||||
/** Managing security in the Java Sound implementation.
|
||||
* This class contains all code that uses and is used by
|
||||
* SecurityManager.doPrivileged().
|
||||
*
|
||||
* @author Matthias Pfisterer
|
||||
*/
|
||||
final class JSSecurityManager {
|
||||
|
||||
/** Prevent instantiation.
|
||||
*/
|
||||
private JSSecurityManager() {
|
||||
}
|
||||
|
||||
/** Checks if the VM currently has a SecurityManager installed.
|
||||
* Note that this may change over time. So the result of this method
|
||||
* should not be cached.
|
||||
*
|
||||
* @return true if a SecurityManger is installed, false otherwise.
|
||||
*/
|
||||
private static boolean hasSecurityManager() {
|
||||
return (System.getSecurityManager() != null);
|
||||
}
|
||||
|
||||
|
||||
static void checkRecordPermission() throws SecurityException {
|
||||
if(Printer.trace) Printer.trace("JSSecurityManager.checkRecordPermission()");
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
sm.checkPermission(new AudioPermission("record"));
|
||||
}
|
||||
}
|
||||
|
||||
/** Load properties from a file.
|
||||
This method tries to load properties from the filename give into
|
||||
the passed properties object.
|
||||
If the file cannot be found or something else goes wrong,
|
||||
the method silently fails.
|
||||
@param properties The properties bundle to store the values of the
|
||||
properties file.
|
||||
@param filename The filename of the properties file to load. This
|
||||
filename is interpreted as relative to the subdirectory "lib" in
|
||||
the JRE directory.
|
||||
*/
|
||||
static void loadProperties(final Properties properties,
|
||||
final String filename) {
|
||||
if(hasSecurityManager()) {
|
||||
try {
|
||||
// invoke the privileged action using 1.2 security
|
||||
PrivilegedAction<Void> action = new PrivilegedAction<Void>() {
|
||||
public Void run() {
|
||||
loadPropertiesImpl(properties, filename);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
AccessController.doPrivileged(action);
|
||||
if(Printer.debug)Printer.debug("Loaded properties with JDK 1.2 security");
|
||||
} catch (Exception e) {
|
||||
if(Printer.debug)Printer.debug("Exception loading properties with JDK 1.2 security");
|
||||
// try without using JDK 1.2 security
|
||||
loadPropertiesImpl(properties, filename);
|
||||
}
|
||||
} else {
|
||||
// not JDK 1.2 security, assume we already have permission
|
||||
loadPropertiesImpl(properties, filename);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void loadPropertiesImpl(Properties properties,
|
||||
String filename) {
|
||||
if(Printer.trace)Printer.trace(">> JSSecurityManager: loadPropertiesImpl()");
|
||||
String fname = System.getProperty("java.home");
|
||||
try {
|
||||
if (fname == null) {
|
||||
throw new Error("Can't find java.home ??");
|
||||
}
|
||||
File f = new File(fname, "lib");
|
||||
f = new File(f, filename);
|
||||
fname = f.getCanonicalPath();
|
||||
InputStream in = new FileInputStream(fname);
|
||||
BufferedInputStream bin = new BufferedInputStream(in);
|
||||
try {
|
||||
properties.load(bin);
|
||||
} finally {
|
||||
if (in != null) {
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
if (Printer.trace) {
|
||||
System.err.println("Could not load properties file \"" + fname + "\"");
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
if(Printer.trace)Printer.trace("<< JSSecurityManager: loadPropertiesImpl() completed");
|
||||
}
|
||||
|
||||
/** Create a Thread in the current ThreadGroup.
|
||||
*/
|
||||
static Thread createThread(final Runnable runnable,
|
||||
final String threadName,
|
||||
final boolean isDaemon, final int priority,
|
||||
final boolean doStart) {
|
||||
Thread thread = new Thread(runnable);
|
||||
if (threadName != null) {
|
||||
thread.setName(threadName);
|
||||
}
|
||||
thread.setDaemon(isDaemon);
|
||||
if (priority >= 0) {
|
||||
thread.setPriority(priority);
|
||||
}
|
||||
if (doStart) {
|
||||
thread.start();
|
||||
}
|
||||
return thread;
|
||||
}
|
||||
|
||||
static synchronized <T> List<T> getProviders(final Class<T> providerClass) {
|
||||
List<T> p = new ArrayList<>(7);
|
||||
// ServiceLoader creates "lazy" iterator instance, but it ensures that
|
||||
// next/hasNext run with permissions that are restricted by whatever
|
||||
// creates the ServiceLoader instance, so it requires to be called from
|
||||
// privileged section
|
||||
final PrivilegedAction<Iterator<T>> psAction =
|
||||
new PrivilegedAction<Iterator<T>>() {
|
||||
@Override
|
||||
public Iterator<T> run() {
|
||||
return ServiceLoader.load(providerClass).iterator();
|
||||
}
|
||||
};
|
||||
final Iterator<T> ps = AccessController.doPrivileged(psAction);
|
||||
|
||||
// the iterator's hasNext() method looks through classpath for
|
||||
// the provider class names, so it requires read permissions
|
||||
PrivilegedAction<Boolean> hasNextAction = new PrivilegedAction<Boolean>() {
|
||||
public Boolean run() {
|
||||
return ps.hasNext();
|
||||
}
|
||||
};
|
||||
|
||||
while (AccessController.doPrivileged(hasNextAction)) {
|
||||
try {
|
||||
// the iterator's next() method creates instances of the
|
||||
// providers and it should be called in the current security
|
||||
// context
|
||||
T provider = ps.next();
|
||||
if (providerClass.isInstance(provider)) {
|
||||
// $$mp 2003-08-22
|
||||
// Always adding at the beginning reverses the
|
||||
// order of the providers. So we no longer have
|
||||
// to do this in AudioSystem and MidiSystem.
|
||||
p.add(0, provider);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
//$$fb 2002-11-07: do not fail on SPI not found
|
||||
if (Printer.err) t.printStackTrace();
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
}
|
||||
485
jdkSrc/jdk8/com/sun/media/sound/JavaSoundAudioClip.java
Normal file
485
jdkSrc/jdk8/com/sun/media/sound/JavaSoundAudioClip.java
Normal file
@@ -0,0 +1,485 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.applet.AudioClip;
|
||||
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
import javax.sound.sampled.Clip;
|
||||
import javax.sound.sampled.AudioInputStream;
|
||||
import javax.sound.sampled.AudioFormat;
|
||||
import javax.sound.sampled.DataLine;
|
||||
import javax.sound.sampled.SourceDataLine;
|
||||
import javax.sound.sampled.LineEvent;
|
||||
import javax.sound.sampled.LineListener;
|
||||
import javax.sound.sampled.UnsupportedAudioFileException;
|
||||
|
||||
import javax.sound.midi.MidiSystem;
|
||||
import javax.sound.midi.MidiFileFormat;
|
||||
import javax.sound.midi.MetaMessage;
|
||||
import javax.sound.midi.Sequence;
|
||||
import javax.sound.midi.Sequencer;
|
||||
import javax.sound.midi.InvalidMidiDataException;
|
||||
import javax.sound.midi.MidiUnavailableException;
|
||||
import javax.sound.midi.MetaEventListener;
|
||||
|
||||
/**
|
||||
* Java Sound audio clip;
|
||||
*
|
||||
* @author Arthur van Hoff, Kara Kytle, Jan Borgersen
|
||||
* @author Florian Bomers
|
||||
*/
|
||||
|
||||
public final class JavaSoundAudioClip implements AudioClip, MetaEventListener, LineListener {
|
||||
|
||||
private static final boolean DEBUG = false;
|
||||
private static final int BUFFER_SIZE = 16384; // number of bytes written each time to the source data line
|
||||
|
||||
private long lastPlayCall = 0;
|
||||
private static final int MINIMUM_PLAY_DELAY = 30;
|
||||
|
||||
private byte loadedAudio[] = null;
|
||||
private int loadedAudioByteLength = 0;
|
||||
private AudioFormat loadedAudioFormat = null;
|
||||
|
||||
private AutoClosingClip clip = null;
|
||||
private boolean clipLooping = false;
|
||||
|
||||
private DataPusher datapusher = null;
|
||||
|
||||
private Sequencer sequencer = null;
|
||||
private Sequence sequence = null;
|
||||
private boolean sequencerloop = false;
|
||||
|
||||
/**
|
||||
* used for determining how many samples is the
|
||||
* threshhold between playing as a Clip and streaming
|
||||
* from the file.
|
||||
*
|
||||
* $$jb: 11.07.99: the engine has a limit of 1M
|
||||
* samples to play as a Clip, so compare this number
|
||||
* with the number of samples in the stream.
|
||||
*
|
||||
*/
|
||||
private final static long CLIP_THRESHOLD = 1048576;
|
||||
//private final static long CLIP_THRESHOLD = 1;
|
||||
private final static int STREAM_BUFFER_SIZE = 1024;
|
||||
|
||||
public JavaSoundAudioClip(InputStream in) throws IOException {
|
||||
if (DEBUG || Printer.debug)Printer.debug("JavaSoundAudioClip.<init>");
|
||||
|
||||
BufferedInputStream bis = new BufferedInputStream(in, STREAM_BUFFER_SIZE);
|
||||
bis.mark(STREAM_BUFFER_SIZE);
|
||||
boolean success = false;
|
||||
try {
|
||||
AudioInputStream as = AudioSystem.getAudioInputStream(bis);
|
||||
// load the stream data into memory
|
||||
success = loadAudioData(as);
|
||||
|
||||
if (success) {
|
||||
success = false;
|
||||
if (loadedAudioByteLength < CLIP_THRESHOLD) {
|
||||
success = createClip();
|
||||
}
|
||||
if (!success) {
|
||||
success = createSourceDataLine();
|
||||
}
|
||||
}
|
||||
} catch (UnsupportedAudioFileException e) {
|
||||
// not an audio file
|
||||
try {
|
||||
MidiFileFormat mff = MidiSystem.getMidiFileFormat(bis);
|
||||
success = createSequencer(bis);
|
||||
} catch (InvalidMidiDataException e1) {
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
if (!success) {
|
||||
throw new IOException("Unable to create AudioClip from input stream");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public synchronized void play() {
|
||||
startImpl(false);
|
||||
}
|
||||
|
||||
|
||||
public synchronized void loop() {
|
||||
startImpl(true);
|
||||
}
|
||||
|
||||
private synchronized void startImpl(boolean loop) {
|
||||
// hack for some applets that call the start method very rapidly...
|
||||
long currentTime = System.currentTimeMillis();
|
||||
long diff = currentTime - lastPlayCall;
|
||||
if (diff < MINIMUM_PLAY_DELAY) {
|
||||
if (DEBUG || Printer.debug) Printer.debug("JavaSoundAudioClip.startImpl(loop="+loop+"): abort - too rapdly");
|
||||
return;
|
||||
}
|
||||
lastPlayCall = currentTime;
|
||||
|
||||
if (DEBUG || Printer.debug) Printer.debug("JavaSoundAudioClip.startImpl(loop="+loop+")");
|
||||
try {
|
||||
if (clip != null) {
|
||||
// We need to disable autoclosing mechanism otherwise the clip
|
||||
// can be closed after "!clip.isOpen()" check, because of
|
||||
// previous inactivity.
|
||||
clip.setAutoClosing(false);
|
||||
try {
|
||||
if (!clip.isOpen()) {
|
||||
clip.open(loadedAudioFormat, loadedAudio, 0,
|
||||
loadedAudioByteLength);
|
||||
} else {
|
||||
clip.flush();
|
||||
if (loop != clipLooping) {
|
||||
// need to stop in case the looped status changed
|
||||
clip.stop();
|
||||
}
|
||||
}
|
||||
clip.setFramePosition(0);
|
||||
if (loop) {
|
||||
clip.loop(Clip.LOOP_CONTINUOUSLY);
|
||||
} else {
|
||||
clip.start();
|
||||
}
|
||||
clipLooping = loop;
|
||||
} finally {
|
||||
clip.setAutoClosing(true);
|
||||
}
|
||||
} else if (datapusher != null ) {
|
||||
datapusher.start(loop);
|
||||
if (DEBUG || Printer.debug)Printer.debug("Stream should be playing/looping");
|
||||
|
||||
} else if (sequencer != null) {
|
||||
sequencerloop = loop;
|
||||
if (sequencer.isRunning()) {
|
||||
sequencer.setMicrosecondPosition(0);
|
||||
}
|
||||
if (!sequencer.isOpen()) {
|
||||
try {
|
||||
sequencer.open();
|
||||
sequencer.setSequence(sequence);
|
||||
|
||||
} catch (InvalidMidiDataException e1) {
|
||||
if (DEBUG || Printer.err)e1.printStackTrace();
|
||||
} catch (MidiUnavailableException e2) {
|
||||
if (DEBUG || Printer.err)e2.printStackTrace();
|
||||
}
|
||||
}
|
||||
sequencer.addMetaEventListener(this);
|
||||
try {
|
||||
sequencer.start();
|
||||
} catch (Exception e) {
|
||||
if (DEBUG || Printer.err) e.printStackTrace();
|
||||
}
|
||||
if (DEBUG || Printer.debug)Printer.debug("Sequencer should be playing/looping");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (DEBUG || Printer.err)e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void stop() {
|
||||
|
||||
if (DEBUG || Printer.debug)Printer.debug("JavaSoundAudioClip->stop()");
|
||||
lastPlayCall = 0;
|
||||
|
||||
if (clip != null) {
|
||||
try {
|
||||
if (DEBUG || Printer.trace)Printer.trace("JavaSoundAudioClip: clip.flush()");
|
||||
clip.flush();
|
||||
} catch (Exception e1) {
|
||||
if (Printer.err) e1.printStackTrace();
|
||||
}
|
||||
try {
|
||||
if (DEBUG || Printer.trace)Printer.trace("JavaSoundAudioClip: clip.stop()");
|
||||
clip.stop();
|
||||
} catch (Exception e2) {
|
||||
if (Printer.err) e2.printStackTrace();
|
||||
}
|
||||
if (DEBUG || Printer.debug)Printer.debug("Clip should be stopped");
|
||||
|
||||
} else if (datapusher != null) {
|
||||
datapusher.stop();
|
||||
if (DEBUG || Printer.debug)Printer.debug("Stream should be stopped");
|
||||
|
||||
} else if (sequencer != null) {
|
||||
try {
|
||||
sequencerloop = false;
|
||||
sequencer.addMetaEventListener(this);
|
||||
sequencer.stop();
|
||||
} catch (Exception e3) {
|
||||
if (Printer.err) e3.printStackTrace();
|
||||
}
|
||||
try {
|
||||
sequencer.close();
|
||||
} catch (Exception e4) {
|
||||
if (Printer.err) e4.printStackTrace();
|
||||
}
|
||||
if (DEBUG || Printer.debug)Printer.debug("Sequencer should be stopped");
|
||||
}
|
||||
}
|
||||
|
||||
// Event handlers (for debugging)
|
||||
|
||||
public synchronized void update(LineEvent event) {
|
||||
if (DEBUG || Printer.debug) Printer.debug("line event received: "+event);
|
||||
}
|
||||
|
||||
// handle MIDI track end meta events for looping
|
||||
|
||||
public synchronized void meta( MetaMessage message ) {
|
||||
|
||||
if (DEBUG || Printer.debug)Printer.debug("META EVENT RECEIVED!!!!! ");
|
||||
|
||||
if( message.getType() == 47 ) {
|
||||
if (sequencerloop){
|
||||
//notifyAll();
|
||||
sequencer.setMicrosecondPosition(0);
|
||||
loop();
|
||||
} else {
|
||||
stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String toString() {
|
||||
return getClass().toString();
|
||||
}
|
||||
|
||||
|
||||
protected void finalize() {
|
||||
|
||||
if (clip != null) {
|
||||
if (DEBUG || Printer.trace)Printer.trace("JavaSoundAudioClip.finalize: clip.close()");
|
||||
clip.close();
|
||||
}
|
||||
|
||||
//$$fb 2001-09-26: may improve situation related to bug #4302884
|
||||
if (datapusher != null) {
|
||||
datapusher.close();
|
||||
}
|
||||
|
||||
if (sequencer != null) {
|
||||
sequencer.close();
|
||||
}
|
||||
}
|
||||
|
||||
// FILE LOADING METHODS
|
||||
|
||||
private boolean loadAudioData(AudioInputStream as) throws IOException, UnsupportedAudioFileException {
|
||||
if (DEBUG || Printer.debug)Printer.debug("JavaSoundAudioClip->openAsClip()");
|
||||
|
||||
// first possibly convert this stream to PCM
|
||||
as = Toolkit.getPCMConvertedAudioInputStream(as);
|
||||
if (as == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
loadedAudioFormat = as.getFormat();
|
||||
long frameLen = as.getFrameLength();
|
||||
int frameSize = loadedAudioFormat.getFrameSize();
|
||||
long byteLen = AudioSystem.NOT_SPECIFIED;
|
||||
if (frameLen != AudioSystem.NOT_SPECIFIED
|
||||
&& frameLen > 0
|
||||
&& frameSize != AudioSystem.NOT_SPECIFIED
|
||||
&& frameSize > 0) {
|
||||
byteLen = frameLen * frameSize;
|
||||
}
|
||||
if (byteLen != AudioSystem.NOT_SPECIFIED) {
|
||||
// if the stream length is known, it can be efficiently loaded into memory
|
||||
readStream(as, byteLen);
|
||||
} else {
|
||||
// otherwise we use a ByteArrayOutputStream to load it into memory
|
||||
readStream(as);
|
||||
}
|
||||
|
||||
// if everything went fine, we have now the audio data in
|
||||
// loadedAudio, and the byte length in loadedAudioByteLength
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void readStream(AudioInputStream as, long byteLen) throws IOException {
|
||||
// arrays "only" max. 2GB
|
||||
int intLen;
|
||||
if (byteLen > 2147483647) {
|
||||
intLen = 2147483647;
|
||||
} else {
|
||||
intLen = (int) byteLen;
|
||||
}
|
||||
loadedAudio = new byte[intLen];
|
||||
loadedAudioByteLength = 0;
|
||||
|
||||
// this loop may throw an IOException
|
||||
while (true) {
|
||||
int bytesRead = as.read(loadedAudio, loadedAudioByteLength, intLen - loadedAudioByteLength);
|
||||
if (bytesRead <= 0) {
|
||||
as.close();
|
||||
break;
|
||||
}
|
||||
loadedAudioByteLength += bytesRead;
|
||||
}
|
||||
}
|
||||
|
||||
private void readStream(AudioInputStream as) throws IOException {
|
||||
|
||||
DirectBAOS baos = new DirectBAOS();
|
||||
byte buffer[] = new byte[16384];
|
||||
int bytesRead = 0;
|
||||
int totalBytesRead = 0;
|
||||
|
||||
// this loop may throw an IOException
|
||||
while( true ) {
|
||||
bytesRead = as.read(buffer, 0, buffer.length);
|
||||
if (bytesRead <= 0) {
|
||||
as.close();
|
||||
break;
|
||||
}
|
||||
totalBytesRead += bytesRead;
|
||||
baos.write(buffer, 0, bytesRead);
|
||||
}
|
||||
loadedAudio = baos.getInternalBuffer();
|
||||
loadedAudioByteLength = totalBytesRead;
|
||||
}
|
||||
|
||||
|
||||
// METHODS FOR CREATING THE DEVICE
|
||||
|
||||
private boolean createClip() {
|
||||
|
||||
if (DEBUG || Printer.debug)Printer.debug("JavaSoundAudioClip.createClip()");
|
||||
|
||||
try {
|
||||
DataLine.Info info = new DataLine.Info(Clip.class, loadedAudioFormat);
|
||||
if (!(AudioSystem.isLineSupported(info)) ) {
|
||||
if (DEBUG || Printer.err)Printer.err("Clip not supported: "+loadedAudioFormat);
|
||||
// fail silently
|
||||
return false;
|
||||
}
|
||||
Object line = AudioSystem.getLine(info);
|
||||
if (!(line instanceof AutoClosingClip)) {
|
||||
if (DEBUG || Printer.err)Printer.err("Clip is not auto closing!"+clip);
|
||||
// fail -> will try with SourceDataLine
|
||||
return false;
|
||||
}
|
||||
clip = (AutoClosingClip) line;
|
||||
clip.setAutoClosing(true);
|
||||
if (DEBUG || Printer.debug) clip.addLineListener(this);
|
||||
} catch (Exception e) {
|
||||
if (DEBUG || Printer.err)e.printStackTrace();
|
||||
// fail silently
|
||||
return false;
|
||||
}
|
||||
|
||||
if (clip==null) {
|
||||
// fail silently
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DEBUG || Printer.debug)Printer.debug("Loaded clip.");
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean createSourceDataLine() {
|
||||
if (DEBUG || Printer.debug)Printer.debug("JavaSoundAudioClip.createSourceDataLine()");
|
||||
try {
|
||||
DataLine.Info info = new DataLine.Info(SourceDataLine.class, loadedAudioFormat);
|
||||
if (!(AudioSystem.isLineSupported(info)) ) {
|
||||
if (DEBUG || Printer.err)Printer.err("Line not supported: "+loadedAudioFormat);
|
||||
// fail silently
|
||||
return false;
|
||||
}
|
||||
SourceDataLine source = (SourceDataLine) AudioSystem.getLine(info);
|
||||
datapusher = new DataPusher(source, loadedAudioFormat, loadedAudio, loadedAudioByteLength);
|
||||
} catch (Exception e) {
|
||||
if (DEBUG || Printer.err)e.printStackTrace();
|
||||
// fail silently
|
||||
return false;
|
||||
}
|
||||
|
||||
if (datapusher==null) {
|
||||
// fail silently
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DEBUG || Printer.debug)Printer.debug("Created SourceDataLine.");
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean createSequencer(BufferedInputStream in) throws IOException {
|
||||
|
||||
if (DEBUG || Printer.debug)Printer.debug("JavaSoundAudioClip.createSequencer()");
|
||||
|
||||
// get the sequencer
|
||||
try {
|
||||
sequencer = MidiSystem.getSequencer( );
|
||||
} catch(MidiUnavailableException me) {
|
||||
if (DEBUG || Printer.err)me.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
if (sequencer==null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
sequence = MidiSystem.getSequence(in);
|
||||
if (sequence == null) {
|
||||
return false;
|
||||
}
|
||||
} catch (InvalidMidiDataException e) {
|
||||
if (DEBUG || Printer.err)e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DEBUG || Printer.debug)Printer.debug("Created Sequencer.");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* private inner class representing a ByteArrayOutputStream
|
||||
* which allows retrieval of the internal array
|
||||
*/
|
||||
private static class DirectBAOS extends ByteArrayOutputStream {
|
||||
DirectBAOS() {
|
||||
super();
|
||||
}
|
||||
|
||||
public byte[] getInternalBuffer() {
|
||||
return buf;
|
||||
}
|
||||
|
||||
} // class DirectBAOS
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
import javax.sound.midi.*;
|
||||
|
||||
|
||||
/**
|
||||
* Helper class which allows to convert {@code Receiver}
|
||||
* to {@code MidiDeviceReceiver}.
|
||||
*
|
||||
* @author Alex Menkov
|
||||
*/
|
||||
public final class MidiDeviceReceiverEnvelope implements MidiDeviceReceiver {
|
||||
|
||||
private final MidiDevice device;
|
||||
private final Receiver receiver;
|
||||
|
||||
/**
|
||||
* Creates a new {@code MidiDeviceReceiverEnvelope} object which
|
||||
* envelops the specified {@code Receiver}
|
||||
* and is owned by the specified {@code MidiDevice}.
|
||||
*
|
||||
* @param device the owner {@code MidiDevice}
|
||||
* @param receiver the {@code Receiver} to be enveloped
|
||||
*/
|
||||
public MidiDeviceReceiverEnvelope(MidiDevice device, Receiver receiver) {
|
||||
if (device == null || receiver == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
this.device = device;
|
||||
this.receiver = receiver;
|
||||
}
|
||||
|
||||
// Receiver implementation
|
||||
public void close() {
|
||||
receiver.close();
|
||||
}
|
||||
|
||||
public void send(MidiMessage message, long timeStamp) {
|
||||
receiver.send(message, timeStamp);
|
||||
}
|
||||
|
||||
// MidiDeviceReceiver implementation
|
||||
public MidiDevice getMidiDevice() {
|
||||
return device;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the receiver enveloped
|
||||
* by this {@code MidiDeviceReceiverEnvelope} object.
|
||||
*
|
||||
* @return the enveloped receiver
|
||||
*/
|
||||
public Receiver getReceiver() {
|
||||
return receiver;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
import javax.sound.midi.*;
|
||||
|
||||
|
||||
/**
|
||||
* Helper class which allows to convert {@code Transmitter}
|
||||
* to {@code MidiDeviceTransmitter}.
|
||||
*
|
||||
* @author Alex Menkov
|
||||
*/
|
||||
public final class MidiDeviceTransmitterEnvelope implements MidiDeviceTransmitter {
|
||||
|
||||
private final MidiDevice device;
|
||||
private final Transmitter transmitter;
|
||||
|
||||
/**
|
||||
* Creates a new {@code MidiDeviceTransmitterEnvelope} object which
|
||||
* envelops the specified {@code Transmitter}
|
||||
* and is owned by the specified {@code MidiDevice}.
|
||||
*
|
||||
* @param device the owner {@code MidiDevice}
|
||||
* @param transmitter the {@code Transmitter} to be enveloped
|
||||
*/
|
||||
public MidiDeviceTransmitterEnvelope(MidiDevice device, Transmitter transmitter) {
|
||||
if (device == null || transmitter == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
this.device = device;
|
||||
this.transmitter = transmitter;
|
||||
}
|
||||
|
||||
// Transmitter implementation
|
||||
public void setReceiver(Receiver receiver) {
|
||||
transmitter.setReceiver(receiver);
|
||||
}
|
||||
|
||||
public Receiver getReceiver() {
|
||||
return transmitter.getReceiver();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
transmitter.close();
|
||||
}
|
||||
|
||||
|
||||
// MidiDeviceReceiver implementation
|
||||
public MidiDevice getMidiDevice() {
|
||||
return device;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the transmitter enveloped
|
||||
* by this {@code MidiDeviceTransmitterEnvelope} object.
|
||||
*
|
||||
* @return the enveloped transmitter
|
||||
*/
|
||||
public Transmitter getTransmitter() {
|
||||
return transmitter;
|
||||
}
|
||||
}
|
||||
195
jdkSrc/jdk8/com/sun/media/sound/MidiInDevice.java
Normal file
195
jdkSrc/jdk8/com/sun/media/sound/MidiInDevice.java
Normal file
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.media.sound;
|
||||
|
||||
import javax.sound.midi.*;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* MidiInDevice class representing functionality of MidiIn devices.
|
||||
*
|
||||
* @author David Rivas
|
||||
* @author Kara Kytle
|
||||
* @author Florian Bomers
|
||||
*/
|
||||
final class MidiInDevice extends AbstractMidiDevice implements Runnable {
|
||||
|
||||
private volatile Thread midiInThread;
|
||||
|
||||
// CONSTRUCTOR
|
||||
|
||||
MidiInDevice(AbstractMidiDeviceProvider.Info info) {
|
||||
super(info);
|
||||
if(Printer.trace) Printer.trace("MidiInDevice CONSTRUCTOR");
|
||||
}
|
||||
|
||||
|
||||
// IMPLEMENTATION OF ABSTRACT MIDI DEVICE METHODS
|
||||
|
||||
// $$kk: 06.24.99: i have this both opening and starting the midi in device.
|
||||
// may want to separate these??
|
||||
protected synchronized void implOpen() throws MidiUnavailableException {
|
||||
if (Printer.trace) Printer.trace("> MidiInDevice: implOpen()");
|
||||
|
||||
int index = ((MidiInDeviceProvider.MidiInDeviceInfo)getDeviceInfo()).getIndex();
|
||||
id = nOpen(index); // can throw MidiUnavailableException
|
||||
|
||||
if (id == 0) {
|
||||
throw new MidiUnavailableException("Unable to open native device");
|
||||
}
|
||||
|
||||
// create / start a thread to get messages
|
||||
if (midiInThread == null) {
|
||||
midiInThread = JSSecurityManager.createThread(this,
|
||||
"Java Sound MidiInDevice Thread", // name
|
||||
false, // daemon
|
||||
-1, // priority
|
||||
true); // doStart
|
||||
}
|
||||
|
||||
nStart(id); // can throw MidiUnavailableException
|
||||
if (Printer.trace) Printer.trace("< MidiInDevice: implOpen() completed");
|
||||
}
|
||||
|
||||
|
||||
// $$kk: 06.24.99: i have this both stopping and closing the midi in device.
|
||||
// may want to separate these??
|
||||
protected synchronized void implClose() {
|
||||
if (Printer.trace) Printer.trace("> MidiInDevice: implClose()");
|
||||
long oldId = id;
|
||||
id = 0;
|
||||
|
||||
super.implClose();
|
||||
|
||||
// close the device
|
||||
nStop(oldId);
|
||||
if (midiInThread != null) {
|
||||
try {
|
||||
midiInThread.join(1000);
|
||||
} catch (InterruptedException e) {
|
||||
// IGNORE EXCEPTION
|
||||
}
|
||||
}
|
||||
nClose(oldId);
|
||||
if (Printer.trace) Printer.trace("< MidiInDevice: implClose() completed");
|
||||
}
|
||||
|
||||
|
||||
public long getMicrosecondPosition() {
|
||||
long timestamp = -1;
|
||||
if (isOpen()) {
|
||||
timestamp = nGetTimeStamp(id);
|
||||
}
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
|
||||
// OVERRIDES OF ABSTRACT MIDI DEVICE METHODS
|
||||
|
||||
|
||||
protected boolean hasTransmitters() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
protected Transmitter createTransmitter() {
|
||||
return new MidiInTransmitter();
|
||||
}
|
||||
|
||||
/**
|
||||
* An own class to distinguish the class name from
|
||||
* the transmitter of other devices
|
||||
*/
|
||||
private final class MidiInTransmitter extends BasicTransmitter {
|
||||
private MidiInTransmitter() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
// RUNNABLE METHOD
|
||||
|
||||
public void run() {
|
||||
// while the device is started, keep trying to get messages.
|
||||
// this thread returns from native code whenever stop() or close() is called
|
||||
while (id!=0) {
|
||||
// go into native code and retrieve messages
|
||||
nGetMessages(id);
|
||||
if (id!=0) {
|
||||
try {
|
||||
Thread.sleep(1);
|
||||
} catch (InterruptedException e) {}
|
||||
}
|
||||
}
|
||||
if(Printer.verbose) Printer.verbose("MidiInDevice Thread exit");
|
||||
// let the thread exit
|
||||
midiInThread = null;
|
||||
}
|
||||
|
||||
|
||||
// CALLBACKS FROM NATIVE
|
||||
|
||||
/**
|
||||
* Callback from native code when a short MIDI event is received from hardware.
|
||||
* @param packedMsg: status | data1 << 8 | data2 << 8
|
||||
* @param timeStamp time-stamp in microseconds
|
||||
*/
|
||||
void callbackShortMessage(int packedMsg, long timeStamp) {
|
||||
if (packedMsg == 0 || id == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*if(Printer.verbose) {
|
||||
int status = packedMsg & 0xFF;
|
||||
int data1 = (packedMsg & 0xFF00)>>8;
|
||||
int data2 = (packedMsg & 0xFF0000)>>16;
|
||||
Printer.verbose(">> MidiInDevice callbackShortMessage: status: " + status + " data1: " + data1 + " data2: " + data2 + " timeStamp: " + timeStamp);
|
||||
}*/
|
||||
|
||||
getTransmitterList().sendMessage(packedMsg, timeStamp);
|
||||
}
|
||||
|
||||
void callbackLongMessage(byte[] data, long timeStamp) {
|
||||
if (id == 0 || data == null) {
|
||||
return;
|
||||
}
|
||||
getTransmitterList().sendMessage(data, timeStamp);
|
||||
}
|
||||
|
||||
// NATIVE METHODS
|
||||
|
||||
private native long nOpen(int index) throws MidiUnavailableException;
|
||||
private native void nClose(long id);
|
||||
|
||||
private native void nStart(long id) throws MidiUnavailableException;
|
||||
private native void nStop(long id);
|
||||
private native long nGetTimeStamp(long id);
|
||||
|
||||
// go into native code and get messages. May be blocking
|
||||
private native void nGetMessages(long id);
|
||||
|
||||
|
||||
}
|
||||
126
jdkSrc/jdk8/com/sun/media/sound/MidiInDeviceProvider.java
Normal file
126
jdkSrc/jdk8/com/sun/media/sound/MidiInDeviceProvider.java
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.media.sound;
|
||||
|
||||
import javax.sound.midi.MidiDevice;
|
||||
|
||||
|
||||
/**
|
||||
* MIDI input device provider.
|
||||
*
|
||||
* @author Kara Kytle
|
||||
* @author Florian Bomers
|
||||
*/
|
||||
public final class MidiInDeviceProvider extends AbstractMidiDeviceProvider {
|
||||
|
||||
/** Cache of info objects for all MIDI output devices on the system. */
|
||||
private static Info[] infos = null;
|
||||
|
||||
/** Cache of open MIDI input devices on the system. */
|
||||
private static MidiDevice[] devices = null;
|
||||
|
||||
private static final boolean enabled;
|
||||
|
||||
// STATIC
|
||||
|
||||
static {
|
||||
// initialize
|
||||
Platform.initialize();
|
||||
enabled = Platform.isMidiIOEnabled();
|
||||
}
|
||||
|
||||
// CONSTRUCTOR
|
||||
|
||||
/**
|
||||
* Required public no-arg constructor.
|
||||
*/
|
||||
public MidiInDeviceProvider() {
|
||||
if (Printer.trace) Printer.trace("MidiInDeviceProvider: constructor");
|
||||
}
|
||||
|
||||
// implementation of abstract methods in AbstractMidiDeviceProvider
|
||||
|
||||
AbstractMidiDeviceProvider.Info createInfo(int index) {
|
||||
if (!enabled) {
|
||||
return null;
|
||||
}
|
||||
return new MidiInDeviceInfo(index, MidiInDeviceProvider.class);
|
||||
}
|
||||
|
||||
MidiDevice createDevice(AbstractMidiDeviceProvider.Info info) {
|
||||
if (enabled && (info instanceof MidiInDeviceInfo)) {
|
||||
return new MidiInDevice(info);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
int getNumDevices() {
|
||||
if (!enabled) {
|
||||
if (Printer.debug)Printer.debug("MidiInDevice not enabled, returning 0 devices");
|
||||
return 0;
|
||||
}
|
||||
int numDevices = nGetNumDevices();
|
||||
if (Printer.debug)Printer.debug("MidiInDeviceProvider.getNumDevices(): devices: " + numDevices);
|
||||
return numDevices;
|
||||
}
|
||||
|
||||
MidiDevice[] getDeviceCache() { return devices; }
|
||||
void setDeviceCache(MidiDevice[] devices) { this.devices = devices; }
|
||||
Info[] getInfoCache() { return infos; }
|
||||
void setInfoCache(Info[] infos) { this.infos = infos; }
|
||||
|
||||
|
||||
// INNER CLASSES
|
||||
|
||||
/**
|
||||
* Info class for MidiInDevices. Adds the
|
||||
* provider's Class to keep the provider class from being
|
||||
* unloaded. Otherwise, at least on JDK1.1.7 and 1.1.8,
|
||||
* the provider class can be unloaded. Then, then the provider
|
||||
* is next invoked, the static block is executed again and a new
|
||||
* instance of the device object is created. Even though the
|
||||
* previous instance may still exist and be open / in use / etc.,
|
||||
* the new instance will not reflect that state...
|
||||
*/
|
||||
static final class MidiInDeviceInfo extends AbstractMidiDeviceProvider.Info {
|
||||
private final Class providerClass;
|
||||
|
||||
private MidiInDeviceInfo(int index, Class providerClass) {
|
||||
super(nGetName(index), nGetVendor(index), nGetDescription(index), nGetVersion(index), index);
|
||||
this.providerClass = providerClass;
|
||||
}
|
||||
|
||||
} // class MidiInDeviceInfo
|
||||
|
||||
|
||||
// NATIVE METHODS
|
||||
|
||||
private static native int nGetNumDevices();
|
||||
private static native String nGetName(int index);
|
||||
private static native String nGetVendor(int index);
|
||||
private static native String nGetDescription(int index);
|
||||
private static native String nGetVersion(int index);
|
||||
}
|
||||
176
jdkSrc/jdk8/com/sun/media/sound/MidiOutDevice.java
Normal file
176
jdkSrc/jdk8/com/sun/media/sound/MidiOutDevice.java
Normal file
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.media.sound;
|
||||
|
||||
import javax.sound.midi.*;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* MidiOutDevice class representing functionality of MidiOut devices.
|
||||
*
|
||||
* @author David Rivas
|
||||
* @author Kara Kytle
|
||||
* @author Florian Bomers
|
||||
*/
|
||||
final class MidiOutDevice extends AbstractMidiDevice {
|
||||
|
||||
// CONSTRUCTOR
|
||||
|
||||
MidiOutDevice(AbstractMidiDeviceProvider.Info info) {
|
||||
super(info);
|
||||
if(Printer.trace) Printer.trace("MidiOutDevice CONSTRUCTOR");
|
||||
}
|
||||
|
||||
|
||||
// IMPLEMENTATION OF ABSTRACT MIDI DEVICE METHODS
|
||||
|
||||
protected synchronized void implOpen() throws MidiUnavailableException {
|
||||
if (Printer.trace) Printer.trace("> MidiOutDevice: implOpen()");
|
||||
int index = ((AbstractMidiDeviceProvider.Info)getDeviceInfo()).getIndex();
|
||||
id = nOpen(index); // can throw MidiUnavailableException
|
||||
if (id == 0) {
|
||||
throw new MidiUnavailableException("Unable to open native device");
|
||||
}
|
||||
if (Printer.trace) Printer.trace("< MidiOutDevice: implOpen(): completed.");
|
||||
}
|
||||
|
||||
|
||||
protected synchronized void implClose() {
|
||||
if (Printer.trace) Printer.trace("> MidiOutDevice: implClose()");
|
||||
// prevent further action
|
||||
long oldId = id;
|
||||
id = 0;
|
||||
|
||||
super.implClose();
|
||||
|
||||
// close the device
|
||||
nClose(oldId);
|
||||
if (Printer.trace) Printer.trace("< MidiOutDevice: implClose(): completed");
|
||||
}
|
||||
|
||||
|
||||
public long getMicrosecondPosition() {
|
||||
long timestamp = -1;
|
||||
if (isOpen()) {
|
||||
timestamp = nGetTimeStamp(id);
|
||||
}
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// OVERRIDES OF ABSTRACT MIDI DEVICE METHODS
|
||||
|
||||
/** Returns if this device supports Receivers.
|
||||
This implementation always returns true.
|
||||
@return true, if the device supports Receivers, false otherwise.
|
||||
*/
|
||||
protected boolean hasReceivers() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
protected Receiver createReceiver() {
|
||||
return new MidiOutReceiver();
|
||||
}
|
||||
|
||||
|
||||
// INNER CLASSES
|
||||
|
||||
final class MidiOutReceiver extends AbstractReceiver {
|
||||
|
||||
void implSend(final MidiMessage message, final long timeStamp) {
|
||||
final int length = message.getLength();
|
||||
final int status = message.getStatus();
|
||||
if (length <= 3 && status != 0xF0 && status != 0xF7) {
|
||||
int packedMsg;
|
||||
if (message instanceof ShortMessage) {
|
||||
if (message instanceof FastShortMessage) {
|
||||
packedMsg = ((FastShortMessage) message).getPackedMsg();
|
||||
} else {
|
||||
ShortMessage msg = (ShortMessage) message;
|
||||
packedMsg = (status & 0xFF)
|
||||
| ((msg.getData1() & 0xFF) << 8)
|
||||
| ((msg.getData2() & 0xFF) << 16);
|
||||
}
|
||||
} else {
|
||||
packedMsg = 0;
|
||||
byte[] data = message.getMessage();
|
||||
if (length>0) {
|
||||
packedMsg = data[0] & 0xFF;
|
||||
if (length>1) {
|
||||
/* We handle meta messages here. The message
|
||||
system reset (FF) doesn't get until here,
|
||||
because it's length is only 1. So if we see
|
||||
a status byte of FF, it's sure that we
|
||||
have a Meta message. */
|
||||
if (status == 0xFF) {
|
||||
return;
|
||||
}
|
||||
packedMsg |= (data[1] & 0xFF) << 8;
|
||||
if (length>2) {
|
||||
packedMsg |= (data[2] & 0xFF) << 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
nSendShortMessage(id, packedMsg, timeStamp);
|
||||
} else {
|
||||
final byte[] data;
|
||||
if (message instanceof FastSysexMessage) {
|
||||
data = ((FastSysexMessage) message).getReadOnlyMessage();
|
||||
} else {
|
||||
data = message.getMessage();
|
||||
}
|
||||
final int dataLength = Math.min(length, data.length);
|
||||
if (dataLength > 0) {
|
||||
nSendLongMessage(id, data, dataLength, timeStamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** shortcut for the Sun implementation */
|
||||
synchronized void sendPackedMidiMessage(int packedMsg, long timeStamp) {
|
||||
if (isOpen() && id != 0) {
|
||||
nSendShortMessage(id, packedMsg, timeStamp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // class MidiOutReceiver
|
||||
|
||||
|
||||
// NATIVE METHODS
|
||||
|
||||
private native long nOpen(int index) throws MidiUnavailableException;
|
||||
private native void nClose(long id);
|
||||
|
||||
private native void nSendShortMessage(long id, int packedMsg, long timeStamp);
|
||||
private native void nSendLongMessage(long id, byte[] data, int size, long timeStamp);
|
||||
private native long nGetTimeStamp(long id);
|
||||
|
||||
} // class MidiOutDevice
|
||||
124
jdkSrc/jdk8/com/sun/media/sound/MidiOutDeviceProvider.java
Normal file
124
jdkSrc/jdk8/com/sun/media/sound/MidiOutDeviceProvider.java
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.media.sound;
|
||||
|
||||
import javax.sound.midi.MidiDevice;
|
||||
|
||||
|
||||
/**
|
||||
* MIDI output device provider.
|
||||
*
|
||||
* @author Kara Kytle
|
||||
* @author Florian Bomers
|
||||
*/
|
||||
public final class MidiOutDeviceProvider extends AbstractMidiDeviceProvider {
|
||||
|
||||
/** Cache of info objects for all MIDI output devices on the system. */
|
||||
private static Info[] infos = null;
|
||||
|
||||
/** Cache of open MIDI output devices on the system. */
|
||||
private static MidiDevice[] devices = null;
|
||||
|
||||
private final static boolean enabled;
|
||||
|
||||
// STATIC
|
||||
|
||||
static {
|
||||
// initialize
|
||||
Platform.initialize();
|
||||
enabled = Platform.isMidiIOEnabled();
|
||||
}
|
||||
|
||||
// CONSTRUCTOR
|
||||
|
||||
/**
|
||||
* Required public no-arg constructor.
|
||||
*/
|
||||
public MidiOutDeviceProvider() {
|
||||
if (Printer.trace) Printer.trace("MidiOutDeviceProvider: constructor");
|
||||
}
|
||||
|
||||
// implementation of abstract methods in AbstractMidiDeviceProvider
|
||||
|
||||
AbstractMidiDeviceProvider.Info createInfo(int index) {
|
||||
if (!enabled) {
|
||||
return null;
|
||||
}
|
||||
return new MidiOutDeviceInfo(index, MidiOutDeviceProvider.class);
|
||||
}
|
||||
|
||||
MidiDevice createDevice(AbstractMidiDeviceProvider.Info info) {
|
||||
if (enabled && (info instanceof MidiOutDeviceInfo)) {
|
||||
return new MidiOutDevice(info);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
int getNumDevices() {
|
||||
if (!enabled) {
|
||||
if (Printer.debug)Printer.debug("MidiOutDevice not enabled, returning 0 devices");
|
||||
return 0;
|
||||
}
|
||||
return nGetNumDevices();
|
||||
}
|
||||
|
||||
MidiDevice[] getDeviceCache() { return devices; }
|
||||
void setDeviceCache(MidiDevice[] devices) { this.devices = devices; }
|
||||
Info[] getInfoCache() { return infos; }
|
||||
void setInfoCache(Info[] infos) { this.infos = infos; }
|
||||
|
||||
|
||||
// INNER CLASSES
|
||||
|
||||
/**
|
||||
* Info class for MidiOutDevices. Adds the
|
||||
* provider's Class to keep the provider class from being
|
||||
* unloaded. Otherwise, at least on JDK1.1.7 and 1.1.8,
|
||||
* the provider class can be unloaded. Then, then the provider
|
||||
* is next invoked, the static block is executed again and a new
|
||||
* instance of the device object is created. Even though the
|
||||
* previous instance may still exist and be open / in use / etc.,
|
||||
* the new instance will not reflect that state...
|
||||
*/
|
||||
static final class MidiOutDeviceInfo extends AbstractMidiDeviceProvider.Info {
|
||||
private final Class providerClass;
|
||||
|
||||
private MidiOutDeviceInfo(int index, Class providerClass) {
|
||||
super(nGetName(index), nGetVendor(index), nGetDescription(index), nGetVersion(index), index);
|
||||
this.providerClass = providerClass;
|
||||
}
|
||||
|
||||
} // class MidiOutDeviceInfo
|
||||
|
||||
|
||||
// NATIVE METHODS
|
||||
|
||||
private static native int nGetNumDevices();
|
||||
private static native String nGetName(int index);
|
||||
private static native String nGetVendor(int index);
|
||||
private static native String nGetDescription(int index);
|
||||
private static native String nGetVersion(int index);
|
||||
}
|
||||
361
jdkSrc/jdk8/com/sun/media/sound/MidiUtils.java
Normal file
361
jdkSrc/jdk8/com/sun/media/sound/MidiUtils.java
Normal file
@@ -0,0 +1,361 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.media.sound;
|
||||
|
||||
import javax.sound.midi.*;
|
||||
import java.util.ArrayList;
|
||||
|
||||
// TODO:
|
||||
// - define and use a global symbolic constant for 60000000 (see convertTempo)
|
||||
|
||||
/**
|
||||
* Some utilities for MIDI (some stuff is used from javax.sound.midi)
|
||||
*
|
||||
* @author Florian Bomers
|
||||
*/
|
||||
public final class MidiUtils {
|
||||
|
||||
public final static int DEFAULT_TEMPO_MPQ = 500000; // 120bpm
|
||||
public final static int META_END_OF_TRACK_TYPE = 0x2F;
|
||||
public final static int META_TEMPO_TYPE = 0x51;
|
||||
|
||||
/**
|
||||
* Suppresses default constructor, ensuring non-instantiability.
|
||||
*/
|
||||
private MidiUtils() {
|
||||
}
|
||||
|
||||
/** return true if the passed message is Meta End Of Track */
|
||||
public static boolean isMetaEndOfTrack(MidiMessage midiMsg) {
|
||||
// first check if it is a META message at all
|
||||
if (midiMsg.getLength() != 3
|
||||
|| midiMsg.getStatus() != MetaMessage.META) {
|
||||
return false;
|
||||
}
|
||||
// now get message and check for end of track
|
||||
byte[] msg = midiMsg.getMessage();
|
||||
return ((msg[1] & 0xFF) == META_END_OF_TRACK_TYPE) && (msg[2] == 0);
|
||||
}
|
||||
|
||||
|
||||
/** return if the given message is a meta tempo message */
|
||||
public static boolean isMetaTempo(MidiMessage midiMsg) {
|
||||
// first check if it is a META message at all
|
||||
if (midiMsg.getLength() != 6
|
||||
|| midiMsg.getStatus() != MetaMessage.META) {
|
||||
return false;
|
||||
}
|
||||
// now get message and check for tempo
|
||||
byte[] msg = midiMsg.getMessage();
|
||||
// meta type must be 0x51, and data length must be 3
|
||||
return ((msg[1] & 0xFF) == META_TEMPO_TYPE) && (msg[2] == 3);
|
||||
}
|
||||
|
||||
|
||||
/** parses this message for a META tempo message and returns
|
||||
* the tempo in MPQ, or -1 if this isn't a tempo message
|
||||
*/
|
||||
public static int getTempoMPQ(MidiMessage midiMsg) {
|
||||
// first check if it is a META message at all
|
||||
if (midiMsg.getLength() != 6
|
||||
|| midiMsg.getStatus() != MetaMessage.META) {
|
||||
return -1;
|
||||
}
|
||||
byte[] msg = midiMsg.getMessage();
|
||||
if (((msg[1] & 0xFF) != META_TEMPO_TYPE) || (msg[2] != 3)) {
|
||||
return -1;
|
||||
}
|
||||
int tempo = (msg[5] & 0xFF)
|
||||
| ((msg[4] & 0xFF) << 8)
|
||||
| ((msg[3] & 0xFF) << 16);
|
||||
return tempo;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* converts<br>
|
||||
* 1 - MPQ-Tempo to BPM tempo<br>
|
||||
* 2 - BPM tempo to MPQ tempo<br>
|
||||
*/
|
||||
public static double convertTempo(double tempo) {
|
||||
if (tempo <= 0) {
|
||||
tempo = 1;
|
||||
}
|
||||
return ((double) 60000000l) / tempo;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* convert tick to microsecond with given tempo.
|
||||
* Does not take tempo changes into account.
|
||||
* Does not work for SMPTE timing!
|
||||
*/
|
||||
public static long ticks2microsec(long tick, double tempoMPQ, int resolution) {
|
||||
return (long) (((double) tick) * tempoMPQ / resolution);
|
||||
}
|
||||
|
||||
/**
|
||||
* convert tempo to microsecond with given tempo
|
||||
* Does not take tempo changes into account.
|
||||
* Does not work for SMPTE timing!
|
||||
*/
|
||||
public static long microsec2ticks(long us, double tempoMPQ, int resolution) {
|
||||
// do not round to nearest tick
|
||||
//return (long) Math.round((((double)us) * resolution) / tempoMPQ);
|
||||
return (long) ((((double)us) * resolution) / tempoMPQ);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Given a tick, convert to microsecond
|
||||
* @param cache tempo info and current tempo
|
||||
*/
|
||||
public static long tick2microsecond(Sequence seq, long tick, TempoCache cache) {
|
||||
if (seq.getDivisionType() != Sequence.PPQ ) {
|
||||
double seconds = ((double)tick / (double)(seq.getDivisionType() * seq.getResolution()));
|
||||
return (long) (1000000 * seconds);
|
||||
}
|
||||
|
||||
if (cache == null) {
|
||||
cache = new TempoCache(seq);
|
||||
}
|
||||
|
||||
int resolution = seq.getResolution();
|
||||
|
||||
long[] ticks = cache.ticks;
|
||||
int[] tempos = cache.tempos; // in MPQ
|
||||
int cacheCount = tempos.length;
|
||||
|
||||
// optimization to not always go through entire list of tempo events
|
||||
int snapshotIndex = cache.snapshotIndex;
|
||||
int snapshotMicro = cache.snapshotMicro;
|
||||
|
||||
// walk through all tempo changes and add time for the respective blocks
|
||||
long us = 0; // microsecond
|
||||
|
||||
if (snapshotIndex <= 0
|
||||
|| snapshotIndex >= cacheCount
|
||||
|| ticks[snapshotIndex] > tick) {
|
||||
snapshotMicro = 0;
|
||||
snapshotIndex = 0;
|
||||
}
|
||||
if (cacheCount > 0) {
|
||||
// this implementation needs a tempo event at tick 0!
|
||||
int i = snapshotIndex + 1;
|
||||
while (i < cacheCount && ticks[i] <= tick) {
|
||||
snapshotMicro += ticks2microsec(ticks[i] - ticks[i - 1], tempos[i - 1], resolution);
|
||||
snapshotIndex = i;
|
||||
i++;
|
||||
}
|
||||
us = snapshotMicro
|
||||
+ ticks2microsec(tick - ticks[snapshotIndex],
|
||||
tempos[snapshotIndex],
|
||||
resolution);
|
||||
}
|
||||
cache.snapshotIndex = snapshotIndex;
|
||||
cache.snapshotMicro = snapshotMicro;
|
||||
return us;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a microsecond time, convert to tick.
|
||||
* returns tempo at the given time in cache.getCurrTempoMPQ
|
||||
*/
|
||||
public static long microsecond2tick(Sequence seq, long micros, TempoCache cache) {
|
||||
if (seq.getDivisionType() != Sequence.PPQ ) {
|
||||
double dTick = ( ((double) micros)
|
||||
* ((double) seq.getDivisionType())
|
||||
* ((double) seq.getResolution()))
|
||||
/ ((double) 1000000);
|
||||
long tick = (long) dTick;
|
||||
if (cache != null) {
|
||||
cache.currTempo = (int) cache.getTempoMPQAt(tick);
|
||||
}
|
||||
return tick;
|
||||
}
|
||||
|
||||
if (cache == null) {
|
||||
cache = new TempoCache(seq);
|
||||
}
|
||||
long[] ticks = cache.ticks;
|
||||
int[] tempos = cache.tempos; // in MPQ
|
||||
int cacheCount = tempos.length;
|
||||
|
||||
int resolution = seq.getResolution();
|
||||
|
||||
long us = 0; long tick = 0; int newReadPos = 0; int i = 1;
|
||||
|
||||
// walk through all tempo changes and add time for the respective blocks
|
||||
// to find the right tick
|
||||
if (micros > 0 && cacheCount > 0) {
|
||||
// this loop requires that the first tempo Event is at time 0
|
||||
while (i < cacheCount) {
|
||||
long nextTime = us + ticks2microsec(ticks[i] - ticks[i - 1],
|
||||
tempos[i - 1], resolution);
|
||||
if (nextTime > micros) {
|
||||
break;
|
||||
}
|
||||
us = nextTime;
|
||||
i++;
|
||||
}
|
||||
tick = ticks[i - 1] + microsec2ticks(micros - us, tempos[i - 1], resolution);
|
||||
if (Printer.debug) Printer.debug("microsecond2tick(" + (micros / 1000)+") = "+tick+" ticks.");
|
||||
//if (Printer.debug) Printer.debug(" -> convert back = " + (tick2microsecond(seq, tick, null) / 1000)+" microseconds");
|
||||
}
|
||||
cache.currTempo = tempos[i - 1];
|
||||
return tick;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Binary search for the event indexes of the track
|
||||
*
|
||||
* @param tick - tick number of index to be found in array
|
||||
* @return index in track which is on or after "tick".
|
||||
* if no entries are found that follow after tick, track.size() is returned
|
||||
*/
|
||||
public static int tick2index(Track track, long tick) {
|
||||
int ret = 0;
|
||||
if (tick > 0) {
|
||||
int low = 0;
|
||||
int high = track.size() - 1;
|
||||
while (low < high) {
|
||||
// take the middle event as estimate
|
||||
ret = (low + high) >> 1;
|
||||
// tick of estimate
|
||||
long t = track.get(ret).getTick();
|
||||
if (t == tick) {
|
||||
break;
|
||||
} else if (t < tick) {
|
||||
// estimate too low
|
||||
if (low == high - 1) {
|
||||
// "or after tick"
|
||||
ret++;
|
||||
break;
|
||||
}
|
||||
low = ret;
|
||||
} else { // if (t>tick)
|
||||
// estimate too high
|
||||
high = ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
public static final class TempoCache {
|
||||
long[] ticks;
|
||||
int[] tempos; // in MPQ
|
||||
// index in ticks/tempos at the snapshot
|
||||
int snapshotIndex = 0;
|
||||
// microsecond at the snapshot
|
||||
int snapshotMicro = 0;
|
||||
|
||||
int currTempo; // MPQ, used as return value for microsecond2tick
|
||||
|
||||
private boolean firstTempoIsFake = false;
|
||||
|
||||
public TempoCache() {
|
||||
// just some defaults, to prevents weird stuff
|
||||
ticks = new long[1];
|
||||
tempos = new int[1];
|
||||
tempos[0] = DEFAULT_TEMPO_MPQ;
|
||||
snapshotIndex = 0;
|
||||
snapshotMicro = 0;
|
||||
}
|
||||
|
||||
public TempoCache(Sequence seq) {
|
||||
this();
|
||||
refresh(seq);
|
||||
}
|
||||
|
||||
|
||||
public synchronized void refresh(Sequence seq) {
|
||||
ArrayList list = new ArrayList();
|
||||
Track[] tracks = seq.getTracks();
|
||||
if (tracks.length > 0) {
|
||||
// tempo events only occur in track 0
|
||||
Track track = tracks[0];
|
||||
int c = track.size();
|
||||
for (int i = 0; i < c; i++) {
|
||||
MidiEvent ev = track.get(i);
|
||||
MidiMessage msg = ev.getMessage();
|
||||
if (isMetaTempo(msg)) {
|
||||
// found a tempo event. Add it to the list
|
||||
list.add(ev);
|
||||
}
|
||||
}
|
||||
}
|
||||
int size = list.size() + 1;
|
||||
firstTempoIsFake = true;
|
||||
if ((size > 1)
|
||||
&& (((MidiEvent) list.get(0)).getTick() == 0)) {
|
||||
// do not need to add an initial tempo event at the beginning
|
||||
size--;
|
||||
firstTempoIsFake = false;
|
||||
}
|
||||
ticks = new long[size];
|
||||
tempos = new int[size];
|
||||
int e = 0;
|
||||
if (firstTempoIsFake) {
|
||||
// add tempo 120 at beginning
|
||||
ticks[0] = 0;
|
||||
tempos[0] = DEFAULT_TEMPO_MPQ;
|
||||
e++;
|
||||
}
|
||||
for (int i = 0; i < list.size(); i++, e++) {
|
||||
MidiEvent evt = (MidiEvent) list.get(i);
|
||||
ticks[e] = evt.getTick();
|
||||
tempos[e] = getTempoMPQ(evt.getMessage());
|
||||
}
|
||||
snapshotIndex = 0;
|
||||
snapshotMicro = 0;
|
||||
}
|
||||
|
||||
public int getCurrTempoMPQ() {
|
||||
return currTempo;
|
||||
}
|
||||
|
||||
float getTempoMPQAt(long tick) {
|
||||
return getTempoMPQAt(tick, -1.0f);
|
||||
}
|
||||
|
||||
synchronized float getTempoMPQAt(long tick, float startTempoMPQ) {
|
||||
for (int i = 0; i < ticks.length; i++) {
|
||||
if (ticks[i] > tick) {
|
||||
if (i > 0) i--;
|
||||
if (startTempoMPQ > 0 && i == 0 && firstTempoIsFake) {
|
||||
return startTempoMPQ;
|
||||
}
|
||||
return (float) tempos[i];
|
||||
}
|
||||
}
|
||||
return tempos[tempos.length - 1];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
126
jdkSrc/jdk8/com/sun/media/sound/ModelAbstractChannelMixer.java
Normal file
126
jdkSrc/jdk8/com/sun/media/sound/ModelAbstractChannelMixer.java
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
/**
|
||||
* ModelAbstractChannelMixer is ready for use class to implement
|
||||
* ModelChannelMixer interface.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public abstract class ModelAbstractChannelMixer implements ModelChannelMixer {
|
||||
|
||||
public abstract boolean process(float[][] buffer, int offset, int len);
|
||||
|
||||
public abstract void stop();
|
||||
|
||||
public void allNotesOff() {
|
||||
}
|
||||
|
||||
public void allSoundOff() {
|
||||
}
|
||||
|
||||
public void controlChange(int controller, int value) {
|
||||
}
|
||||
|
||||
public int getChannelPressure() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getController(int controller) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public boolean getMono() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean getMute() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean getOmni() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getPitchBend() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getPolyPressure(int noteNumber) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getProgram() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public boolean getSolo() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean localControl(boolean on) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void noteOff(int noteNumber) {
|
||||
}
|
||||
|
||||
public void noteOff(int noteNumber, int velocity) {
|
||||
}
|
||||
|
||||
public void noteOn(int noteNumber, int velocity) {
|
||||
}
|
||||
|
||||
public void programChange(int program) {
|
||||
}
|
||||
|
||||
public void programChange(int bank, int program) {
|
||||
}
|
||||
|
||||
public void resetAllControllers() {
|
||||
}
|
||||
|
||||
public void setChannelPressure(int pressure) {
|
||||
}
|
||||
|
||||
public void setMono(boolean on) {
|
||||
}
|
||||
|
||||
public void setMute(boolean mute) {
|
||||
}
|
||||
|
||||
public void setOmni(boolean on) {
|
||||
}
|
||||
|
||||
public void setPitchBend(int bend) {
|
||||
}
|
||||
|
||||
public void setPolyPressure(int noteNumber, int pressure) {
|
||||
}
|
||||
|
||||
public void setSolo(boolean soloState) {
|
||||
}
|
||||
}
|
||||
200
jdkSrc/jdk8/com/sun/media/sound/ModelAbstractOscillator.java
Normal file
200
jdkSrc/jdk8/com/sun/media/sound/ModelAbstractOscillator.java
Normal file
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.sound.midi.Instrument;
|
||||
import javax.sound.midi.MidiChannel;
|
||||
import javax.sound.midi.Patch;
|
||||
import javax.sound.midi.Soundbank;
|
||||
import javax.sound.midi.SoundbankResource;
|
||||
import javax.sound.midi.VoiceStatus;
|
||||
|
||||
/**
|
||||
* A abstract class used to simplify creating custom ModelOscillator.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public abstract class ModelAbstractOscillator
|
||||
implements ModelOscillator, ModelOscillatorStream, Soundbank {
|
||||
|
||||
protected float pitch = 6000;
|
||||
protected float samplerate;
|
||||
protected MidiChannel channel;
|
||||
protected VoiceStatus voice;
|
||||
protected int noteNumber;
|
||||
protected int velocity;
|
||||
protected boolean on = false;
|
||||
|
||||
public void init() {
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
}
|
||||
|
||||
public void noteOff(int velocity) {
|
||||
on = false;
|
||||
}
|
||||
|
||||
public void noteOn(MidiChannel channel, VoiceStatus voice, int noteNumber,
|
||||
int velocity) {
|
||||
this.channel = channel;
|
||||
this.voice = voice;
|
||||
this.noteNumber = noteNumber;
|
||||
this.velocity = velocity;
|
||||
on = true;
|
||||
}
|
||||
|
||||
public int read(float[][] buffer, int offset, int len) throws IOException {
|
||||
return -1;
|
||||
}
|
||||
|
||||
public MidiChannel getChannel() {
|
||||
return channel;
|
||||
}
|
||||
|
||||
public VoiceStatus getVoice() {
|
||||
return voice;
|
||||
}
|
||||
|
||||
public int getNoteNumber() {
|
||||
return noteNumber;
|
||||
}
|
||||
|
||||
public int getVelocity() {
|
||||
return velocity;
|
||||
}
|
||||
|
||||
public boolean isOn() {
|
||||
return on;
|
||||
}
|
||||
|
||||
public void setPitch(float pitch) {
|
||||
this.pitch = pitch;
|
||||
}
|
||||
|
||||
public float getPitch() {
|
||||
return pitch;
|
||||
}
|
||||
|
||||
public void setSampleRate(float samplerate) {
|
||||
this.samplerate = samplerate;
|
||||
}
|
||||
|
||||
public float getSampleRate() {
|
||||
return samplerate;
|
||||
}
|
||||
|
||||
public float getAttenuation() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getChannels() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return getClass().getName();
|
||||
}
|
||||
|
||||
public Patch getPatch() {
|
||||
return new Patch(0, 0);
|
||||
}
|
||||
|
||||
public ModelOscillatorStream open(float samplerate) {
|
||||
ModelAbstractOscillator oscs;
|
||||
try {
|
||||
oscs = this.getClass().newInstance();
|
||||
} catch (InstantiationException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
oscs.setSampleRate(samplerate);
|
||||
oscs.init();
|
||||
return oscs;
|
||||
}
|
||||
|
||||
public ModelPerformer getPerformer() {
|
||||
// Create performer for my custom oscillirator
|
||||
ModelPerformer performer = new ModelPerformer();
|
||||
performer.getOscillators().add(this);
|
||||
return performer;
|
||||
|
||||
}
|
||||
|
||||
public ModelInstrument getInstrument() {
|
||||
// Create Instrument object around my performer
|
||||
SimpleInstrument ins = new SimpleInstrument();
|
||||
ins.setName(getName());
|
||||
ins.add(getPerformer());
|
||||
ins.setPatch(getPatch());
|
||||
return ins;
|
||||
|
||||
}
|
||||
|
||||
public Soundbank getSoundBank() {
|
||||
// Create Soundbank object around the instrument
|
||||
SimpleSoundbank sbk = new SimpleSoundbank();
|
||||
sbk.addInstrument(getInstrument());
|
||||
return sbk;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
public Instrument getInstrument(Patch patch) {
|
||||
Instrument ins = getInstrument();
|
||||
Patch p = ins.getPatch();
|
||||
if (p.getBank() != patch.getBank())
|
||||
return null;
|
||||
if (p.getProgram() != patch.getProgram())
|
||||
return null;
|
||||
if (p instanceof ModelPatch && patch instanceof ModelPatch) {
|
||||
if (((ModelPatch)p).isPercussion()
|
||||
!= ((ModelPatch)patch).isPercussion()) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return ins;
|
||||
}
|
||||
|
||||
public Instrument[] getInstruments() {
|
||||
return new Instrument[]{getInstrument()};
|
||||
}
|
||||
|
||||
public SoundbankResource[] getResources() {
|
||||
return new SoundbankResource[0];
|
||||
}
|
||||
|
||||
public String getVendor() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
331
jdkSrc/jdk8/com/sun/media/sound/ModelByteBuffer.java
Normal file
331
jdkSrc/jdk8/com/sun/media/sound/ModelByteBuffer.java
Normal file
@@ -0,0 +1,331 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* This class is a pointer to a binary array either in memory or on disk.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public final class ModelByteBuffer {
|
||||
|
||||
private ModelByteBuffer root = this;
|
||||
private File file;
|
||||
private long fileoffset;
|
||||
private byte[] buffer;
|
||||
private long offset;
|
||||
private final long len;
|
||||
|
||||
private class RandomFileInputStream extends InputStream {
|
||||
|
||||
private final RandomAccessFile raf;
|
||||
private long left;
|
||||
private long mark = 0;
|
||||
private long markleft = 0;
|
||||
|
||||
RandomFileInputStream() throws IOException {
|
||||
raf = new RandomAccessFile(root.file, "r");
|
||||
raf.seek(root.fileoffset + arrayOffset());
|
||||
left = capacity();
|
||||
}
|
||||
|
||||
public int available() throws IOException {
|
||||
if (left > Integer.MAX_VALUE)
|
||||
return Integer.MAX_VALUE;
|
||||
return (int)left;
|
||||
}
|
||||
|
||||
public synchronized void mark(int readlimit) {
|
||||
try {
|
||||
mark = raf.getFilePointer();
|
||||
markleft = left;
|
||||
} catch (IOException e) {
|
||||
//e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean markSupported() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public synchronized void reset() throws IOException {
|
||||
raf.seek(mark);
|
||||
left = markleft;
|
||||
}
|
||||
|
||||
public long skip(long n) throws IOException {
|
||||
if( n < 0)
|
||||
return 0;
|
||||
if (n > left)
|
||||
n = left;
|
||||
long p = raf.getFilePointer();
|
||||
raf.seek(p + n);
|
||||
left -= n;
|
||||
return n;
|
||||
}
|
||||
|
||||
public int read(byte b[], int off, int len) throws IOException {
|
||||
if (len > left)
|
||||
len = (int)left;
|
||||
if (left == 0)
|
||||
return -1;
|
||||
len = raf.read(b, off, len);
|
||||
if (len == -1)
|
||||
return -1;
|
||||
left -= len;
|
||||
return len;
|
||||
}
|
||||
|
||||
public int read(byte[] b) throws IOException {
|
||||
int len = b.length;
|
||||
if (len > left)
|
||||
len = (int)left;
|
||||
if (left == 0)
|
||||
return -1;
|
||||
len = raf.read(b, 0, len);
|
||||
if (len == -1)
|
||||
return -1;
|
||||
left -= len;
|
||||
return len;
|
||||
}
|
||||
|
||||
public int read() throws IOException {
|
||||
if (left == 0)
|
||||
return -1;
|
||||
int b = raf.read();
|
||||
if (b == -1)
|
||||
return -1;
|
||||
left--;
|
||||
return b;
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
raf.close();
|
||||
}
|
||||
}
|
||||
|
||||
private ModelByteBuffer(ModelByteBuffer parent,
|
||||
long beginIndex, long endIndex, boolean independent) {
|
||||
this.root = parent.root;
|
||||
this.offset = 0;
|
||||
long parent_len = parent.len;
|
||||
if (beginIndex < 0)
|
||||
beginIndex = 0;
|
||||
if (beginIndex > parent_len)
|
||||
beginIndex = parent_len;
|
||||
if (endIndex < 0)
|
||||
endIndex = 0;
|
||||
if (endIndex > parent_len)
|
||||
endIndex = parent_len;
|
||||
if (beginIndex > endIndex)
|
||||
beginIndex = endIndex;
|
||||
offset = beginIndex;
|
||||
len = endIndex - beginIndex;
|
||||
if (independent) {
|
||||
buffer = root.buffer;
|
||||
if (root.file != null) {
|
||||
file = root.file;
|
||||
fileoffset = root.fileoffset + arrayOffset();
|
||||
offset = 0;
|
||||
} else
|
||||
offset = arrayOffset();
|
||||
root = this;
|
||||
}
|
||||
}
|
||||
|
||||
public ModelByteBuffer(byte[] buffer) {
|
||||
this.buffer = buffer;
|
||||
this.offset = 0;
|
||||
this.len = buffer.length;
|
||||
}
|
||||
|
||||
public ModelByteBuffer(byte[] buffer, int offset, int len) {
|
||||
this.buffer = buffer;
|
||||
this.offset = offset;
|
||||
this.len = len;
|
||||
}
|
||||
|
||||
public ModelByteBuffer(File file) {
|
||||
this.file = file;
|
||||
this.fileoffset = 0;
|
||||
this.len = file.length();
|
||||
}
|
||||
|
||||
public ModelByteBuffer(File file, long offset, long len) {
|
||||
this.file = file;
|
||||
this.fileoffset = offset;
|
||||
this.len = len;
|
||||
}
|
||||
|
||||
public void writeTo(OutputStream out) throws IOException {
|
||||
if (root.file != null && root.buffer == null) {
|
||||
try (InputStream is = getInputStream()) {
|
||||
byte[] buff = new byte[1024];
|
||||
int ret;
|
||||
while ((ret = is.read(buff)) != -1) {
|
||||
out.write(buff, 0, ret);
|
||||
}
|
||||
}
|
||||
} else
|
||||
out.write(array(), (int) arrayOffset(), (int) capacity());
|
||||
}
|
||||
|
||||
public InputStream getInputStream() {
|
||||
if (root.file != null && root.buffer == null) {
|
||||
try {
|
||||
return new RandomFileInputStream();
|
||||
} catch (IOException e) {
|
||||
//e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return new ByteArrayInputStream(array(),
|
||||
(int)arrayOffset(), (int)capacity());
|
||||
}
|
||||
|
||||
public ModelByteBuffer subbuffer(long beginIndex) {
|
||||
return subbuffer(beginIndex, capacity());
|
||||
}
|
||||
|
||||
public ModelByteBuffer subbuffer(long beginIndex, long endIndex) {
|
||||
return subbuffer(beginIndex, endIndex, false);
|
||||
}
|
||||
|
||||
public ModelByteBuffer subbuffer(long beginIndex, long endIndex,
|
||||
boolean independent) {
|
||||
return new ModelByteBuffer(this, beginIndex, endIndex, independent);
|
||||
}
|
||||
|
||||
public byte[] array() {
|
||||
return root.buffer;
|
||||
}
|
||||
|
||||
public long arrayOffset() {
|
||||
if (root != this)
|
||||
return root.arrayOffset() + offset;
|
||||
return offset;
|
||||
}
|
||||
|
||||
public long capacity() {
|
||||
return len;
|
||||
}
|
||||
|
||||
public ModelByteBuffer getRoot() {
|
||||
return root;
|
||||
}
|
||||
|
||||
public File getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
public long getFilePointer() {
|
||||
return fileoffset;
|
||||
}
|
||||
|
||||
public static void loadAll(Collection<ModelByteBuffer> col)
|
||||
throws IOException {
|
||||
File selfile = null;
|
||||
RandomAccessFile raf = null;
|
||||
try {
|
||||
for (ModelByteBuffer mbuff : col) {
|
||||
mbuff = mbuff.root;
|
||||
if (mbuff.file == null)
|
||||
continue;
|
||||
if (mbuff.buffer != null)
|
||||
continue;
|
||||
if (selfile == null || !selfile.equals(mbuff.file)) {
|
||||
if (raf != null) {
|
||||
raf.close();
|
||||
raf = null;
|
||||
}
|
||||
selfile = mbuff.file;
|
||||
raf = new RandomAccessFile(mbuff.file, "r");
|
||||
}
|
||||
raf.seek(mbuff.fileoffset);
|
||||
byte[] buffer = new byte[(int) mbuff.capacity()];
|
||||
|
||||
int read = 0;
|
||||
int avail = buffer.length;
|
||||
while (read != avail) {
|
||||
if (avail - read > 65536) {
|
||||
raf.readFully(buffer, read, 65536);
|
||||
read += 65536;
|
||||
} else {
|
||||
raf.readFully(buffer, read, avail - read);
|
||||
read = avail;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
mbuff.buffer = buffer;
|
||||
mbuff.offset = 0;
|
||||
}
|
||||
} finally {
|
||||
if (raf != null)
|
||||
raf.close();
|
||||
}
|
||||
}
|
||||
|
||||
public void load() throws IOException {
|
||||
if (root != this) {
|
||||
root.load();
|
||||
return;
|
||||
}
|
||||
if (buffer != null)
|
||||
return;
|
||||
if (file == null) {
|
||||
throw new IllegalStateException(
|
||||
"No file associated with this ByteBuffer!");
|
||||
}
|
||||
|
||||
DataInputStream is = new DataInputStream(getInputStream());
|
||||
buffer = new byte[(int) capacity()];
|
||||
offset = 0;
|
||||
is.readFully(buffer);
|
||||
is.close();
|
||||
|
||||
}
|
||||
|
||||
public void unload() {
|
||||
if (root != this) {
|
||||
root.unload();
|
||||
return;
|
||||
}
|
||||
if (file == null) {
|
||||
throw new IllegalStateException(
|
||||
"No file associated with this ByteBuffer!");
|
||||
}
|
||||
root.buffer = null;
|
||||
}
|
||||
}
|
||||
282
jdkSrc/jdk8/com/sun/media/sound/ModelByteBufferWavetable.java
Normal file
282
jdkSrc/jdk8/com/sun/media/sound/ModelByteBufferWavetable.java
Normal file
@@ -0,0 +1,282 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import javax.sound.sampled.AudioFormat;
|
||||
import javax.sound.sampled.AudioInputStream;
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
import javax.sound.sampled.AudioFormat.Encoding;
|
||||
|
||||
/**
|
||||
* Wavetable oscillator for pre-loaded data.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public final class ModelByteBufferWavetable implements ModelWavetable {
|
||||
|
||||
private class Buffer8PlusInputStream extends InputStream {
|
||||
|
||||
private final boolean bigendian;
|
||||
private final int framesize_pc;
|
||||
int pos = 0;
|
||||
int pos2 = 0;
|
||||
int markpos = 0;
|
||||
int markpos2 = 0;
|
||||
|
||||
Buffer8PlusInputStream() {
|
||||
framesize_pc = format.getFrameSize() / format.getChannels();
|
||||
bigendian = format.isBigEndian();
|
||||
}
|
||||
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
int avail = available();
|
||||
if (avail <= 0)
|
||||
return -1;
|
||||
if (len > avail)
|
||||
len = avail;
|
||||
byte[] buff1 = buffer.array();
|
||||
byte[] buff2 = buffer8.array();
|
||||
pos += buffer.arrayOffset();
|
||||
pos2 += buffer8.arrayOffset();
|
||||
if (bigendian) {
|
||||
for (int i = 0; i < len; i += (framesize_pc + 1)) {
|
||||
System.arraycopy(buff1, pos, b, i, framesize_pc);
|
||||
System.arraycopy(buff2, pos2, b, i + framesize_pc, 1);
|
||||
pos += framesize_pc;
|
||||
pos2 += 1;
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < len; i += (framesize_pc + 1)) {
|
||||
System.arraycopy(buff2, pos2, b, i, 1);
|
||||
System.arraycopy(buff1, pos, b, i + 1, framesize_pc);
|
||||
pos += framesize_pc;
|
||||
pos2 += 1;
|
||||
}
|
||||
}
|
||||
pos -= buffer.arrayOffset();
|
||||
pos2 -= buffer8.arrayOffset();
|
||||
return len;
|
||||
}
|
||||
|
||||
public long skip(long n) throws IOException {
|
||||
int avail = available();
|
||||
if (avail <= 0)
|
||||
return -1;
|
||||
if (n > avail)
|
||||
n = avail;
|
||||
pos += (n / (framesize_pc + 1)) * (framesize_pc);
|
||||
pos2 += n / (framesize_pc + 1);
|
||||
return super.skip(n);
|
||||
}
|
||||
|
||||
public int read(byte[] b) throws IOException {
|
||||
return read(b, 0, b.length);
|
||||
}
|
||||
|
||||
public int read() throws IOException {
|
||||
byte[] b = new byte[1];
|
||||
int ret = read(b, 0, 1);
|
||||
if (ret == -1)
|
||||
return -1;
|
||||
return 0 & 0xFF;
|
||||
}
|
||||
|
||||
public boolean markSupported() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public int available() throws IOException {
|
||||
return (int)buffer.capacity() + (int)buffer8.capacity() - pos - pos2;
|
||||
}
|
||||
|
||||
public synchronized void mark(int readlimit) {
|
||||
markpos = pos;
|
||||
markpos2 = pos2;
|
||||
}
|
||||
|
||||
public synchronized void reset() throws IOException {
|
||||
pos = markpos;
|
||||
pos2 = markpos2;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private float loopStart = -1;
|
||||
private float loopLength = -1;
|
||||
private final ModelByteBuffer buffer;
|
||||
private ModelByteBuffer buffer8 = null;
|
||||
private AudioFormat format = null;
|
||||
private float pitchcorrection = 0;
|
||||
private float attenuation = 0;
|
||||
private int loopType = LOOP_TYPE_OFF;
|
||||
|
||||
public ModelByteBufferWavetable(ModelByteBuffer buffer) {
|
||||
this.buffer = buffer;
|
||||
}
|
||||
|
||||
public ModelByteBufferWavetable(ModelByteBuffer buffer,
|
||||
float pitchcorrection) {
|
||||
this.buffer = buffer;
|
||||
this.pitchcorrection = pitchcorrection;
|
||||
}
|
||||
|
||||
public ModelByteBufferWavetable(ModelByteBuffer buffer, AudioFormat format) {
|
||||
this.format = format;
|
||||
this.buffer = buffer;
|
||||
}
|
||||
|
||||
public ModelByteBufferWavetable(ModelByteBuffer buffer, AudioFormat format,
|
||||
float pitchcorrection) {
|
||||
this.format = format;
|
||||
this.buffer = buffer;
|
||||
this.pitchcorrection = pitchcorrection;
|
||||
}
|
||||
|
||||
public void set8BitExtensionBuffer(ModelByteBuffer buffer) {
|
||||
buffer8 = buffer;
|
||||
}
|
||||
|
||||
public ModelByteBuffer get8BitExtensionBuffer() {
|
||||
return buffer8;
|
||||
}
|
||||
|
||||
public ModelByteBuffer getBuffer() {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public AudioFormat getFormat() {
|
||||
if (format == null) {
|
||||
if (buffer == null)
|
||||
return null;
|
||||
InputStream is = buffer.getInputStream();
|
||||
AudioFormat format = null;
|
||||
try {
|
||||
format = AudioSystem.getAudioFileFormat(is).getFormat();
|
||||
} catch (Exception e) {
|
||||
//e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
is.close();
|
||||
} catch (IOException e) {
|
||||
//e.printStackTrace();
|
||||
}
|
||||
return format;
|
||||
}
|
||||
return format;
|
||||
}
|
||||
|
||||
public AudioFloatInputStream openStream() {
|
||||
if (buffer == null)
|
||||
return null;
|
||||
if (format == null) {
|
||||
InputStream is = buffer.getInputStream();
|
||||
AudioInputStream ais = null;
|
||||
try {
|
||||
ais = AudioSystem.getAudioInputStream(is);
|
||||
} catch (Exception e) {
|
||||
//e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
return AudioFloatInputStream.getInputStream(ais);
|
||||
}
|
||||
if (buffer.array() == null) {
|
||||
return AudioFloatInputStream.getInputStream(new AudioInputStream(
|
||||
buffer.getInputStream(), format,
|
||||
buffer.capacity() / format.getFrameSize()));
|
||||
}
|
||||
if (buffer8 != null) {
|
||||
if (format.getEncoding().equals(Encoding.PCM_SIGNED)
|
||||
|| format.getEncoding().equals(Encoding.PCM_UNSIGNED)) {
|
||||
InputStream is = new Buffer8PlusInputStream();
|
||||
AudioFormat format2 = new AudioFormat(
|
||||
format.getEncoding(),
|
||||
format.getSampleRate(),
|
||||
format.getSampleSizeInBits() + 8,
|
||||
format.getChannels(),
|
||||
format.getFrameSize() + (1 * format.getChannels()),
|
||||
format.getFrameRate(),
|
||||
format.isBigEndian());
|
||||
|
||||
AudioInputStream ais = new AudioInputStream(is, format2,
|
||||
buffer.capacity() / format.getFrameSize());
|
||||
return AudioFloatInputStream.getInputStream(ais);
|
||||
}
|
||||
}
|
||||
return AudioFloatInputStream.getInputStream(format, buffer.array(),
|
||||
(int)buffer.arrayOffset(), (int)buffer.capacity());
|
||||
}
|
||||
|
||||
public int getChannels() {
|
||||
return getFormat().getChannels();
|
||||
}
|
||||
|
||||
public ModelOscillatorStream open(float samplerate) {
|
||||
// ModelWavetableOscillator doesn't support ModelOscillatorStream
|
||||
return null;
|
||||
}
|
||||
|
||||
// attenuation is in cB
|
||||
public float getAttenuation() {
|
||||
return attenuation;
|
||||
}
|
||||
// attenuation is in cB
|
||||
public void setAttenuation(float attenuation) {
|
||||
this.attenuation = attenuation;
|
||||
}
|
||||
|
||||
public float getLoopLength() {
|
||||
return loopLength;
|
||||
}
|
||||
|
||||
public void setLoopLength(float loopLength) {
|
||||
this.loopLength = loopLength;
|
||||
}
|
||||
|
||||
public float getLoopStart() {
|
||||
return loopStart;
|
||||
}
|
||||
|
||||
public void setLoopStart(float loopStart) {
|
||||
this.loopStart = loopStart;
|
||||
}
|
||||
|
||||
public void setLoopType(int loopType) {
|
||||
this.loopType = loopType;
|
||||
}
|
||||
|
||||
public int getLoopType() {
|
||||
return loopType;
|
||||
}
|
||||
|
||||
public float getPitchcorrection() {
|
||||
return pitchcorrection;
|
||||
}
|
||||
|
||||
public void setPitchcorrection(float pitchcorrection) {
|
||||
this.pitchcorrection = pitchcorrection;
|
||||
}
|
||||
}
|
||||
50
jdkSrc/jdk8/com/sun/media/sound/ModelChannelMixer.java
Normal file
50
jdkSrc/jdk8/com/sun/media/sound/ModelChannelMixer.java
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
import javax.sound.midi.MidiChannel;
|
||||
|
||||
/**
|
||||
* ModelChannelMixer is used to process channel voice mix output before going
|
||||
* to master output.<br>
|
||||
* It can be used to:<br>
|
||||
* <ul>
|
||||
* <li>Implement non-voice oriented instruments.</li>
|
||||
* <li>Add insert effect to instruments; for example distortion effect.</li>
|
||||
* </ui>
|
||||
* <p>
|
||||
* <b>Warning! Classes that implements ModelChannelMixer must be thread-safe.</b>
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public interface ModelChannelMixer extends MidiChannel {
|
||||
|
||||
// Used to process input audio from voices mix.
|
||||
public boolean process(float[][] buffer, int offset, int len);
|
||||
|
||||
// Is used to trigger that this mixer is not be used
|
||||
// and it should fade out.
|
||||
public void stop();
|
||||
}
|
||||
135
jdkSrc/jdk8/com/sun/media/sound/ModelConnectionBlock.java
Normal file
135
jdkSrc/jdk8/com/sun/media/sound/ModelConnectionBlock.java
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Connection blocks are used to connect source variable
|
||||
* to a destination variable.
|
||||
* For example Note On velocity can be connected to output gain.
|
||||
* In DLS this is called articulator and in SoundFonts (SF2) a modulator.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public final class ModelConnectionBlock {
|
||||
|
||||
//
|
||||
// source1 * source2 * scale -> destination
|
||||
//
|
||||
private final static ModelSource[] no_sources = new ModelSource[0];
|
||||
private ModelSource[] sources = no_sources;
|
||||
private double scale = 1;
|
||||
private ModelDestination destination;
|
||||
|
||||
public ModelConnectionBlock() {
|
||||
}
|
||||
|
||||
public ModelConnectionBlock(double scale, ModelDestination destination) {
|
||||
this.scale = scale;
|
||||
this.destination = destination;
|
||||
}
|
||||
|
||||
public ModelConnectionBlock(ModelSource source,
|
||||
ModelDestination destination) {
|
||||
if (source != null) {
|
||||
this.sources = new ModelSource[1];
|
||||
this.sources[0] = source;
|
||||
}
|
||||
this.destination = destination;
|
||||
}
|
||||
|
||||
public ModelConnectionBlock(ModelSource source, double scale,
|
||||
ModelDestination destination) {
|
||||
if (source != null) {
|
||||
this.sources = new ModelSource[1];
|
||||
this.sources[0] = source;
|
||||
}
|
||||
this.scale = scale;
|
||||
this.destination = destination;
|
||||
}
|
||||
|
||||
public ModelConnectionBlock(ModelSource source, ModelSource control,
|
||||
ModelDestination destination) {
|
||||
if (source != null) {
|
||||
if (control == null) {
|
||||
this.sources = new ModelSource[1];
|
||||
this.sources[0] = source;
|
||||
} else {
|
||||
this.sources = new ModelSource[2];
|
||||
this.sources[0] = source;
|
||||
this.sources[1] = control;
|
||||
}
|
||||
}
|
||||
this.destination = destination;
|
||||
}
|
||||
|
||||
public ModelConnectionBlock(ModelSource source, ModelSource control,
|
||||
double scale, ModelDestination destination) {
|
||||
if (source != null) {
|
||||
if (control == null) {
|
||||
this.sources = new ModelSource[1];
|
||||
this.sources[0] = source;
|
||||
} else {
|
||||
this.sources = new ModelSource[2];
|
||||
this.sources[0] = source;
|
||||
this.sources[1] = control;
|
||||
}
|
||||
}
|
||||
this.scale = scale;
|
||||
this.destination = destination;
|
||||
}
|
||||
|
||||
public ModelDestination getDestination() {
|
||||
return destination;
|
||||
}
|
||||
|
||||
public void setDestination(ModelDestination destination) {
|
||||
this.destination = destination;
|
||||
}
|
||||
|
||||
public double getScale() {
|
||||
return scale;
|
||||
}
|
||||
|
||||
public void setScale(double scale) {
|
||||
this.scale = scale;
|
||||
}
|
||||
|
||||
public ModelSource[] getSources() {
|
||||
return Arrays.copyOf(sources, sources.length);
|
||||
}
|
||||
|
||||
public void setSources(ModelSource[] source) {
|
||||
this.sources = source == null ? no_sources : Arrays.copyOf(source, source.length);
|
||||
}
|
||||
|
||||
public void addSource(ModelSource source) {
|
||||
ModelSource[] oldsources = sources;
|
||||
sources = new ModelSource[oldsources.length + 1];
|
||||
System.arraycopy(oldsources, 0, sources, 0, oldsources.length);
|
||||
sources[sources.length - 1] = source;
|
||||
}
|
||||
}
|
||||
117
jdkSrc/jdk8/com/sun/media/sound/ModelDestination.java
Normal file
117
jdkSrc/jdk8/com/sun/media/sound/ModelDestination.java
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
/**
|
||||
* This class is used to identify destinations in connection blocks,
|
||||
* see ModelConnectionBlock.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public final class ModelDestination {
|
||||
|
||||
public static final ModelIdentifier DESTINATION_NONE = null;
|
||||
public static final ModelIdentifier DESTINATION_KEYNUMBER
|
||||
= new ModelIdentifier("noteon", "keynumber");
|
||||
public static final ModelIdentifier DESTINATION_VELOCITY
|
||||
= new ModelIdentifier("noteon", "velocity");
|
||||
public static final ModelIdentifier DESTINATION_PITCH
|
||||
= new ModelIdentifier("osc", "pitch"); // cent
|
||||
public static final ModelIdentifier DESTINATION_GAIN
|
||||
= new ModelIdentifier("mixer", "gain"); // cB
|
||||
public static final ModelIdentifier DESTINATION_PAN
|
||||
= new ModelIdentifier("mixer", "pan"); // 0.1 %
|
||||
public static final ModelIdentifier DESTINATION_REVERB
|
||||
= new ModelIdentifier("mixer", "reverb"); // 0.1 %
|
||||
public static final ModelIdentifier DESTINATION_CHORUS
|
||||
= new ModelIdentifier("mixer", "chorus"); // 0.1 %
|
||||
public static final ModelIdentifier DESTINATION_LFO1_DELAY
|
||||
= new ModelIdentifier("lfo", "delay", 0); // timecent
|
||||
public static final ModelIdentifier DESTINATION_LFO1_FREQ
|
||||
= new ModelIdentifier("lfo", "freq", 0); // cent
|
||||
public static final ModelIdentifier DESTINATION_LFO2_DELAY
|
||||
= new ModelIdentifier("lfo", "delay", 1); // timecent
|
||||
public static final ModelIdentifier DESTINATION_LFO2_FREQ
|
||||
= new ModelIdentifier("lfo", "freq", 1); // cent
|
||||
public static final ModelIdentifier DESTINATION_EG1_DELAY
|
||||
= new ModelIdentifier("eg", "delay", 0); // timecent
|
||||
public static final ModelIdentifier DESTINATION_EG1_ATTACK
|
||||
= new ModelIdentifier("eg", "attack", 0); // timecent
|
||||
public static final ModelIdentifier DESTINATION_EG1_HOLD
|
||||
= new ModelIdentifier("eg", "hold", 0); // timecent
|
||||
public static final ModelIdentifier DESTINATION_EG1_DECAY
|
||||
= new ModelIdentifier("eg", "decay", 0); // timecent
|
||||
public static final ModelIdentifier DESTINATION_EG1_SUSTAIN
|
||||
= new ModelIdentifier("eg", "sustain", 0);
|
||||
// 0.1 % (I want this to be value not %)
|
||||
public static final ModelIdentifier DESTINATION_EG1_RELEASE
|
||||
= new ModelIdentifier("eg", "release", 0); // timecent
|
||||
public static final ModelIdentifier DESTINATION_EG1_SHUTDOWN
|
||||
= new ModelIdentifier("eg", "shutdown", 0); // timecent
|
||||
public static final ModelIdentifier DESTINATION_EG2_DELAY
|
||||
= new ModelIdentifier("eg", "delay", 1); // timecent
|
||||
public static final ModelIdentifier DESTINATION_EG2_ATTACK
|
||||
= new ModelIdentifier("eg", "attack", 1); // timecent
|
||||
public static final ModelIdentifier DESTINATION_EG2_HOLD
|
||||
= new ModelIdentifier("eg", "hold", 1); // 0.1 %
|
||||
public static final ModelIdentifier DESTINATION_EG2_DECAY
|
||||
= new ModelIdentifier("eg", "decay", 1); // timecent
|
||||
public static final ModelIdentifier DESTINATION_EG2_SUSTAIN
|
||||
= new ModelIdentifier("eg", "sustain", 1);
|
||||
// 0.1 % ( I want this to be value not %)
|
||||
public static final ModelIdentifier DESTINATION_EG2_RELEASE
|
||||
= new ModelIdentifier("eg", "release", 1); // timecent
|
||||
public static final ModelIdentifier DESTINATION_EG2_SHUTDOWN
|
||||
= new ModelIdentifier("eg", "shutdown", 1); // timecent
|
||||
public static final ModelIdentifier DESTINATION_FILTER_FREQ
|
||||
= new ModelIdentifier("filter", "freq", 0); // cent
|
||||
public static final ModelIdentifier DESTINATION_FILTER_Q
|
||||
= new ModelIdentifier("filter", "q", 0); // cB
|
||||
private ModelIdentifier destination = DESTINATION_NONE;
|
||||
private ModelTransform transform = new ModelStandardTransform();
|
||||
|
||||
public ModelDestination() {
|
||||
}
|
||||
|
||||
public ModelDestination(ModelIdentifier id) {
|
||||
destination = id;
|
||||
}
|
||||
|
||||
public ModelIdentifier getIdentifier() {
|
||||
return destination;
|
||||
}
|
||||
|
||||
public void setIdentifier(ModelIdentifier destination) {
|
||||
this.destination = destination;
|
||||
}
|
||||
|
||||
public ModelTransform getTransform() {
|
||||
return transform;
|
||||
}
|
||||
|
||||
public void setTransform(ModelTransform transform) {
|
||||
this.transform = transform;
|
||||
}
|
||||
}
|
||||
36
jdkSrc/jdk8/com/sun/media/sound/ModelDirectedPlayer.java
Normal file
36
jdkSrc/jdk8/com/sun/media/sound/ModelDirectedPlayer.java
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
/**
|
||||
* ModelDirectedPlayer is the one who is directed by ModelDirector
|
||||
* to play ModelPerformer objects.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public interface ModelDirectedPlayer {
|
||||
|
||||
public void play(int performerIndex, ModelConnectionBlock[] connectionBlocks);
|
||||
}
|
||||
46
jdkSrc/jdk8/com/sun/media/sound/ModelDirector.java
Normal file
46
jdkSrc/jdk8/com/sun/media/sound/ModelDirector.java
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
/**
|
||||
* A director chooses what performers should be played for each note on
|
||||
* and note off events.
|
||||
*
|
||||
* ModelInstrument can implement custom performer who chooses what performers
|
||||
* to play for example by sustain pedal is off or on.
|
||||
*
|
||||
* The default director (ModelStandardDirector) chooses performers
|
||||
* by there keyfrom,keyto,velfrom,velto properties.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public interface ModelDirector {
|
||||
|
||||
public void noteOn(int noteNumber, int velocity);
|
||||
|
||||
public void noteOff(int noteNumber, int velocity);
|
||||
|
||||
public void close();
|
||||
}
|
||||
169
jdkSrc/jdk8/com/sun/media/sound/ModelIdentifier.java
Normal file
169
jdkSrc/jdk8/com/sun/media/sound/ModelIdentifier.java
Normal file
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
/**
|
||||
* This class stores the identity of source and destinations in connection
|
||||
* blocks, see ModelConnectionBlock.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public final class ModelIdentifier {
|
||||
|
||||
/*
|
||||
* Object Variable
|
||||
* ------ --------
|
||||
*
|
||||
* // INPUT parameters
|
||||
* noteon keynumber 7 bit midi value
|
||||
* velocity 7 bit midi vale
|
||||
* on 1 or 0
|
||||
*
|
||||
* midi pitch 14 bit midi value
|
||||
* channel_pressure 7 bit midi value
|
||||
* poly_pressure 7 bit midi value
|
||||
*
|
||||
* midi_cc 0 (midi control #0 7 bit midi value
|
||||
* 1 (midi control #1 7 bit midi value
|
||||
* ...
|
||||
* 127 (midi control #127 7 bit midi value
|
||||
*
|
||||
* midi_rpn 0 (midi rpn control #0) 14 bit midi value
|
||||
* 1 (midi rpn control #1) 14 bit midi value
|
||||
* ....
|
||||
*
|
||||
* // DAHDSR envelope generator
|
||||
* eg (null)
|
||||
* delay timecent
|
||||
* attack timecent
|
||||
* hold timecent
|
||||
* decay timecent
|
||||
* sustain 0.1 %
|
||||
* release timecent
|
||||
*
|
||||
* // Low frequency oscillirator (sine wave)
|
||||
* lfo (null)
|
||||
* delay timcent
|
||||
* freq cent
|
||||
*
|
||||
* // Resonance LowPass Filter 6dB slope
|
||||
* filter (null) (output/input)
|
||||
* freq cent
|
||||
* q cB
|
||||
*
|
||||
* // The oscillator with preloaded wavetable data
|
||||
* osc (null)
|
||||
* pitch cent
|
||||
*
|
||||
* // Output mixer pins
|
||||
* mixer gain cB
|
||||
* pan 0.1 %
|
||||
* reverb 0.1 %
|
||||
* chorus 0.1 %
|
||||
*
|
||||
*/
|
||||
private String object = null;
|
||||
private String variable = null;
|
||||
private int instance = 0;
|
||||
|
||||
public ModelIdentifier(String object) {
|
||||
this.object = object;
|
||||
}
|
||||
|
||||
public ModelIdentifier(String object, int instance) {
|
||||
this.object = object;
|
||||
this.instance = instance;
|
||||
}
|
||||
|
||||
public ModelIdentifier(String object, String variable) {
|
||||
this.object = object;
|
||||
this.variable = variable;
|
||||
|
||||
}
|
||||
|
||||
public ModelIdentifier(String object, String variable, int instance) {
|
||||
this.object = object;
|
||||
this.variable = variable;
|
||||
this.instance = instance;
|
||||
|
||||
}
|
||||
|
||||
public int getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void setInstance(int instance) {
|
||||
this.instance = instance;
|
||||
}
|
||||
|
||||
public String getObject() {
|
||||
return object;
|
||||
}
|
||||
|
||||
public void setObject(String object) {
|
||||
this.object = object;
|
||||
}
|
||||
|
||||
public String getVariable() {
|
||||
return variable;
|
||||
}
|
||||
|
||||
public void setVariable(String variable) {
|
||||
this.variable = variable;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int hashcode = instance;
|
||||
if(object != null) hashcode |= object.hashCode();
|
||||
if(variable != null) hashcode |= variable.hashCode();
|
||||
return hashcode;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof ModelIdentifier))
|
||||
return false;
|
||||
|
||||
ModelIdentifier mobj = (ModelIdentifier)obj;
|
||||
if ((object == null) != (mobj.object == null))
|
||||
return false;
|
||||
if ((variable == null) != (mobj.variable == null))
|
||||
return false;
|
||||
if (mobj.getInstance() != getInstance())
|
||||
return false;
|
||||
if (!(object == null || object.equals(mobj.object)))
|
||||
return false;
|
||||
if (!(variable == null || variable.equals(mobj.variable)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
if (variable == null) {
|
||||
return object + "[" + instance + "]";
|
||||
} else {
|
||||
return object + "[" + instance + "]" + "." + variable;
|
||||
}
|
||||
}
|
||||
}
|
||||
136
jdkSrc/jdk8/com/sun/media/sound/ModelInstrument.java
Normal file
136
jdkSrc/jdk8/com/sun/media/sound/ModelInstrument.java
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
import javax.sound.midi.Instrument;
|
||||
import javax.sound.midi.MidiChannel;
|
||||
import javax.sound.midi.Patch;
|
||||
import javax.sound.midi.Soundbank;
|
||||
import javax.sound.sampled.AudioFormat;
|
||||
|
||||
/**
|
||||
* The model instrument class.
|
||||
*
|
||||
* <p>The main methods to override are:<br>
|
||||
* getPerformer, getDirector, getChannelMixer.
|
||||
*
|
||||
* <p>Performers are used to define what voices which will
|
||||
* playback when using the instrument.<br>
|
||||
*
|
||||
* ChannelMixer is used to add channel-wide processing
|
||||
* on voices output or to define non-voice oriented instruments.<br>
|
||||
*
|
||||
* Director is used to change how the synthesizer
|
||||
* chooses what performers to play on midi events.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public abstract class ModelInstrument extends Instrument {
|
||||
|
||||
protected ModelInstrument(Soundbank soundbank, Patch patch, String name,
|
||||
Class<?> dataClass) {
|
||||
super(soundbank, patch, name, dataClass);
|
||||
}
|
||||
|
||||
public ModelDirector getDirector(ModelPerformer[] performers,
|
||||
MidiChannel channel, ModelDirectedPlayer player) {
|
||||
return new ModelStandardIndexedDirector(performers, player);
|
||||
}
|
||||
|
||||
public ModelPerformer[] getPerformers() {
|
||||
return new ModelPerformer[0];
|
||||
}
|
||||
|
||||
public ModelChannelMixer getChannelMixer(MidiChannel channel,
|
||||
AudioFormat format) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get General MIDI 2 Alias patch for this instrument.
|
||||
public final Patch getPatchAlias() {
|
||||
Patch patch = getPatch();
|
||||
int program = patch.getProgram();
|
||||
int bank = patch.getBank();
|
||||
if (bank != 0)
|
||||
return patch;
|
||||
boolean percussion = false;
|
||||
if (getPatch() instanceof ModelPatch)
|
||||
percussion = ((ModelPatch)getPatch()).isPercussion();
|
||||
if (percussion)
|
||||
return new Patch(0x78 << 7, program);
|
||||
else
|
||||
return new Patch(0x79 << 7, program);
|
||||
}
|
||||
|
||||
// Return name of all the keys.
|
||||
// This information is generated from ModelPerformer.getName()
|
||||
// returned from getPerformers().
|
||||
public final String[] getKeys() {
|
||||
String[] keys = new String[128];
|
||||
for (ModelPerformer performer : getPerformers()) {
|
||||
for (int k = performer.getKeyFrom(); k <= performer.getKeyTo(); k++) {
|
||||
if (k >= 0 && k < 128 && keys[k] == null) {
|
||||
String name = performer.getName();
|
||||
if (name == null)
|
||||
name = "untitled";
|
||||
keys[k] = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
// Return what channels this instrument will probably response
|
||||
// on General MIDI synthesizer.
|
||||
public final boolean[] getChannels() {
|
||||
boolean percussion = false;
|
||||
if (getPatch() instanceof ModelPatch)
|
||||
percussion = ((ModelPatch)getPatch()).isPercussion();
|
||||
|
||||
// Check if instrument is percussion.
|
||||
if (percussion) {
|
||||
boolean[] ch = new boolean[16];
|
||||
for (int i = 0; i < ch.length; i++)
|
||||
ch[i] = false;
|
||||
ch[9] = true;
|
||||
return ch;
|
||||
}
|
||||
|
||||
// Check if instrument uses General MIDI 2 default banks.
|
||||
int bank = getPatch().getBank();
|
||||
if (bank >> 7 == 0x78 || bank >> 7 == 0x79) {
|
||||
boolean[] ch = new boolean[16];
|
||||
for (int i = 0; i < ch.length; i++)
|
||||
ch[i] = true;
|
||||
return ch;
|
||||
}
|
||||
|
||||
boolean[] ch = new boolean[16];
|
||||
for (int i = 0; i < ch.length; i++)
|
||||
ch[i] = true;
|
||||
ch[9] = false;
|
||||
return ch;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.util.Comparator;
|
||||
import javax.sound.midi.Instrument;
|
||||
import javax.sound.midi.Patch;
|
||||
|
||||
/**
|
||||
* Instrument comparator class.
|
||||
* Used to order instrument by program, bank, percussion.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public final class ModelInstrumentComparator implements Comparator<Instrument> {
|
||||
|
||||
public int compare(Instrument arg0, Instrument arg1) {
|
||||
Patch p0 = arg0.getPatch();
|
||||
Patch p1 = arg1.getPatch();
|
||||
int a = p0.getBank() * 128 + p0.getProgram();
|
||||
int b = p1.getBank() * 128 + p1.getProgram();
|
||||
if (p0 instanceof ModelPatch) {
|
||||
a += ((ModelPatch)p0).isPercussion() ? 2097152 : 0;
|
||||
}
|
||||
if (p1 instanceof ModelPatch) {
|
||||
b += ((ModelPatch)p1).isPercussion() ? 2097152 : 0;
|
||||
}
|
||||
return a - b;
|
||||
}
|
||||
}
|
||||
62
jdkSrc/jdk8/com/sun/media/sound/ModelMappedInstrument.java
Normal file
62
jdkSrc/jdk8/com/sun/media/sound/ModelMappedInstrument.java
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
import javax.sound.midi.MidiChannel;
|
||||
import javax.sound.midi.Patch;
|
||||
import javax.sound.sampled.AudioFormat;
|
||||
|
||||
/**
|
||||
* This class is used to map instrument to another patch.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public final class ModelMappedInstrument extends ModelInstrument {
|
||||
|
||||
private final ModelInstrument ins;
|
||||
|
||||
public ModelMappedInstrument(ModelInstrument ins, Patch patch) {
|
||||
super(ins.getSoundbank(), patch, ins.getName(), ins.getDataClass());
|
||||
this.ins = ins;
|
||||
}
|
||||
|
||||
public Object getData() {
|
||||
return ins.getData();
|
||||
}
|
||||
|
||||
public ModelPerformer[] getPerformers() {
|
||||
return ins.getPerformers();
|
||||
}
|
||||
|
||||
public ModelDirector getDirector(ModelPerformer[] performers,
|
||||
MidiChannel channel, ModelDirectedPlayer player) {
|
||||
return ins.getDirector(performers, channel, player);
|
||||
}
|
||||
|
||||
public ModelChannelMixer getChannelMixer(MidiChannel channel,
|
||||
AudioFormat format) {
|
||||
return ins.getChannelMixer(channel, format);
|
||||
}
|
||||
}
|
||||
44
jdkSrc/jdk8/com/sun/media/sound/ModelOscillator.java
Normal file
44
jdkSrc/jdk8/com/sun/media/sound/ModelOscillator.java
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
/**
|
||||
* This interface is used for oscillators.
|
||||
* See example in ModelDefaultOscillator which is a wavetable oscillator.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public interface ModelOscillator {
|
||||
|
||||
public int getChannels();
|
||||
|
||||
/**
|
||||
* Attenuation is in cB.
|
||||
* @return
|
||||
*/
|
||||
public float getAttenuation();
|
||||
|
||||
public ModelOscillatorStream open(float samplerate);
|
||||
}
|
||||
48
jdkSrc/jdk8/com/sun/media/sound/ModelOscillatorStream.java
Normal file
48
jdkSrc/jdk8/com/sun/media/sound/ModelOscillatorStream.java
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.sound.midi.MidiChannel;
|
||||
import javax.sound.midi.VoiceStatus;
|
||||
|
||||
/**
|
||||
* This interface is used for audio streams from ModelOscillator.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public interface ModelOscillatorStream {
|
||||
|
||||
public void setPitch(float pitch); // Pitch is in cents!
|
||||
|
||||
public void noteOn(MidiChannel channel, VoiceStatus voice, int noteNumber,
|
||||
int velocity);
|
||||
|
||||
public void noteOff(int velocity);
|
||||
|
||||
public int read(float[][] buffer, int offset, int len) throws IOException;
|
||||
|
||||
public void close() throws IOException;
|
||||
}
|
||||
52
jdkSrc/jdk8/com/sun/media/sound/ModelPatch.java
Normal file
52
jdkSrc/jdk8/com/sun/media/sound/ModelPatch.java
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
import javax.sound.midi.Patch;
|
||||
|
||||
/**
|
||||
* A extended patch object that has isPercussion function.
|
||||
* Which is necessary to identify percussion instruments
|
||||
* from melodic instruments.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public final class ModelPatch extends Patch {
|
||||
|
||||
private boolean percussion = false;
|
||||
|
||||
public ModelPatch(int bank, int program) {
|
||||
super(bank, program);
|
||||
}
|
||||
|
||||
public ModelPatch(int bank, int program, boolean percussion) {
|
||||
super(bank, program);
|
||||
this.percussion = percussion;
|
||||
}
|
||||
|
||||
public boolean isPercussion() {
|
||||
return percussion;
|
||||
}
|
||||
}
|
||||
143
jdkSrc/jdk8/com/sun/media/sound/ModelPerformer.java
Normal file
143
jdkSrc/jdk8/com/sun/media/sound/ModelPerformer.java
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class is used to define how to synthesize audio in universal maner
|
||||
* for both SF2 and DLS instruments.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public final class ModelPerformer {
|
||||
|
||||
private final List<ModelOscillator> oscillators = new ArrayList<ModelOscillator>();
|
||||
private List<ModelConnectionBlock> connectionBlocks
|
||||
= new ArrayList<ModelConnectionBlock>();
|
||||
private int keyFrom = 0;
|
||||
private int keyTo = 127;
|
||||
private int velFrom = 0;
|
||||
private int velTo = 127;
|
||||
private int exclusiveClass = 0;
|
||||
private boolean releaseTrigger = false;
|
||||
private boolean selfNonExclusive = false;
|
||||
private Object userObject = null;
|
||||
private boolean addDefaultConnections = true;
|
||||
private String name = null;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public List<ModelConnectionBlock> getConnectionBlocks() {
|
||||
return connectionBlocks;
|
||||
}
|
||||
|
||||
public void setConnectionBlocks(List<ModelConnectionBlock> connectionBlocks) {
|
||||
this.connectionBlocks = connectionBlocks;
|
||||
}
|
||||
|
||||
public List<ModelOscillator> getOscillators() {
|
||||
return oscillators;
|
||||
}
|
||||
|
||||
public int getExclusiveClass() {
|
||||
return exclusiveClass;
|
||||
}
|
||||
|
||||
public void setExclusiveClass(int exclusiveClass) {
|
||||
this.exclusiveClass = exclusiveClass;
|
||||
}
|
||||
|
||||
public boolean isSelfNonExclusive() {
|
||||
return selfNonExclusive;
|
||||
}
|
||||
|
||||
public void setSelfNonExclusive(boolean selfNonExclusive) {
|
||||
this.selfNonExclusive = selfNonExclusive;
|
||||
}
|
||||
|
||||
public int getKeyFrom() {
|
||||
return keyFrom;
|
||||
}
|
||||
|
||||
public void setKeyFrom(int keyFrom) {
|
||||
this.keyFrom = keyFrom;
|
||||
}
|
||||
|
||||
public int getKeyTo() {
|
||||
return keyTo;
|
||||
}
|
||||
|
||||
public void setKeyTo(int keyTo) {
|
||||
this.keyTo = keyTo;
|
||||
}
|
||||
|
||||
public int getVelFrom() {
|
||||
return velFrom;
|
||||
}
|
||||
|
||||
public void setVelFrom(int velFrom) {
|
||||
this.velFrom = velFrom;
|
||||
}
|
||||
|
||||
public int getVelTo() {
|
||||
return velTo;
|
||||
}
|
||||
|
||||
public void setVelTo(int velTo) {
|
||||
this.velTo = velTo;
|
||||
}
|
||||
|
||||
public boolean isReleaseTriggered() {
|
||||
return releaseTrigger;
|
||||
}
|
||||
|
||||
public void setReleaseTriggered(boolean value) {
|
||||
this.releaseTrigger = value;
|
||||
}
|
||||
|
||||
public Object getUserObject() {
|
||||
return userObject;
|
||||
}
|
||||
|
||||
public void setUserObject(Object object) {
|
||||
userObject = object;
|
||||
}
|
||||
|
||||
public boolean isDefaultConnectionsEnabled() {
|
||||
return addDefaultConnections;
|
||||
}
|
||||
|
||||
public void setDefaultConnectionsEnabled(boolean addDefaultConnections) {
|
||||
this.addDefaultConnections = addDefaultConnections;
|
||||
}
|
||||
}
|
||||
109
jdkSrc/jdk8/com/sun/media/sound/ModelSource.java
Normal file
109
jdkSrc/jdk8/com/sun/media/sound/ModelSource.java
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
/**
|
||||
* This class is used to identify sources in connection blocks,
|
||||
* see ModelConnectionBlock.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public final class ModelSource {
|
||||
|
||||
public static final ModelIdentifier SOURCE_NONE = null;
|
||||
public static final ModelIdentifier SOURCE_NOTEON_KEYNUMBER =
|
||||
new ModelIdentifier("noteon", "keynumber"); // midi keynumber
|
||||
public static final ModelIdentifier SOURCE_NOTEON_VELOCITY =
|
||||
new ModelIdentifier("noteon", "velocity"); // midi velocity
|
||||
public static final ModelIdentifier SOURCE_EG1 =
|
||||
new ModelIdentifier("eg", null, 0);
|
||||
public static final ModelIdentifier SOURCE_EG2 =
|
||||
new ModelIdentifier("eg", null, 1);
|
||||
public static final ModelIdentifier SOURCE_LFO1 =
|
||||
new ModelIdentifier("lfo", null, 0);
|
||||
public static final ModelIdentifier SOURCE_LFO2 =
|
||||
new ModelIdentifier("lfo", null, 1);
|
||||
public static final ModelIdentifier SOURCE_MIDI_PITCH =
|
||||
new ModelIdentifier("midi", "pitch", 0); // (0..16383)
|
||||
public static final ModelIdentifier SOURCE_MIDI_CHANNEL_PRESSURE =
|
||||
new ModelIdentifier("midi", "channel_pressure", 0); // (0..127)
|
||||
// public static final ModelIdentifier SOURCE_MIDI_MONO_PRESSURE =
|
||||
// new ModelIdentifier("midi","mono_pressure",0); // (0..127)
|
||||
public static final ModelIdentifier SOURCE_MIDI_POLY_PRESSURE =
|
||||
new ModelIdentifier("midi", "poly_pressure", 0); // (0..127)
|
||||
public static final ModelIdentifier SOURCE_MIDI_CC_0 =
|
||||
new ModelIdentifier("midi_cc", "0", 0); // (0..127)
|
||||
public static final ModelIdentifier SOURCE_MIDI_RPN_0 =
|
||||
new ModelIdentifier("midi_rpn", "0", 0); // (0..16383)
|
||||
private ModelIdentifier source = SOURCE_NONE;
|
||||
private ModelTransform transform;
|
||||
|
||||
public ModelSource() {
|
||||
this.transform = new ModelStandardTransform();
|
||||
}
|
||||
|
||||
public ModelSource(ModelIdentifier id) {
|
||||
source = id;
|
||||
this.transform = new ModelStandardTransform();
|
||||
}
|
||||
|
||||
public ModelSource(ModelIdentifier id, boolean direction) {
|
||||
source = id;
|
||||
this.transform = new ModelStandardTransform(direction);
|
||||
}
|
||||
|
||||
public ModelSource(ModelIdentifier id, boolean direction, boolean polarity) {
|
||||
source = id;
|
||||
this.transform = new ModelStandardTransform(direction, polarity);
|
||||
}
|
||||
|
||||
public ModelSource(ModelIdentifier id, boolean direction, boolean polarity,
|
||||
int transform) {
|
||||
source = id;
|
||||
this.transform =
|
||||
new ModelStandardTransform(direction, polarity, transform);
|
||||
}
|
||||
|
||||
public ModelSource(ModelIdentifier id, ModelTransform transform) {
|
||||
source = id;
|
||||
this.transform = transform;
|
||||
}
|
||||
|
||||
public ModelIdentifier getIdentifier() {
|
||||
return source;
|
||||
}
|
||||
|
||||
public void setIdentifier(ModelIdentifier source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public ModelTransform getTransform() {
|
||||
return transform;
|
||||
}
|
||||
|
||||
public void setTransform(ModelTransform transform) {
|
||||
this.transform = transform;
|
||||
}
|
||||
}
|
||||
87
jdkSrc/jdk8/com/sun/media/sound/ModelStandardDirector.java
Normal file
87
jdkSrc/jdk8/com/sun/media/sound/ModelStandardDirector.java
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* A standard director who chooses performers
|
||||
* by there keyfrom,keyto,velfrom,velto properties.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public final class ModelStandardDirector implements ModelDirector {
|
||||
|
||||
private final ModelPerformer[] performers;
|
||||
private final ModelDirectedPlayer player;
|
||||
private boolean noteOnUsed = false;
|
||||
private boolean noteOffUsed = false;
|
||||
|
||||
public ModelStandardDirector(final ModelPerformer[] performers,
|
||||
final ModelDirectedPlayer player) {
|
||||
this.performers = Arrays.copyOf(performers, performers.length);
|
||||
this.player = player;
|
||||
for (final ModelPerformer p : this.performers) {
|
||||
if (p.isReleaseTriggered()) {
|
||||
noteOffUsed = true;
|
||||
} else {
|
||||
noteOnUsed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
}
|
||||
|
||||
public void noteOff(int noteNumber, int velocity) {
|
||||
if (!noteOffUsed)
|
||||
return;
|
||||
for (int i = 0; i < performers.length; i++) {
|
||||
ModelPerformer p = performers[i];
|
||||
if (p.getKeyFrom() <= noteNumber && p.getKeyTo() >= noteNumber) {
|
||||
if (p.getVelFrom() <= velocity && p.getVelTo() >= velocity) {
|
||||
if (p.isReleaseTriggered()) {
|
||||
player.play(i, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void noteOn(int noteNumber, int velocity) {
|
||||
if (!noteOnUsed)
|
||||
return;
|
||||
for (int i = 0; i < performers.length; i++) {
|
||||
ModelPerformer p = performers[i];
|
||||
if (p.getKeyFrom() <= noteNumber && p.getKeyTo() >= noteNumber) {
|
||||
if (p.getVelFrom() <= velocity && p.getVelTo() >= velocity) {
|
||||
if (!p.isReleaseTriggered()) {
|
||||
player.play(i, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* A standard indexed director who chooses performers
|
||||
* by there keyfrom,keyto,velfrom,velto properties.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public final class ModelStandardIndexedDirector implements ModelDirector {
|
||||
|
||||
private final ModelPerformer[] performers;
|
||||
private final ModelDirectedPlayer player;
|
||||
private boolean noteOnUsed = false;
|
||||
private boolean noteOffUsed = false;
|
||||
|
||||
// Variables needed for index
|
||||
private byte[][] trantables;
|
||||
private int[] counters;
|
||||
private int[][] mat;
|
||||
|
||||
public ModelStandardIndexedDirector(final ModelPerformer[] performers,
|
||||
final ModelDirectedPlayer player) {
|
||||
this.performers = Arrays.copyOf(performers, performers.length);
|
||||
this.player = player;
|
||||
for (final ModelPerformer p : this.performers) {
|
||||
if (p.isReleaseTriggered()) {
|
||||
noteOffUsed = true;
|
||||
} else {
|
||||
noteOnUsed = true;
|
||||
}
|
||||
}
|
||||
buildindex();
|
||||
}
|
||||
|
||||
private int[] lookupIndex(int x, int y) {
|
||||
if ((x >= 0) && (x < 128) && (y >= 0) && (y < 128)) {
|
||||
int xt = trantables[0][x];
|
||||
int yt = trantables[1][y];
|
||||
if (xt != -1 && yt != -1) {
|
||||
return mat[xt + yt * counters[0]];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private int restrict(int value) {
|
||||
if(value < 0) return 0;
|
||||
if(value > 127) return 127;
|
||||
return value;
|
||||
}
|
||||
|
||||
private void buildindex() {
|
||||
trantables = new byte[2][129];
|
||||
counters = new int[trantables.length];
|
||||
for (ModelPerformer performer : performers) {
|
||||
int keyFrom = performer.getKeyFrom();
|
||||
int keyTo = performer.getKeyTo();
|
||||
int velFrom = performer.getVelFrom();
|
||||
int velTo = performer.getVelTo();
|
||||
if (keyFrom > keyTo) continue;
|
||||
if (velFrom > velTo) continue;
|
||||
keyFrom = restrict(keyFrom);
|
||||
keyTo = restrict(keyTo);
|
||||
velFrom = restrict(velFrom);
|
||||
velTo = restrict(velTo);
|
||||
trantables[0][keyFrom] = 1;
|
||||
trantables[0][keyTo + 1] = 1;
|
||||
trantables[1][velFrom] = 1;
|
||||
trantables[1][velTo + 1] = 1;
|
||||
}
|
||||
for (int d = 0; d < trantables.length; d++) {
|
||||
byte[] trantable = trantables[d];
|
||||
int transize = trantable.length;
|
||||
for (int i = transize - 1; i >= 0; i--) {
|
||||
if (trantable[i] == 1) {
|
||||
trantable[i] = -1;
|
||||
break;
|
||||
}
|
||||
trantable[i] = -1;
|
||||
}
|
||||
int counter = -1;
|
||||
for (int i = 0; i < transize; i++) {
|
||||
if (trantable[i] != 0) {
|
||||
counter++;
|
||||
if (trantable[i] == -1)
|
||||
break;
|
||||
}
|
||||
trantable[i] = (byte) counter;
|
||||
}
|
||||
counters[d] = counter;
|
||||
}
|
||||
mat = new int[counters[0] * counters[1]][];
|
||||
int ix = 0;
|
||||
for (ModelPerformer performer : performers) {
|
||||
int keyFrom = performer.getKeyFrom();
|
||||
int keyTo = performer.getKeyTo();
|
||||
int velFrom = performer.getVelFrom();
|
||||
int velTo = performer.getVelTo();
|
||||
if (keyFrom > keyTo) continue;
|
||||
if (velFrom > velTo) continue;
|
||||
keyFrom = restrict(keyFrom);
|
||||
keyTo = restrict(keyTo);
|
||||
velFrom = restrict(velFrom);
|
||||
velTo = restrict(velTo);
|
||||
int x_from = trantables[0][keyFrom];
|
||||
int x_to = trantables[0][keyTo + 1];
|
||||
int y_from = trantables[1][velFrom];
|
||||
int y_to = trantables[1][velTo + 1];
|
||||
if (x_to == -1)
|
||||
x_to = counters[0];
|
||||
if (y_to == -1)
|
||||
y_to = counters[1];
|
||||
for (int y = y_from; y < y_to; y++) {
|
||||
int i = x_from + y * counters[0];
|
||||
for (int x = x_from; x < x_to; x++) {
|
||||
int[] mprev = mat[i];
|
||||
if (mprev == null) {
|
||||
mat[i] = new int[] { ix };
|
||||
} else {
|
||||
int[] mnew = new int[mprev.length + 1];
|
||||
mnew[mnew.length - 1] = ix;
|
||||
for (int k = 0; k < mprev.length; k++)
|
||||
mnew[k] = mprev[k];
|
||||
mat[i] = mnew;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
ix++;
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
}
|
||||
|
||||
public void noteOff(int noteNumber, int velocity) {
|
||||
if (!noteOffUsed)
|
||||
return;
|
||||
int[] plist = lookupIndex(noteNumber, velocity);
|
||||
if(plist == null) return;
|
||||
for (int i : plist) {
|
||||
ModelPerformer p = performers[i];
|
||||
if (p.isReleaseTriggered()) {
|
||||
player.play(i, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void noteOn(int noteNumber, int velocity) {
|
||||
if (!noteOnUsed)
|
||||
return;
|
||||
int[] plist = lookupIndex(noteNumber, velocity);
|
||||
if(plist == null) return;
|
||||
for (int i : plist) {
|
||||
ModelPerformer p = performers[i];
|
||||
if (!p.isReleaseTriggered()) {
|
||||
player.play(i, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
139
jdkSrc/jdk8/com/sun/media/sound/ModelStandardTransform.java
Normal file
139
jdkSrc/jdk8/com/sun/media/sound/ModelStandardTransform.java
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
/**
|
||||
* A standard transformer used in connection blocks.
|
||||
* It expects input values to be between 0 and 1.
|
||||
*
|
||||
* The result of the transform is
|
||||
* between 0 and 1 if polarity = unipolar and
|
||||
* between -1 and 1 if polarity = bipolar.
|
||||
*
|
||||
* These constraints only applies to Concave, Convex and Switch transforms.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public final class ModelStandardTransform implements ModelTransform {
|
||||
|
||||
public static final boolean DIRECTION_MIN2MAX = false;
|
||||
public static final boolean DIRECTION_MAX2MIN = true;
|
||||
public static final boolean POLARITY_UNIPOLAR = false;
|
||||
public static final boolean POLARITY_BIPOLAR = true;
|
||||
public static final int TRANSFORM_LINEAR = 0;
|
||||
// concave: output = (20*log10(127^2/value^2)) / 96
|
||||
public static final int TRANSFORM_CONCAVE = 1;
|
||||
// convex: same as concave except that start and end point are reversed.
|
||||
public static final int TRANSFORM_CONVEX = 2;
|
||||
// switch: if value > avg(max,min) then max else min
|
||||
public static final int TRANSFORM_SWITCH = 3;
|
||||
public static final int TRANSFORM_ABSOLUTE = 4;
|
||||
private boolean direction = DIRECTION_MIN2MAX;
|
||||
private boolean polarity = POLARITY_UNIPOLAR;
|
||||
private int transform = TRANSFORM_LINEAR;
|
||||
|
||||
public ModelStandardTransform() {
|
||||
}
|
||||
|
||||
public ModelStandardTransform(boolean direction) {
|
||||
this.direction = direction;
|
||||
}
|
||||
|
||||
public ModelStandardTransform(boolean direction, boolean polarity) {
|
||||
this.direction = direction;
|
||||
this.polarity = polarity;
|
||||
}
|
||||
|
||||
public ModelStandardTransform(boolean direction, boolean polarity,
|
||||
int transform) {
|
||||
this.direction = direction;
|
||||
this.polarity = polarity;
|
||||
this.transform = transform;
|
||||
}
|
||||
|
||||
public double transform(double value) {
|
||||
double s;
|
||||
double a;
|
||||
if (direction == DIRECTION_MAX2MIN)
|
||||
value = 1.0 - value;
|
||||
if (polarity == POLARITY_BIPOLAR)
|
||||
value = value * 2.0 - 1.0;
|
||||
switch (transform) {
|
||||
case TRANSFORM_CONCAVE:
|
||||
s = Math.signum(value);
|
||||
a = Math.abs(value);
|
||||
a = -((5.0 / 12.0) / Math.log(10)) * Math.log(1.0 - a);
|
||||
if (a < 0)
|
||||
a = 0;
|
||||
else if (a > 1)
|
||||
a = 1;
|
||||
return s * a;
|
||||
case TRANSFORM_CONVEX:
|
||||
s = Math.signum(value);
|
||||
a = Math.abs(value);
|
||||
a = 1.0 + ((5.0 / 12.0) / Math.log(10)) * Math.log(a);
|
||||
if (a < 0)
|
||||
a = 0;
|
||||
else if (a > 1)
|
||||
a = 1;
|
||||
return s * a;
|
||||
case TRANSFORM_SWITCH:
|
||||
if (polarity == POLARITY_BIPOLAR)
|
||||
return (value > 0) ? 1 : -1;
|
||||
else
|
||||
return (value > 0.5) ? 1 : 0;
|
||||
case TRANSFORM_ABSOLUTE:
|
||||
return Math.abs(value);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public boolean getDirection() {
|
||||
return direction;
|
||||
}
|
||||
|
||||
public void setDirection(boolean direction) {
|
||||
this.direction = direction;
|
||||
}
|
||||
|
||||
public boolean getPolarity() {
|
||||
return polarity;
|
||||
}
|
||||
|
||||
public void setPolarity(boolean polarity) {
|
||||
this.polarity = polarity;
|
||||
}
|
||||
|
||||
public int getTransform() {
|
||||
return transform;
|
||||
}
|
||||
|
||||
public void setTransform(int transform) {
|
||||
this.transform = transform;
|
||||
}
|
||||
}
|
||||
35
jdkSrc/jdk8/com/sun/media/sound/ModelTransform.java
Normal file
35
jdkSrc/jdk8/com/sun/media/sound/ModelTransform.java
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
/**
|
||||
* Model transform interface.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public interface ModelTransform {
|
||||
|
||||
abstract public double transform(double value);
|
||||
}
|
||||
49
jdkSrc/jdk8/com/sun/media/sound/ModelWavetable.java
Normal file
49
jdkSrc/jdk8/com/sun/media/sound/ModelWavetable.java
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
/**
|
||||
* This is a wavetable oscillator interface.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public interface ModelWavetable extends ModelOscillator {
|
||||
|
||||
public static final int LOOP_TYPE_OFF = 0;
|
||||
public static final int LOOP_TYPE_FORWARD = 1;
|
||||
public static final int LOOP_TYPE_RELEASE = 2;
|
||||
public static final int LOOP_TYPE_PINGPONG = 4;
|
||||
public static final int LOOP_TYPE_REVERSE = 8;
|
||||
|
||||
public AudioFloatInputStream openStream();
|
||||
|
||||
public float getLoopLength();
|
||||
|
||||
public float getLoopStart();
|
||||
|
||||
public int getLoopType();
|
||||
|
||||
public float getPitchcorrection();
|
||||
}
|
||||
589
jdkSrc/jdk8/com/sun/media/sound/PCMtoPCMCodec.java
Normal file
589
jdkSrc/jdk8/com/sun/media/sound/PCMtoPCMCodec.java
Normal file
@@ -0,0 +1,589 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Vector;
|
||||
|
||||
import javax.sound.sampled.AudioFormat;
|
||||
import javax.sound.sampled.AudioInputStream;
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
|
||||
|
||||
/**
|
||||
* Converts among signed/unsigned and little/big endianness of sampled.
|
||||
*
|
||||
* @author Jan Borgersen
|
||||
*/
|
||||
public final class PCMtoPCMCodec extends SunCodec {
|
||||
|
||||
|
||||
private static final AudioFormat.Encoding[] inputEncodings = {
|
||||
AudioFormat.Encoding.PCM_SIGNED,
|
||||
AudioFormat.Encoding.PCM_UNSIGNED,
|
||||
};
|
||||
|
||||
private static final AudioFormat.Encoding[] outputEncodings = {
|
||||
AudioFormat.Encoding.PCM_SIGNED,
|
||||
AudioFormat.Encoding.PCM_UNSIGNED,
|
||||
};
|
||||
|
||||
|
||||
|
||||
private static final int tempBufferSize = 64;
|
||||
private byte tempBuffer [] = null;
|
||||
|
||||
/**
|
||||
* Constructs a new PCMtoPCM codec object.
|
||||
*/
|
||||
public PCMtoPCMCodec() {
|
||||
|
||||
super( inputEncodings, outputEncodings);
|
||||
}
|
||||
|
||||
// NEW CODE
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public AudioFormat.Encoding[] getTargetEncodings(AudioFormat sourceFormat){
|
||||
|
||||
if( sourceFormat.getEncoding().equals( AudioFormat.Encoding.PCM_SIGNED ) ||
|
||||
sourceFormat.getEncoding().equals( AudioFormat.Encoding.PCM_UNSIGNED ) ) {
|
||||
|
||||
AudioFormat.Encoding encs[] = new AudioFormat.Encoding[2];
|
||||
encs[0] = AudioFormat.Encoding.PCM_SIGNED;
|
||||
encs[1] = AudioFormat.Encoding.PCM_UNSIGNED;
|
||||
return encs;
|
||||
} else {
|
||||
return new AudioFormat.Encoding[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public AudioFormat[] getTargetFormats(AudioFormat.Encoding targetEncoding, AudioFormat sourceFormat){
|
||||
|
||||
// filter out targetEncoding from the old getOutputFormats( sourceFormat ) method
|
||||
|
||||
AudioFormat[] formats = getOutputFormats( sourceFormat );
|
||||
Vector newFormats = new Vector();
|
||||
for(int i=0; i<formats.length; i++ ) {
|
||||
if( formats[i].getEncoding().equals( targetEncoding ) ) {
|
||||
newFormats.addElement( formats[i] );
|
||||
}
|
||||
}
|
||||
|
||||
AudioFormat[] formatArray = new AudioFormat[newFormats.size()];
|
||||
|
||||
for (int i = 0; i < formatArray.length; i++) {
|
||||
formatArray[i] = (AudioFormat)(newFormats.elementAt(i));
|
||||
}
|
||||
|
||||
return formatArray;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public AudioInputStream getAudioInputStream(AudioFormat.Encoding targetEncoding, AudioInputStream sourceStream) {
|
||||
|
||||
if( isConversionSupported(targetEncoding, sourceStream.getFormat()) ) {
|
||||
|
||||
AudioFormat sourceFormat = sourceStream.getFormat();
|
||||
AudioFormat targetFormat = new AudioFormat( targetEncoding,
|
||||
sourceFormat.getSampleRate(),
|
||||
sourceFormat.getSampleSizeInBits(),
|
||||
sourceFormat.getChannels(),
|
||||
sourceFormat.getFrameSize(),
|
||||
sourceFormat.getFrameRate(),
|
||||
sourceFormat.isBigEndian() );
|
||||
|
||||
return getAudioInputStream( targetFormat, sourceStream );
|
||||
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported conversion: " + sourceStream.getFormat().toString() + " to " + targetEncoding.toString() );
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* use old code
|
||||
*/
|
||||
public AudioInputStream getAudioInputStream(AudioFormat targetFormat, AudioInputStream sourceStream){
|
||||
|
||||
return getConvertedStream( targetFormat, sourceStream );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// OLD CODE
|
||||
|
||||
/**
|
||||
* Opens the codec with the specified parameters.
|
||||
* @param stream stream from which data to be processed should be read
|
||||
* @param outputFormat desired data format of the stream after processing
|
||||
* @return stream from which processed data may be read
|
||||
* @throws IllegalArgumentException if the format combination supplied is
|
||||
* not supported.
|
||||
*/
|
||||
/* public AudioInputStream getConvertedStream(AudioFormat outputFormat, AudioInputStream stream) {*/
|
||||
private AudioInputStream getConvertedStream(AudioFormat outputFormat, AudioInputStream stream) {
|
||||
|
||||
AudioInputStream cs = null;
|
||||
|
||||
AudioFormat inputFormat = stream.getFormat();
|
||||
|
||||
if( inputFormat.matches(outputFormat) ) {
|
||||
|
||||
cs = stream;
|
||||
} else {
|
||||
|
||||
cs = (AudioInputStream) (new PCMtoPCMCodecStream(stream, outputFormat));
|
||||
tempBuffer = new byte[tempBufferSize];
|
||||
}
|
||||
return cs;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Obtains the set of output formats supported by the codec
|
||||
* given a particular input format.
|
||||
* If no output formats are supported for this input format,
|
||||
* returns an array of length 0.
|
||||
* @return array of supported output formats.
|
||||
*/
|
||||
/* public AudioFormat[] getOutputFormats(AudioFormat inputFormat) { */
|
||||
private AudioFormat[] getOutputFormats(AudioFormat inputFormat) {
|
||||
|
||||
Vector formats = new Vector();
|
||||
AudioFormat format;
|
||||
|
||||
int sampleSize = inputFormat.getSampleSizeInBits();
|
||||
boolean isBigEndian = inputFormat.isBigEndian();
|
||||
|
||||
|
||||
if ( sampleSize==8 ) {
|
||||
if ( AudioFormat.Encoding.PCM_SIGNED.equals(inputFormat.getEncoding()) ) {
|
||||
|
||||
format = new AudioFormat(AudioFormat.Encoding.PCM_UNSIGNED,
|
||||
inputFormat.getSampleRate(),
|
||||
inputFormat.getSampleSizeInBits(),
|
||||
inputFormat.getChannels(),
|
||||
inputFormat.getFrameSize(),
|
||||
inputFormat.getFrameRate(),
|
||||
false );
|
||||
formats.addElement(format);
|
||||
}
|
||||
|
||||
if ( AudioFormat.Encoding.PCM_UNSIGNED.equals(inputFormat.getEncoding()) ) {
|
||||
|
||||
format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
|
||||
inputFormat.getSampleRate(),
|
||||
inputFormat.getSampleSizeInBits(),
|
||||
inputFormat.getChannels(),
|
||||
inputFormat.getFrameSize(),
|
||||
inputFormat.getFrameRate(),
|
||||
false );
|
||||
formats.addElement(format);
|
||||
}
|
||||
|
||||
} else if ( sampleSize==16 ) {
|
||||
|
||||
if ( AudioFormat.Encoding.PCM_SIGNED.equals(inputFormat.getEncoding()) && isBigEndian ) {
|
||||
|
||||
format = new AudioFormat(AudioFormat.Encoding.PCM_UNSIGNED,
|
||||
inputFormat.getSampleRate(),
|
||||
inputFormat.getSampleSizeInBits(),
|
||||
inputFormat.getChannels(),
|
||||
inputFormat.getFrameSize(),
|
||||
inputFormat.getFrameRate(),
|
||||
true );
|
||||
formats.addElement(format);
|
||||
format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
|
||||
inputFormat.getSampleRate(),
|
||||
inputFormat.getSampleSizeInBits(),
|
||||
inputFormat.getChannels(),
|
||||
inputFormat.getFrameSize(),
|
||||
inputFormat.getFrameRate(),
|
||||
false );
|
||||
formats.addElement(format);
|
||||
format = new AudioFormat(AudioFormat.Encoding.PCM_UNSIGNED,
|
||||
inputFormat.getSampleRate(),
|
||||
inputFormat.getSampleSizeInBits(),
|
||||
inputFormat.getChannels(),
|
||||
inputFormat.getFrameSize(),
|
||||
inputFormat.getFrameRate(),
|
||||
false );
|
||||
formats.addElement(format);
|
||||
}
|
||||
|
||||
if ( AudioFormat.Encoding.PCM_UNSIGNED.equals(inputFormat.getEncoding()) && isBigEndian ) {
|
||||
|
||||
format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
|
||||
inputFormat.getSampleRate(),
|
||||
inputFormat.getSampleSizeInBits(),
|
||||
inputFormat.getChannels(),
|
||||
inputFormat.getFrameSize(),
|
||||
inputFormat.getFrameRate(),
|
||||
true );
|
||||
formats.addElement(format);
|
||||
format = new AudioFormat(AudioFormat.Encoding.PCM_UNSIGNED,
|
||||
inputFormat.getSampleRate(),
|
||||
inputFormat.getSampleSizeInBits(),
|
||||
inputFormat.getChannels(),
|
||||
inputFormat.getFrameSize(),
|
||||
inputFormat.getFrameRate(),
|
||||
false );
|
||||
formats.addElement(format);
|
||||
format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
|
||||
inputFormat.getSampleRate(),
|
||||
inputFormat.getSampleSizeInBits(),
|
||||
inputFormat.getChannels(),
|
||||
inputFormat.getFrameSize(),
|
||||
inputFormat.getFrameRate(),
|
||||
false );
|
||||
formats.addElement(format);
|
||||
}
|
||||
|
||||
if ( AudioFormat.Encoding.PCM_SIGNED.equals(inputFormat.getEncoding()) && !isBigEndian ) {
|
||||
|
||||
format = new AudioFormat(AudioFormat.Encoding.PCM_UNSIGNED,
|
||||
inputFormat.getSampleRate(),
|
||||
inputFormat.getSampleSizeInBits(),
|
||||
inputFormat.getChannels(),
|
||||
inputFormat.getFrameSize(),
|
||||
inputFormat.getFrameRate(),
|
||||
false );
|
||||
formats.addElement(format);
|
||||
format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
|
||||
inputFormat.getSampleRate(),
|
||||
inputFormat.getSampleSizeInBits(),
|
||||
inputFormat.getChannels(),
|
||||
inputFormat.getFrameSize(),
|
||||
inputFormat.getFrameRate(),
|
||||
true );
|
||||
formats.addElement(format);
|
||||
format = new AudioFormat(AudioFormat.Encoding.PCM_UNSIGNED,
|
||||
inputFormat.getSampleRate(),
|
||||
inputFormat.getSampleSizeInBits(),
|
||||
inputFormat.getChannels(),
|
||||
inputFormat.getFrameSize(),
|
||||
inputFormat.getFrameRate(),
|
||||
true );
|
||||
formats.addElement(format);
|
||||
}
|
||||
|
||||
if ( AudioFormat.Encoding.PCM_UNSIGNED.equals(inputFormat.getEncoding()) && !isBigEndian ) {
|
||||
|
||||
format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
|
||||
inputFormat.getSampleRate(),
|
||||
inputFormat.getSampleSizeInBits(),
|
||||
inputFormat.getChannels(),
|
||||
inputFormat.getFrameSize(),
|
||||
inputFormat.getFrameRate(),
|
||||
false );
|
||||
formats.addElement(format);
|
||||
format = new AudioFormat(AudioFormat.Encoding.PCM_UNSIGNED,
|
||||
inputFormat.getSampleRate(),
|
||||
inputFormat.getSampleSizeInBits(),
|
||||
inputFormat.getChannels(),
|
||||
inputFormat.getFrameSize(),
|
||||
inputFormat.getFrameRate(),
|
||||
true );
|
||||
formats.addElement(format);
|
||||
format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
|
||||
inputFormat.getSampleRate(),
|
||||
inputFormat.getSampleSizeInBits(),
|
||||
inputFormat.getChannels(),
|
||||
inputFormat.getFrameSize(),
|
||||
inputFormat.getFrameRate(),
|
||||
true );
|
||||
formats.addElement(format);
|
||||
}
|
||||
}
|
||||
AudioFormat[] formatArray;
|
||||
|
||||
synchronized(formats) {
|
||||
|
||||
formatArray = new AudioFormat[formats.size()];
|
||||
|
||||
for (int i = 0; i < formatArray.length; i++) {
|
||||
|
||||
formatArray[i] = (AudioFormat)(formats.elementAt(i));
|
||||
}
|
||||
}
|
||||
|
||||
return formatArray;
|
||||
}
|
||||
|
||||
|
||||
class PCMtoPCMCodecStream extends AudioInputStream {
|
||||
|
||||
private final int PCM_SWITCH_SIGNED_8BIT = 1;
|
||||
private final int PCM_SWITCH_ENDIAN = 2;
|
||||
private final int PCM_SWITCH_SIGNED_LE = 3;
|
||||
private final int PCM_SWITCH_SIGNED_BE = 4;
|
||||
private final int PCM_UNSIGNED_LE2SIGNED_BE = 5;
|
||||
private final int PCM_SIGNED_LE2UNSIGNED_BE = 6;
|
||||
private final int PCM_UNSIGNED_BE2SIGNED_LE = 7;
|
||||
private final int PCM_SIGNED_BE2UNSIGNED_LE = 8;
|
||||
|
||||
private final int sampleSizeInBytes;
|
||||
private int conversionType = 0;
|
||||
|
||||
|
||||
PCMtoPCMCodecStream(AudioInputStream stream, AudioFormat outputFormat) {
|
||||
|
||||
super(stream, outputFormat, -1);
|
||||
|
||||
int sampleSizeInBits = 0;
|
||||
AudioFormat.Encoding inputEncoding = null;
|
||||
AudioFormat.Encoding outputEncoding = null;
|
||||
boolean inputIsBigEndian;
|
||||
boolean outputIsBigEndian;
|
||||
|
||||
AudioFormat inputFormat = stream.getFormat();
|
||||
|
||||
// throw an IllegalArgumentException if not ok
|
||||
if ( ! (isConversionSupported(inputFormat, outputFormat)) ) {
|
||||
|
||||
throw new IllegalArgumentException("Unsupported conversion: " + inputFormat.toString() + " to " + outputFormat.toString());
|
||||
}
|
||||
|
||||
inputEncoding = inputFormat.getEncoding();
|
||||
outputEncoding = outputFormat.getEncoding();
|
||||
inputIsBigEndian = inputFormat.isBigEndian();
|
||||
outputIsBigEndian = outputFormat.isBigEndian();
|
||||
sampleSizeInBits = inputFormat.getSampleSizeInBits();
|
||||
sampleSizeInBytes = sampleSizeInBits/8;
|
||||
|
||||
// determine conversion to perform
|
||||
|
||||
if( sampleSizeInBits==8 ) {
|
||||
if( AudioFormat.Encoding.PCM_UNSIGNED.equals(inputEncoding) &&
|
||||
AudioFormat.Encoding.PCM_SIGNED.equals(outputEncoding) ) {
|
||||
conversionType = PCM_SWITCH_SIGNED_8BIT;
|
||||
if(Printer.debug) Printer.debug("PCMtoPCMCodecStream: conversionType = PCM_SWITCH_SIGNED_8BIT");
|
||||
|
||||
} else if( AudioFormat.Encoding.PCM_SIGNED.equals(inputEncoding) &&
|
||||
AudioFormat.Encoding.PCM_UNSIGNED.equals(outputEncoding) ) {
|
||||
conversionType = PCM_SWITCH_SIGNED_8BIT;
|
||||
if(Printer.debug) Printer.debug("PCMtoPCMCodecStream: conversionType = PCM_SWITCH_SIGNED_8BIT");
|
||||
}
|
||||
} else {
|
||||
|
||||
if( inputEncoding.equals(outputEncoding) && (inputIsBigEndian != outputIsBigEndian) ) {
|
||||
|
||||
conversionType = PCM_SWITCH_ENDIAN;
|
||||
if(Printer.debug) Printer.debug("PCMtoPCMCodecStream: conversionType = PCM_SWITCH_ENDIAN");
|
||||
|
||||
|
||||
} else if (AudioFormat.Encoding.PCM_UNSIGNED.equals(inputEncoding) && !inputIsBigEndian &&
|
||||
AudioFormat.Encoding.PCM_SIGNED.equals(outputEncoding) && outputIsBigEndian) {
|
||||
|
||||
conversionType = PCM_UNSIGNED_LE2SIGNED_BE;
|
||||
if(Printer.debug) Printer.debug("PCMtoPCMCodecStream: conversionType = PCM_UNSIGNED_LE2SIGNED_BE");
|
||||
|
||||
} else if (AudioFormat.Encoding.PCM_SIGNED.equals(inputEncoding) && !inputIsBigEndian &&
|
||||
AudioFormat.Encoding.PCM_UNSIGNED.equals(outputEncoding) && outputIsBigEndian) {
|
||||
|
||||
conversionType = PCM_SIGNED_LE2UNSIGNED_BE;
|
||||
if(Printer.debug) Printer.debug("PCMtoPCMCodecStream: conversionType = PCM_SIGNED_LE2UNSIGNED_BE");
|
||||
|
||||
} else if (AudioFormat.Encoding.PCM_UNSIGNED.equals(inputEncoding) && inputIsBigEndian &&
|
||||
AudioFormat.Encoding.PCM_SIGNED.equals(outputEncoding) && !outputIsBigEndian) {
|
||||
|
||||
conversionType = PCM_UNSIGNED_BE2SIGNED_LE;
|
||||
if(Printer.debug) Printer.debug("PCMtoPCMCodecStream: conversionType = PCM_UNSIGNED_BE2SIGNED_LE");
|
||||
|
||||
} else if (AudioFormat.Encoding.PCM_SIGNED.equals(inputEncoding) && inputIsBigEndian &&
|
||||
AudioFormat.Encoding.PCM_UNSIGNED.equals(outputEncoding) && !outputIsBigEndian) {
|
||||
|
||||
conversionType = PCM_SIGNED_BE2UNSIGNED_LE;
|
||||
if(Printer.debug) Printer.debug("PCMtoPCMCodecStream: conversionType = PCM_SIGNED_BE2UNSIGNED_LE");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// set the audio stream length in frames if we know it
|
||||
|
||||
frameSize = inputFormat.getFrameSize();
|
||||
if( frameSize == AudioSystem.NOT_SPECIFIED ) {
|
||||
frameSize=1;
|
||||
}
|
||||
if( stream instanceof AudioInputStream ) {
|
||||
frameLength = stream.getFrameLength();
|
||||
} else {
|
||||
frameLength = AudioSystem.NOT_SPECIFIED;
|
||||
}
|
||||
|
||||
// set framePos to zero
|
||||
framePos = 0;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Note that this only works for sign conversions.
|
||||
* Other conversions require a read of at least 2 bytes.
|
||||
*/
|
||||
|
||||
public int read() throws IOException {
|
||||
|
||||
// $$jb: do we want to implement this function?
|
||||
|
||||
int temp;
|
||||
byte tempbyte;
|
||||
|
||||
if( frameSize==1 ) {
|
||||
if( conversionType == PCM_SWITCH_SIGNED_8BIT ) {
|
||||
temp = super.read();
|
||||
|
||||
if( temp < 0 ) return temp; // EOF or error
|
||||
|
||||
tempbyte = (byte) (temp & 0xf);
|
||||
tempbyte = (tempbyte >= 0) ? (byte)(0x80 | tempbyte) : (byte)(0x7F & tempbyte);
|
||||
temp = (int) tempbyte & 0xf;
|
||||
|
||||
return temp;
|
||||
|
||||
} else {
|
||||
// $$jb: what to return here?
|
||||
throw new IOException("cannot read a single byte if frame size > 1");
|
||||
}
|
||||
} else {
|
||||
throw new IOException("cannot read a single byte if frame size > 1");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public int read(byte[] b) throws IOException {
|
||||
|
||||
return read(b, 0, b.length);
|
||||
}
|
||||
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
|
||||
|
||||
int i;
|
||||
|
||||
// don't read fractional frames
|
||||
if ( len%frameSize != 0 ) {
|
||||
len -= (len%frameSize);
|
||||
}
|
||||
// don't read past our own set length
|
||||
if( (frameLength!=AudioSystem.NOT_SPECIFIED) && ( (len/frameSize) >(frameLength-framePos)) ) {
|
||||
len = (int)(frameLength-framePos) * frameSize;
|
||||
}
|
||||
|
||||
int readCount = super.read(b, off, len);
|
||||
byte tempByte;
|
||||
|
||||
if(readCount<0) { // EOF or error
|
||||
return readCount;
|
||||
}
|
||||
|
||||
// now do the conversions
|
||||
|
||||
switch( conversionType ) {
|
||||
|
||||
case PCM_SWITCH_SIGNED_8BIT:
|
||||
switchSigned8bit(b,off,len,readCount);
|
||||
break;
|
||||
|
||||
case PCM_SWITCH_ENDIAN:
|
||||
switchEndian(b,off,len,readCount);
|
||||
break;
|
||||
|
||||
case PCM_SWITCH_SIGNED_LE:
|
||||
switchSignedLE(b,off,len,readCount);
|
||||
break;
|
||||
|
||||
case PCM_SWITCH_SIGNED_BE:
|
||||
switchSignedBE(b,off,len,readCount);
|
||||
break;
|
||||
|
||||
case PCM_UNSIGNED_LE2SIGNED_BE:
|
||||
case PCM_SIGNED_LE2UNSIGNED_BE:
|
||||
switchSignedLE(b,off,len,readCount);
|
||||
switchEndian(b,off,len,readCount);
|
||||
break;
|
||||
|
||||
case PCM_UNSIGNED_BE2SIGNED_LE:
|
||||
case PCM_SIGNED_BE2UNSIGNED_LE:
|
||||
switchSignedBE(b,off,len,readCount);
|
||||
switchEndian(b,off,len,readCount);
|
||||
break;
|
||||
|
||||
default:
|
||||
// do nothing
|
||||
}
|
||||
|
||||
// we've done the conversion, just return the readCount
|
||||
return readCount;
|
||||
|
||||
}
|
||||
|
||||
private void switchSigned8bit(byte[] b, int off, int len, int readCount) {
|
||||
|
||||
for(int i=off; i < (off+readCount); i++) {
|
||||
b[i] = (b[i] >= 0) ? (byte)(0x80 | b[i]) : (byte)(0x7F & b[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private void switchSignedBE(byte[] b, int off, int len, int readCount) {
|
||||
|
||||
for(int i=off; i < (off+readCount); i+= sampleSizeInBytes ) {
|
||||
b[i] = (b[i] >= 0) ? (byte)(0x80 | b[i]) : (byte)(0x7F & b[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private void switchSignedLE(byte[] b, int off, int len, int readCount) {
|
||||
|
||||
for(int i=(off+sampleSizeInBytes-1); i < (off+readCount); i+= sampleSizeInBytes ) {
|
||||
b[i] = (b[i] >= 0) ? (byte)(0x80 | b[i]) : (byte)(0x7F & b[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private void switchEndian(byte[] b, int off, int len, int readCount) {
|
||||
|
||||
if(sampleSizeInBytes == 2) {
|
||||
for(int i=off; i < (off+readCount); i += sampleSizeInBytes ) {
|
||||
byte temp;
|
||||
temp = b[i];
|
||||
b[i] = b[i+1];
|
||||
b[i+1] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // end class PCMtoPCMCodecStream
|
||||
|
||||
} // end class PCMtoPCMCodec
|
||||
201
jdkSrc/jdk8/com/sun/media/sound/Platform.java
Normal file
201
jdkSrc/jdk8/com/sun/media/sound/Platform.java
Normal file
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Audio configuration class for exposing attributes specific to the platform or system.
|
||||
*
|
||||
* @author Kara Kytle
|
||||
* @author Florian Bomers
|
||||
*/
|
||||
final class Platform {
|
||||
|
||||
|
||||
// STATIC FINAL CHARACTERISTICS
|
||||
|
||||
// native library we need to load
|
||||
private static final String libNameMain = "jsound";
|
||||
private static final String libNameALSA = "jsoundalsa";
|
||||
private static final String libNameDSound = "jsoundds";
|
||||
|
||||
// extra libs handling: bit flags for each different library
|
||||
public static final int LIB_MAIN = 1;
|
||||
public static final int LIB_ALSA = 2;
|
||||
public static final int LIB_DSOUND = 4;
|
||||
|
||||
// bit field of the constants above. Willbe set in loadLibraries
|
||||
private static int loadedLibs = 0;
|
||||
|
||||
// features: the main native library jsound reports which feature is
|
||||
// contained in which lib
|
||||
public static final int FEATURE_MIDIIO = 1;
|
||||
public static final int FEATURE_PORTS = 2;
|
||||
public static final int FEATURE_DIRECT_AUDIO = 3;
|
||||
|
||||
// SYSTEM CHARACTERISTICS
|
||||
// vary according to hardware architecture
|
||||
|
||||
// signed8 (use signed 8-bit values) is true for everything we support except for
|
||||
// the solaris sbpro card.
|
||||
// we'll leave it here as a variable; in the future we may need this in java.
|
||||
// wait, is that true? i'm not sure. i think solaris takes unsigned data?
|
||||
// $$kk: 03.11.99: i think solaris takes unsigned 8-bit or signed 16-bit data....
|
||||
private static boolean signed8;
|
||||
|
||||
// intel is little-endian. sparc is big-endian.
|
||||
private static boolean bigEndian;
|
||||
|
||||
static {
|
||||
if(Printer.trace)Printer.trace(">> Platform.java: static");
|
||||
|
||||
loadLibraries();
|
||||
readProperties();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Private constructor.
|
||||
*/
|
||||
private Platform() {
|
||||
}
|
||||
|
||||
|
||||
// METHODS FOR INTERNAL IMPLEMENTATION USE
|
||||
|
||||
|
||||
/**
|
||||
* Dummy method for forcing initialization.
|
||||
*/
|
||||
static void initialize() {
|
||||
|
||||
if(Printer.trace)Printer.trace("Platform: initialize()");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine whether the system is big-endian.
|
||||
*/
|
||||
static boolean isBigEndian() {
|
||||
|
||||
return bigEndian;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine whether the system takes signed 8-bit data.
|
||||
*/
|
||||
static boolean isSigned8() {
|
||||
|
||||
return signed8;
|
||||
}
|
||||
|
||||
// PRIVATE METHODS
|
||||
|
||||
/**
|
||||
* Load the native library or libraries.
|
||||
*/
|
||||
private static void loadLibraries() {
|
||||
if(Printer.trace)Printer.trace(">>Platform.loadLibraries");
|
||||
|
||||
// load the main library
|
||||
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
|
||||
System.loadLibrary(libNameMain);
|
||||
return null;
|
||||
});
|
||||
// just for the heck of it...
|
||||
loadedLibs |= LIB_MAIN;
|
||||
|
||||
// now try to load extra libs. They are defined at compile time in the Makefile
|
||||
// with the define EXTRA_SOUND_JNI_LIBS
|
||||
String extraLibs = nGetExtraLibraries();
|
||||
// the string is the libraries, separated by white space
|
||||
StringTokenizer st = new StringTokenizer(extraLibs);
|
||||
while (st.hasMoreTokens()) {
|
||||
final String lib = st.nextToken();
|
||||
try {
|
||||
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
|
||||
System.loadLibrary(lib);
|
||||
return null;
|
||||
});
|
||||
|
||||
if (lib.equals(libNameALSA)) {
|
||||
loadedLibs |= LIB_ALSA;
|
||||
if (Printer.debug) Printer.debug("Loaded ALSA lib successfully.");
|
||||
} else if (lib.equals(libNameDSound)) {
|
||||
loadedLibs |= LIB_DSOUND;
|
||||
if (Printer.debug) Printer.debug("Loaded DirectSound lib successfully.");
|
||||
} else {
|
||||
if (Printer.err) Printer.err("Loaded unknown lib '"+lib+"' successfully.");
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
if (Printer.err) Printer.err("Couldn't load library "+lib+": "+t.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static boolean isMidiIOEnabled() {
|
||||
return isFeatureLibLoaded(FEATURE_MIDIIO);
|
||||
}
|
||||
|
||||
static boolean isPortsEnabled() {
|
||||
return isFeatureLibLoaded(FEATURE_PORTS);
|
||||
}
|
||||
|
||||
static boolean isDirectAudioEnabled() {
|
||||
return isFeatureLibLoaded(FEATURE_DIRECT_AUDIO);
|
||||
}
|
||||
|
||||
private static boolean isFeatureLibLoaded(int feature) {
|
||||
if (Printer.debug) Printer.debug("Platform: Checking for feature "+feature+"...");
|
||||
int requiredLib = nGetLibraryForFeature(feature);
|
||||
boolean isLoaded = (requiredLib != 0) && ((loadedLibs & requiredLib) == requiredLib);
|
||||
if (Printer.debug) Printer.debug(" ...needs library "+requiredLib+". Result is loaded="+isLoaded);
|
||||
return isLoaded;
|
||||
}
|
||||
|
||||
// the following native methods are implemented in Platform.c
|
||||
private native static boolean nIsBigEndian();
|
||||
private native static boolean nIsSigned8();
|
||||
private native static String nGetExtraLibraries();
|
||||
private native static int nGetLibraryForFeature(int feature);
|
||||
|
||||
|
||||
/**
|
||||
* Read the required system properties.
|
||||
*/
|
||||
private static void readProperties() {
|
||||
// $$fb 2002-03-06: implement check for endianness in native. Facilitates porting !
|
||||
bigEndian = nIsBigEndian();
|
||||
signed8 = nIsSigned8(); // Solaris on Sparc: signed, all others unsigned
|
||||
}
|
||||
}
|
||||
505
jdkSrc/jdk8/com/sun/media/sound/PortMixer.java
Normal file
505
jdkSrc/jdk8/com/sun/media/sound/PortMixer.java
Normal file
@@ -0,0 +1,505 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
import javax.sound.sampled.Control;
|
||||
import javax.sound.sampled.Line;
|
||||
import javax.sound.sampled.LineUnavailableException;
|
||||
import javax.sound.sampled.Port;
|
||||
import javax.sound.sampled.BooleanControl;
|
||||
import javax.sound.sampled.CompoundControl;
|
||||
import javax.sound.sampled.FloatControl;
|
||||
|
||||
|
||||
/**
|
||||
* A Mixer which only provides Ports.
|
||||
*
|
||||
* @author Florian Bomers
|
||||
*/
|
||||
final class PortMixer extends AbstractMixer {
|
||||
|
||||
// CONSTANTS
|
||||
private static final int SRC_UNKNOWN = 0x01;
|
||||
private static final int SRC_MICROPHONE = 0x02;
|
||||
private static final int SRC_LINE_IN = 0x03;
|
||||
private static final int SRC_COMPACT_DISC = 0x04;
|
||||
private static final int SRC_MASK = 0xFF;
|
||||
|
||||
private static final int DST_UNKNOWN = 0x0100;
|
||||
private static final int DST_SPEAKER = 0x0200;
|
||||
private static final int DST_HEADPHONE = 0x0300;
|
||||
private static final int DST_LINE_OUT = 0x0400;
|
||||
private static final int DST_MASK = 0xFF00;
|
||||
|
||||
// INSTANCE VARIABLES
|
||||
private Port.Info[] portInfos;
|
||||
// cache of instantiated ports
|
||||
private PortMixerPort[] ports;
|
||||
|
||||
// instance ID of the native implementation
|
||||
private long id = 0;
|
||||
|
||||
// CONSTRUCTOR
|
||||
PortMixer(PortMixerProvider.PortMixerInfo portMixerInfo) {
|
||||
// pass in Line.Info, mixer, controls
|
||||
super(portMixerInfo, // Mixer.Info
|
||||
null, // Control[]
|
||||
null, // Line.Info[] sourceLineInfo
|
||||
null); // Line.Info[] targetLineInfo
|
||||
|
||||
if (Printer.trace) Printer.trace(">> PortMixer: constructor");
|
||||
|
||||
int count = 0;
|
||||
int srcLineCount = 0;
|
||||
int dstLineCount = 0;
|
||||
|
||||
try {
|
||||
try {
|
||||
id = nOpen(getMixerIndex());
|
||||
if (id != 0) {
|
||||
count = nGetPortCount(id);
|
||||
if (count < 0) {
|
||||
if (Printer.trace) Printer.trace("nGetPortCount() returned error code: " + count);
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {}
|
||||
|
||||
portInfos = new Port.Info[count];
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
int type = nGetPortType(id, i);
|
||||
srcLineCount += ((type & SRC_MASK) != 0)?1:0;
|
||||
dstLineCount += ((type & DST_MASK) != 0)?1:0;
|
||||
portInfos[i] = getPortInfo(i, type);
|
||||
}
|
||||
} finally {
|
||||
if (id != 0) {
|
||||
nClose(id);
|
||||
}
|
||||
id = 0;
|
||||
}
|
||||
|
||||
// fill sourceLineInfo and targetLineInfos with copies of the ones in portInfos
|
||||
sourceLineInfo = new Port.Info[srcLineCount];
|
||||
targetLineInfo = new Port.Info[dstLineCount];
|
||||
|
||||
srcLineCount = 0; dstLineCount = 0;
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (portInfos[i].isSource()) {
|
||||
sourceLineInfo[srcLineCount++] = portInfos[i];
|
||||
} else {
|
||||
targetLineInfo[dstLineCount++] = portInfos[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (Printer.trace) Printer.trace("<< PortMixer: constructor completed");
|
||||
}
|
||||
|
||||
|
||||
// ABSTRACT MIXER: ABSTRACT METHOD IMPLEMENTATIONS
|
||||
|
||||
public Line getLine(Line.Info info) throws LineUnavailableException {
|
||||
Line.Info fullInfo = getLineInfo(info);
|
||||
|
||||
if ((fullInfo != null) && (fullInfo instanceof Port.Info)) {
|
||||
for (int i = 0; i < portInfos.length; i++) {
|
||||
if (fullInfo.equals(portInfos[i])) {
|
||||
return getPort(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Line unsupported: " + info);
|
||||
}
|
||||
|
||||
|
||||
public int getMaxLines(Line.Info info) {
|
||||
Line.Info fullInfo = getLineInfo(info);
|
||||
|
||||
// if it's not supported at all, return 0.
|
||||
if (fullInfo == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fullInfo instanceof Port.Info) {
|
||||
//return AudioSystem.NOT_SPECIFIED; // if several instances of PortMixerPort
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
protected void implOpen() throws LineUnavailableException {
|
||||
if (Printer.trace) Printer.trace(">> PortMixer: implOpen (id="+id+")");
|
||||
|
||||
// open the mixer device
|
||||
id = nOpen(getMixerIndex());
|
||||
|
||||
if (Printer.trace) Printer.trace("<< PortMixer: implOpen succeeded.");
|
||||
}
|
||||
|
||||
protected void implClose() {
|
||||
if (Printer.trace) Printer.trace(">> PortMixer: implClose");
|
||||
|
||||
// close the mixer device
|
||||
long thisID = id;
|
||||
id = 0;
|
||||
nClose(thisID);
|
||||
if (ports != null) {
|
||||
for (int i = 0; i < ports.length; i++) {
|
||||
if (ports[i] != null) {
|
||||
ports[i].disposeControls();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Printer.trace) Printer.trace("<< PortMixer: implClose succeeded");
|
||||
}
|
||||
|
||||
protected void implStart() {}
|
||||
protected void implStop() {}
|
||||
|
||||
// IMPLEMENTATION HELPERS
|
||||
|
||||
private Port.Info getPortInfo(int portIndex, int type) {
|
||||
switch (type) {
|
||||
case SRC_UNKNOWN: return new PortInfo(nGetPortName(getID(), portIndex), true);
|
||||
case SRC_MICROPHONE: return Port.Info.MICROPHONE;
|
||||
case SRC_LINE_IN: return Port.Info.LINE_IN;
|
||||
case SRC_COMPACT_DISC: return Port.Info.COMPACT_DISC;
|
||||
|
||||
case DST_UNKNOWN: return new PortInfo(nGetPortName(getID(), portIndex), false);
|
||||
case DST_SPEAKER: return Port.Info.SPEAKER;
|
||||
case DST_HEADPHONE: return Port.Info.HEADPHONE;
|
||||
case DST_LINE_OUT: return Port.Info.LINE_OUT;
|
||||
}
|
||||
// should never happen...
|
||||
if (Printer.debug) Printer.debug("unknown port type: "+type);
|
||||
return null;
|
||||
}
|
||||
|
||||
int getMixerIndex() {
|
||||
return ((PortMixerProvider.PortMixerInfo) getMixerInfo()).getIndex();
|
||||
}
|
||||
|
||||
Port getPort(int index) {
|
||||
if (ports == null) {
|
||||
ports = new PortMixerPort[portInfos.length];
|
||||
}
|
||||
if (ports[index] == null) {
|
||||
ports[index] = new PortMixerPort((Port.Info)portInfos[index], this, index);
|
||||
return ports[index];
|
||||
}
|
||||
// $$fb TODO: return (Port) (ports[index].clone());
|
||||
return ports[index];
|
||||
}
|
||||
|
||||
long getID() {
|
||||
return id;
|
||||
}
|
||||
|
||||
// INNER CLASSES
|
||||
|
||||
/**
|
||||
* Private inner class representing a Port for the PortMixer.
|
||||
*/
|
||||
private static final class PortMixerPort extends AbstractLine
|
||||
implements Port {
|
||||
|
||||
private final int portIndex;
|
||||
private long id;
|
||||
|
||||
// CONSTRUCTOR
|
||||
private PortMixerPort(Port.Info info,
|
||||
PortMixer mixer,
|
||||
int portIndex) {
|
||||
super(info, mixer, null);
|
||||
if (Printer.trace) Printer.trace("PortMixerPort CONSTRUCTOR: info: " + info);
|
||||
this.portIndex = portIndex;
|
||||
}
|
||||
|
||||
|
||||
// ABSTRACT METHOD IMPLEMENTATIONS
|
||||
|
||||
// ABSTRACT LINE
|
||||
|
||||
void implOpen() throws LineUnavailableException {
|
||||
if (Printer.trace) Printer.trace(">> PortMixerPort: implOpen().");
|
||||
long newID = ((PortMixer) mixer).getID();
|
||||
if ((id == 0) || (newID != id) || (controls.length == 0)) {
|
||||
id = newID;
|
||||
Vector vector = new Vector();
|
||||
synchronized (vector) {
|
||||
nGetControls(id, portIndex, vector);
|
||||
controls = new Control[vector.size()];
|
||||
for (int i = 0; i < controls.length; i++) {
|
||||
controls[i] = (Control) vector.elementAt(i);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
enableControls(controls, true);
|
||||
}
|
||||
if (Printer.trace) Printer.trace("<< PortMixerPort: implOpen() succeeded");
|
||||
}
|
||||
|
||||
private void enableControls(Control[] controls, boolean enable) {
|
||||
for (int i = 0; i < controls.length; i++) {
|
||||
if (controls[i] instanceof BoolCtrl) {
|
||||
((BoolCtrl) controls[i]).closed = !enable;
|
||||
}
|
||||
else if (controls[i] instanceof FloatCtrl) {
|
||||
((FloatCtrl) controls[i]).closed = !enable;
|
||||
}
|
||||
else if (controls[i] instanceof CompoundControl) {
|
||||
enableControls(((CompoundControl) controls[i]).getMemberControls(), enable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void disposeControls() {
|
||||
enableControls(controls, false);
|
||||
controls = new Control[0];
|
||||
}
|
||||
|
||||
|
||||
void implClose() {
|
||||
if (Printer.trace) Printer.trace(">> PortMixerPort: implClose()");
|
||||
// get rid of controls
|
||||
enableControls(controls, false);
|
||||
if (Printer.trace) Printer.trace("<< PortMixerPort: implClose() succeeded");
|
||||
}
|
||||
|
||||
// METHOD OVERRIDES
|
||||
|
||||
// this is very similar to open(AudioFormat, int) in AbstractDataLine...
|
||||
public void open() throws LineUnavailableException {
|
||||
synchronized (mixer) {
|
||||
// if the line is not currently open, try to open it with this format and buffer size
|
||||
if (!isOpen()) {
|
||||
if (Printer.trace) Printer.trace("> PortMixerPort: open");
|
||||
// reserve mixer resources for this line
|
||||
mixer.open(this);
|
||||
try {
|
||||
// open the line. may throw LineUnavailableException.
|
||||
implOpen();
|
||||
|
||||
// if we succeeded, set the open state to true and send events
|
||||
setOpen(true);
|
||||
} catch (LineUnavailableException e) {
|
||||
// release mixer resources for this line and then throw the exception
|
||||
mixer.close(this);
|
||||
throw e;
|
||||
}
|
||||
if (Printer.trace) Printer.trace("< PortMixerPort: open succeeded");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this is very similar to close() in AbstractDataLine...
|
||||
public void close() {
|
||||
synchronized (mixer) {
|
||||
if (isOpen()) {
|
||||
if (Printer.trace) Printer.trace("> PortMixerPort.close()");
|
||||
|
||||
// set the open state to false and send events
|
||||
setOpen(false);
|
||||
|
||||
// close resources for this line
|
||||
implClose();
|
||||
|
||||
// release mixer resources for this line
|
||||
mixer.close(this);
|
||||
if (Printer.trace) Printer.trace("< PortMixerPort.close() succeeded");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // class PortMixerPort
|
||||
|
||||
/**
|
||||
* Private inner class representing a BooleanControl for PortMixerPort
|
||||
*/
|
||||
private static final class BoolCtrl extends BooleanControl {
|
||||
// the handle to the native control function
|
||||
private final long controlID;
|
||||
private boolean closed = false;
|
||||
|
||||
private static BooleanControl.Type createType(String name) {
|
||||
if (name.equals("Mute")) {
|
||||
return BooleanControl.Type.MUTE;
|
||||
}
|
||||
else if (name.equals("Select")) {
|
||||
// $$fb add as new static type?
|
||||
//return BooleanControl.Type.SELECT;
|
||||
}
|
||||
return new BCT(name);
|
||||
}
|
||||
|
||||
|
||||
private BoolCtrl(long controlID, String name) {
|
||||
this(controlID, createType(name));
|
||||
}
|
||||
|
||||
private BoolCtrl(long controlID, BooleanControl.Type typ) {
|
||||
super(typ, false);
|
||||
this.controlID = controlID;
|
||||
}
|
||||
|
||||
public void setValue(boolean value) {
|
||||
if (!closed) {
|
||||
nControlSetIntValue(controlID, value?1:0);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getValue() {
|
||||
if (!closed) {
|
||||
// never use any cached values
|
||||
return (nControlGetIntValue(controlID)!=0)?true:false;
|
||||
}
|
||||
// ??
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* inner class for custom types
|
||||
*/
|
||||
private static final class BCT extends BooleanControl.Type {
|
||||
private BCT(String name) {
|
||||
super(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Private inner class representing a CompoundControl for PortMixerPort
|
||||
*/
|
||||
private static final class CompCtrl extends CompoundControl {
|
||||
private CompCtrl(String name, Control[] controls) {
|
||||
super(new CCT(name), controls);
|
||||
}
|
||||
|
||||
/**
|
||||
* inner class for custom compound control types
|
||||
*/
|
||||
private static final class CCT extends CompoundControl.Type {
|
||||
private CCT(String name) {
|
||||
super(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Private inner class representing a BooleanControl for PortMixerPort
|
||||
*/
|
||||
private static final class FloatCtrl extends FloatControl {
|
||||
// the handle to the native control function
|
||||
private final long controlID;
|
||||
private boolean closed = false;
|
||||
|
||||
// predefined float control types. See also Ports.h
|
||||
private final static FloatControl.Type[] FLOAT_CONTROL_TYPES = {
|
||||
null,
|
||||
FloatControl.Type.BALANCE,
|
||||
FloatControl.Type.MASTER_GAIN,
|
||||
FloatControl.Type.PAN,
|
||||
FloatControl.Type.VOLUME
|
||||
};
|
||||
|
||||
private FloatCtrl(long controlID, String name,
|
||||
float min, float max, float precision, String units) {
|
||||
this(controlID, new FCT(name), min, max, precision, units);
|
||||
}
|
||||
|
||||
private FloatCtrl(long controlID, int type,
|
||||
float min, float max, float precision, String units) {
|
||||
this(controlID, FLOAT_CONTROL_TYPES[type], min, max, precision, units);
|
||||
}
|
||||
|
||||
private FloatCtrl(long controlID, FloatControl.Type typ,
|
||||
float min, float max, float precision, String units) {
|
||||
super(typ, min, max, precision, 1000, min, units);
|
||||
this.controlID = controlID;
|
||||
}
|
||||
|
||||
public void setValue(float value) {
|
||||
if (!closed) {
|
||||
nControlSetFloatValue(controlID, value);
|
||||
}
|
||||
}
|
||||
|
||||
public float getValue() {
|
||||
if (!closed) {
|
||||
// never use any cached values
|
||||
return nControlGetFloatValue(controlID);
|
||||
}
|
||||
// ??
|
||||
return getMinimum();
|
||||
}
|
||||
|
||||
/**
|
||||
* inner class for custom types
|
||||
*/
|
||||
private static final class FCT extends FloatControl.Type {
|
||||
private FCT(String name) {
|
||||
super(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Private inner class representing a port info
|
||||
*/
|
||||
private static final class PortInfo extends Port.Info {
|
||||
private PortInfo(String name, boolean isSource) {
|
||||
super(Port.class, name, isSource);
|
||||
}
|
||||
}
|
||||
|
||||
// open the mixer with the given index. Returns a handle ID
|
||||
private static native long nOpen(int mixerIndex) throws LineUnavailableException;
|
||||
private static native void nClose(long id);
|
||||
|
||||
// gets the number of ports for this mixer
|
||||
private static native int nGetPortCount(long id);
|
||||
|
||||
// gets the type of the port with this index
|
||||
private static native int nGetPortType(long id, int portIndex);
|
||||
|
||||
// gets the name of the port with this index
|
||||
private static native String nGetPortName(long id, int portIndex);
|
||||
|
||||
// fills the vector with the controls for this port
|
||||
private static native void nGetControls(long id, int portIndex, Vector vector);
|
||||
|
||||
// getters/setters for controls
|
||||
private static native void nControlSetIntValue(long controlID, int value);
|
||||
private static native int nControlGetIntValue(long controlID);
|
||||
private static native void nControlSetFloatValue(long controlID, float value);
|
||||
private static native float nControlGetFloatValue(long controlID);
|
||||
|
||||
}
|
||||
151
jdkSrc/jdk8/com/sun/media/sound/PortMixerProvider.java
Normal file
151
jdkSrc/jdk8/com/sun/media/sound/PortMixerProvider.java
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.media.sound;
|
||||
|
||||
import javax.sound.sampled.Mixer;
|
||||
import javax.sound.sampled.spi.MixerProvider;
|
||||
|
||||
|
||||
/**
|
||||
* Port provider.
|
||||
*
|
||||
* @author Florian Bomers
|
||||
*/
|
||||
public final class PortMixerProvider extends MixerProvider {
|
||||
|
||||
// STATIC VARIABLES
|
||||
|
||||
/**
|
||||
* Set of info objects for all port input devices on the system.
|
||||
*/
|
||||
private static PortMixerInfo[] infos;
|
||||
|
||||
/**
|
||||
* Set of all port input devices on the system.
|
||||
*/
|
||||
private static PortMixer[] devices;
|
||||
|
||||
|
||||
// STATIC
|
||||
|
||||
static {
|
||||
// initialize
|
||||
Platform.initialize();
|
||||
}
|
||||
|
||||
|
||||
// CONSTRUCTOR
|
||||
|
||||
|
||||
/**
|
||||
* Required public no-arg constructor.
|
||||
*/
|
||||
public PortMixerProvider() {
|
||||
synchronized (PortMixerProvider.class) {
|
||||
if (Platform.isPortsEnabled()) {
|
||||
init();
|
||||
} else {
|
||||
infos = new PortMixerInfo[0];
|
||||
devices = new PortMixer[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void init() {
|
||||
// get the number of input devices
|
||||
int numDevices = nGetNumDevices();
|
||||
|
||||
if (infos == null || infos.length != numDevices) {
|
||||
if (Printer.trace) Printer.trace("PortMixerProvider: init()");
|
||||
// initialize the arrays
|
||||
infos = new PortMixerInfo[numDevices];
|
||||
devices = new PortMixer[numDevices];
|
||||
|
||||
// fill in the info objects now.
|
||||
// we'll fill in the device objects as they're requested.
|
||||
for (int i = 0; i < infos.length; i++) {
|
||||
infos[i] = nNewPortMixerInfo(i);
|
||||
}
|
||||
if (Printer.trace) Printer.trace("PortMixerProvider: init(): found numDevices: " + numDevices);
|
||||
}
|
||||
}
|
||||
|
||||
public Mixer.Info[] getMixerInfo() {
|
||||
synchronized (PortMixerProvider.class) {
|
||||
Mixer.Info[] localArray = new Mixer.Info[infos.length];
|
||||
System.arraycopy(infos, 0, localArray, 0, infos.length);
|
||||
return localArray;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Mixer getMixer(Mixer.Info info) {
|
||||
synchronized (PortMixerProvider.class) {
|
||||
for (int i = 0; i < infos.length; i++) {
|
||||
if (infos[i].equals(info)) {
|
||||
return getDevice(infos[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Mixer " + info.toString()
|
||||
+ " not supported by this provider.");
|
||||
}
|
||||
|
||||
|
||||
private static Mixer getDevice(PortMixerInfo info) {
|
||||
int index = info.getIndex();
|
||||
if (devices[index] == null) {
|
||||
devices[index] = new PortMixer(info);
|
||||
}
|
||||
return devices[index];
|
||||
}
|
||||
|
||||
// INNER CLASSES
|
||||
|
||||
|
||||
/**
|
||||
* Info class for PortMixers. Adds an index value for
|
||||
* making native references to a particular device.
|
||||
* This constructor is called from native.
|
||||
*/
|
||||
static final class PortMixerInfo extends Mixer.Info {
|
||||
private final int index;
|
||||
|
||||
private PortMixerInfo(int index, String name, String vendor, String description, String version) {
|
||||
super("Port " + name, vendor, description, version);
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
} // class PortMixerInfo
|
||||
|
||||
// NATIVE METHODS
|
||||
private static native int nGetNumDevices();
|
||||
private static native PortMixerInfo nNewPortMixerInfo(int mixerIndex);
|
||||
}
|
||||
127
jdkSrc/jdk8/com/sun/media/sound/Printer.java
Normal file
127
jdkSrc/jdk8/com/sun/media/sound/Printer.java
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.media.sound;
|
||||
|
||||
/**
|
||||
* Printer allows you to set up global debugging status and print
|
||||
* messages accordingly.
|
||||
*
|
||||
* @author David Rivas
|
||||
* @author Kara Kytle
|
||||
*/
|
||||
final class Printer {
|
||||
|
||||
static final boolean err = false;
|
||||
static final boolean debug = false;
|
||||
static final boolean trace = false;
|
||||
static final boolean verbose = false;
|
||||
static final boolean release = false;
|
||||
|
||||
static final boolean SHOW_THREADID = false;
|
||||
static final boolean SHOW_TIMESTAMP = false;
|
||||
|
||||
/*static void setErrorPrint(boolean on) {
|
||||
|
||||
err = on;
|
||||
}
|
||||
|
||||
static void setDebugPrint(boolean on) {
|
||||
|
||||
debug = on;
|
||||
}
|
||||
|
||||
static void setTracePrint(boolean on) {
|
||||
|
||||
trace = on;
|
||||
}
|
||||
|
||||
static void setVerbosePrint(boolean on) {
|
||||
|
||||
verbose = on;
|
||||
}
|
||||
|
||||
static void setReleasePrint(boolean on) {
|
||||
|
||||
release = on;
|
||||
}*/
|
||||
|
||||
/**
|
||||
* Suppresses default constructor, ensuring non-instantiability.
|
||||
*/
|
||||
private Printer() {
|
||||
}
|
||||
|
||||
public static void err(String str) {
|
||||
|
||||
if (err)
|
||||
println(str);
|
||||
}
|
||||
|
||||
public static void debug(String str) {
|
||||
|
||||
if (debug)
|
||||
println(str);
|
||||
}
|
||||
|
||||
public static void trace(String str) {
|
||||
|
||||
if (trace)
|
||||
println(str);
|
||||
}
|
||||
|
||||
public static void verbose(String str) {
|
||||
|
||||
if (verbose)
|
||||
println(str);
|
||||
}
|
||||
|
||||
public static void release(String str) {
|
||||
|
||||
if (release)
|
||||
println(str);
|
||||
}
|
||||
|
||||
private static long startTime = 0;
|
||||
|
||||
public static void println(String s) {
|
||||
String prepend = "";
|
||||
if (SHOW_THREADID) {
|
||||
prepend = "thread " + Thread.currentThread().getId() + " " + prepend;
|
||||
}
|
||||
if (SHOW_TIMESTAMP) {
|
||||
if (startTime == 0) {
|
||||
startTime = System.nanoTime() / 1000000l;
|
||||
}
|
||||
prepend = prepend + ((System.nanoTime()/1000000l) - startTime) + "millis: ";
|
||||
}
|
||||
System.out.println(prepend + s);
|
||||
}
|
||||
|
||||
public static void println() {
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
/**
|
||||
* This exception is used when a RIFF file contains illegal or unexpected data.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public final class RIFFInvalidDataException extends InvalidDataException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public RIFFInvalidDataException() {
|
||||
super("Invalid Data!");
|
||||
}
|
||||
|
||||
public RIFFInvalidDataException(String s) {
|
||||
super(s);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
/**
|
||||
* This exception is used when a reader is used to read RIFF file of a format it
|
||||
* doesn't unterstand or support.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public final class RIFFInvalidFormatException extends InvalidFormatException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public RIFFInvalidFormatException() {
|
||||
super("Invalid format!");
|
||||
}
|
||||
|
||||
public RIFFInvalidFormatException(String s) {
|
||||
super(s);
|
||||
}
|
||||
}
|
||||
339
jdkSrc/jdk8/com/sun/media/sound/RIFFReader.java
Normal file
339
jdkSrc/jdk8/com/sun/media/sound/RIFFReader.java
Normal file
@@ -0,0 +1,339 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Resource Interchange File Format (RIFF) stream decoder.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public final class RIFFReader extends InputStream {
|
||||
|
||||
private final RIFFReader root;
|
||||
private long filepointer = 0;
|
||||
private final String fourcc;
|
||||
private String riff_type = null;
|
||||
private long ckSize = Integer.MAX_VALUE;
|
||||
private InputStream stream;
|
||||
private long avail = Integer.MAX_VALUE;
|
||||
private RIFFReader lastiterator = null;
|
||||
|
||||
public RIFFReader(InputStream stream) throws IOException {
|
||||
|
||||
if (stream instanceof RIFFReader) {
|
||||
root = ((RIFFReader) stream).root;
|
||||
} else {
|
||||
root = this;
|
||||
}
|
||||
|
||||
this.stream = stream;
|
||||
|
||||
// Check for RIFF null paddings,
|
||||
int b;
|
||||
while (true) {
|
||||
b = read();
|
||||
if (b == -1) {
|
||||
fourcc = ""; // don't put null value into fourcc,
|
||||
// because it is expected to
|
||||
// always contain a string value
|
||||
riff_type = null;
|
||||
avail = 0;
|
||||
return;
|
||||
}
|
||||
if (b != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
byte[] fourcc = new byte[4];
|
||||
fourcc[0] = (byte) b;
|
||||
readFully(fourcc, 1, 3);
|
||||
this.fourcc = new String(fourcc, "ascii");
|
||||
ckSize = readUnsignedInt();
|
||||
avail = ckSize;
|
||||
|
||||
if (getFormat().equals("RIFF") || getFormat().equals("LIST")) {
|
||||
if (avail > Integer.MAX_VALUE) {
|
||||
throw new RIFFInvalidDataException("Chunk size too big");
|
||||
}
|
||||
byte[] format = new byte[4];
|
||||
readFully(format);
|
||||
this.riff_type = new String(format, "ascii");
|
||||
}
|
||||
}
|
||||
|
||||
public long getFilePointer() throws IOException {
|
||||
return root.filepointer;
|
||||
}
|
||||
|
||||
public boolean hasNextChunk() throws IOException {
|
||||
if (lastiterator != null)
|
||||
lastiterator.finish();
|
||||
return avail != 0;
|
||||
}
|
||||
|
||||
public RIFFReader nextChunk() throws IOException {
|
||||
if (lastiterator != null)
|
||||
lastiterator.finish();
|
||||
if (avail == 0)
|
||||
return null;
|
||||
lastiterator = new RIFFReader(this);
|
||||
return lastiterator;
|
||||
}
|
||||
|
||||
public String getFormat() {
|
||||
return fourcc;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return riff_type;
|
||||
}
|
||||
|
||||
public long getSize() {
|
||||
return ckSize;
|
||||
}
|
||||
|
||||
public int read() throws IOException {
|
||||
if (avail == 0) {
|
||||
return -1;
|
||||
}
|
||||
int b = stream.read();
|
||||
if (b == -1) {
|
||||
avail = 0;
|
||||
return -1;
|
||||
}
|
||||
avail--;
|
||||
filepointer++;
|
||||
return b;
|
||||
}
|
||||
|
||||
public int read(byte[] b, int offset, int len) throws IOException {
|
||||
if (avail == 0) {
|
||||
return -1;
|
||||
}
|
||||
if (len > avail) {
|
||||
int rlen = stream.read(b, offset, (int)avail);
|
||||
if (rlen != -1)
|
||||
filepointer += rlen;
|
||||
avail = 0;
|
||||
return rlen;
|
||||
} else {
|
||||
int ret = stream.read(b, offset, len);
|
||||
if (ret == -1) {
|
||||
avail = 0;
|
||||
return -1;
|
||||
}
|
||||
avail -= ret;
|
||||
filepointer += ret;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
public final void readFully(byte b[]) throws IOException {
|
||||
readFully(b, 0, b.length);
|
||||
}
|
||||
|
||||
public final void readFully(byte b[], int off, int len) throws IOException {
|
||||
if (len < 0)
|
||||
throw new IndexOutOfBoundsException();
|
||||
while (len > 0) {
|
||||
int s = read(b, off, len);
|
||||
if (s < 0)
|
||||
throw new EOFException();
|
||||
if (s == 0)
|
||||
Thread.yield();
|
||||
off += s;
|
||||
len -= s;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long skip(final long n) throws IOException {
|
||||
if (n <= 0 || avail == 0) {
|
||||
return 0;
|
||||
}
|
||||
// will not skip more than
|
||||
long remaining = Math.min(n, avail);
|
||||
while (remaining > 0) {
|
||||
// Some input streams like FileInputStream can return more bytes,
|
||||
// when EOF is reached.
|
||||
long ret = Math.min(stream.skip(remaining), remaining);
|
||||
if (ret == 0) {
|
||||
// EOF or not? we need to check.
|
||||
Thread.yield();
|
||||
if (stream.read() == -1) {
|
||||
avail = 0;
|
||||
break;
|
||||
}
|
||||
ret = 1;
|
||||
}
|
||||
remaining -= ret;
|
||||
avail -= ret;
|
||||
filepointer += ret;
|
||||
}
|
||||
return n - remaining;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int available() {
|
||||
return (int)avail;
|
||||
}
|
||||
|
||||
public void finish() throws IOException {
|
||||
if (avail != 0) {
|
||||
skip(avail);
|
||||
}
|
||||
}
|
||||
|
||||
// Read ASCII chars from stream
|
||||
public String readString(final int len) throws IOException {
|
||||
final byte[] buff;
|
||||
try {
|
||||
buff = new byte[len];
|
||||
} catch (final OutOfMemoryError oom) {
|
||||
throw new IOException("Length too big", oom);
|
||||
}
|
||||
readFully(buff);
|
||||
for (int i = 0; i < buff.length; i++) {
|
||||
if (buff[i] == 0) {
|
||||
return new String(buff, 0, i, "ascii");
|
||||
}
|
||||
}
|
||||
return new String(buff, "ascii");
|
||||
}
|
||||
|
||||
// Read 8 bit signed integer from stream
|
||||
public byte readByte() throws IOException {
|
||||
int ch = read();
|
||||
if (ch < 0)
|
||||
throw new EOFException();
|
||||
return (byte) ch;
|
||||
}
|
||||
|
||||
// Read 16 bit signed integer from stream
|
||||
public short readShort() throws IOException {
|
||||
int ch1 = read();
|
||||
int ch2 = read();
|
||||
if (ch1 < 0)
|
||||
throw new EOFException();
|
||||
if (ch2 < 0)
|
||||
throw new EOFException();
|
||||
return (short)(ch1 | (ch2 << 8));
|
||||
}
|
||||
|
||||
// Read 32 bit signed integer from stream
|
||||
public int readInt() throws IOException {
|
||||
int ch1 = read();
|
||||
int ch2 = read();
|
||||
int ch3 = read();
|
||||
int ch4 = read();
|
||||
if (ch1 < 0)
|
||||
throw new EOFException();
|
||||
if (ch2 < 0)
|
||||
throw new EOFException();
|
||||
if (ch3 < 0)
|
||||
throw new EOFException();
|
||||
if (ch4 < 0)
|
||||
throw new EOFException();
|
||||
return ch1 + (ch2 << 8) | (ch3 << 16) | (ch4 << 24);
|
||||
}
|
||||
|
||||
// Read 64 bit signed integer from stream
|
||||
public long readLong() throws IOException {
|
||||
long ch1 = read();
|
||||
long ch2 = read();
|
||||
long ch3 = read();
|
||||
long ch4 = read();
|
||||
long ch5 = read();
|
||||
long ch6 = read();
|
||||
long ch7 = read();
|
||||
long ch8 = read();
|
||||
if (ch1 < 0)
|
||||
throw new EOFException();
|
||||
if (ch2 < 0)
|
||||
throw new EOFException();
|
||||
if (ch3 < 0)
|
||||
throw new EOFException();
|
||||
if (ch4 < 0)
|
||||
throw new EOFException();
|
||||
if (ch5 < 0)
|
||||
throw new EOFException();
|
||||
if (ch6 < 0)
|
||||
throw new EOFException();
|
||||
if (ch7 < 0)
|
||||
throw new EOFException();
|
||||
if (ch8 < 0)
|
||||
throw new EOFException();
|
||||
return ch1 | (ch2 << 8) | (ch3 << 16) | (ch4 << 24)
|
||||
| (ch5 << 32) | (ch6 << 40) | (ch7 << 48) | (ch8 << 56);
|
||||
}
|
||||
|
||||
// Read 8 bit unsigned integer from stream
|
||||
public int readUnsignedByte() throws IOException {
|
||||
int ch = read();
|
||||
if (ch < 0)
|
||||
throw new EOFException();
|
||||
return ch;
|
||||
}
|
||||
|
||||
// Read 16 bit unsigned integer from stream
|
||||
public int readUnsignedShort() throws IOException {
|
||||
int ch1 = read();
|
||||
int ch2 = read();
|
||||
if (ch1 < 0)
|
||||
throw new EOFException();
|
||||
if (ch2 < 0)
|
||||
throw new EOFException();
|
||||
return ch1 | (ch2 << 8);
|
||||
}
|
||||
|
||||
// Read 32 bit unsigned integer from stream
|
||||
public long readUnsignedInt() throws IOException {
|
||||
long ch1 = read();
|
||||
long ch2 = read();
|
||||
long ch3 = read();
|
||||
long ch4 = read();
|
||||
if (ch1 < 0)
|
||||
throw new EOFException();
|
||||
if (ch2 < 0)
|
||||
throw new EOFException();
|
||||
if (ch3 < 0)
|
||||
throw new EOFException();
|
||||
if (ch4 < 0)
|
||||
throw new EOFException();
|
||||
return ch1 + (ch2 << 8) | (ch3 << 16) | (ch4 << 24);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
finish();
|
||||
if (this == root)
|
||||
stream.close();
|
||||
stream = null;
|
||||
}
|
||||
}
|
||||
365
jdkSrc/jdk8/com/sun/media/sound/RIFFWriter.java
Normal file
365
jdkSrc/jdk8/com/sun/media/sound/RIFFWriter.java
Normal file
@@ -0,0 +1,365 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
/**
|
||||
* Resource Interchange File Format (RIFF) stream encoder.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public final class RIFFWriter extends OutputStream {
|
||||
|
||||
private interface RandomAccessWriter {
|
||||
|
||||
public void seek(long chunksizepointer) throws IOException;
|
||||
|
||||
public long getPointer() throws IOException;
|
||||
|
||||
public void close() throws IOException;
|
||||
|
||||
public void write(int b) throws IOException;
|
||||
|
||||
public void write(byte[] b, int off, int len) throws IOException;
|
||||
|
||||
public void write(byte[] bytes) throws IOException;
|
||||
|
||||
public long length() throws IOException;
|
||||
|
||||
public void setLength(long i) throws IOException;
|
||||
}
|
||||
|
||||
private static class RandomAccessFileWriter implements RandomAccessWriter {
|
||||
|
||||
RandomAccessFile raf;
|
||||
|
||||
RandomAccessFileWriter(File file) throws FileNotFoundException {
|
||||
this.raf = new RandomAccessFile(file, "rw");
|
||||
}
|
||||
|
||||
RandomAccessFileWriter(String name) throws FileNotFoundException {
|
||||
this.raf = new RandomAccessFile(name, "rw");
|
||||
}
|
||||
|
||||
public void seek(long chunksizepointer) throws IOException {
|
||||
raf.seek(chunksizepointer);
|
||||
}
|
||||
|
||||
public long getPointer() throws IOException {
|
||||
return raf.getFilePointer();
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
raf.close();
|
||||
}
|
||||
|
||||
public void write(int b) throws IOException {
|
||||
raf.write(b);
|
||||
}
|
||||
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
raf.write(b, off, len);
|
||||
}
|
||||
|
||||
public void write(byte[] bytes) throws IOException {
|
||||
raf.write(bytes);
|
||||
}
|
||||
|
||||
public long length() throws IOException {
|
||||
return raf.length();
|
||||
}
|
||||
|
||||
public void setLength(long i) throws IOException {
|
||||
raf.setLength(i);
|
||||
}
|
||||
}
|
||||
|
||||
private static class RandomAccessByteWriter implements RandomAccessWriter {
|
||||
|
||||
byte[] buff = new byte[32];
|
||||
int length = 0;
|
||||
int pos = 0;
|
||||
byte[] s;
|
||||
final OutputStream stream;
|
||||
|
||||
RandomAccessByteWriter(OutputStream stream) {
|
||||
this.stream = stream;
|
||||
}
|
||||
|
||||
public void seek(long chunksizepointer) throws IOException {
|
||||
pos = (int) chunksizepointer;
|
||||
}
|
||||
|
||||
public long getPointer() throws IOException {
|
||||
return pos;
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
stream.write(buff, 0, length);
|
||||
stream.close();
|
||||
}
|
||||
|
||||
public void write(int b) throws IOException {
|
||||
if (s == null)
|
||||
s = new byte[1];
|
||||
s[0] = (byte)b;
|
||||
write(s, 0, 1);
|
||||
}
|
||||
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
int newsize = pos + len;
|
||||
if (newsize > length)
|
||||
setLength(newsize);
|
||||
int end = off + len;
|
||||
for (int i = off; i < end; i++) {
|
||||
buff[pos++] = b[i];
|
||||
}
|
||||
}
|
||||
|
||||
public void write(byte[] bytes) throws IOException {
|
||||
write(bytes, 0, bytes.length);
|
||||
}
|
||||
|
||||
public long length() throws IOException {
|
||||
return length;
|
||||
}
|
||||
|
||||
public void setLength(long i) throws IOException {
|
||||
length = (int) i;
|
||||
if (length > buff.length) {
|
||||
int newlen = Math.max(buff.length << 1, length);
|
||||
byte[] newbuff = new byte[newlen];
|
||||
System.arraycopy(buff, 0, newbuff, 0, buff.length);
|
||||
buff = newbuff;
|
||||
}
|
||||
}
|
||||
}
|
||||
private int chunktype = 0; // 0=RIFF, 1=LIST; 2=CHUNK
|
||||
private RandomAccessWriter raf;
|
||||
private final long chunksizepointer;
|
||||
private final long startpointer;
|
||||
private RIFFWriter childchunk = null;
|
||||
private boolean open = true;
|
||||
private boolean writeoverride = false;
|
||||
|
||||
public RIFFWriter(String name, String format) throws IOException {
|
||||
this(new RandomAccessFileWriter(name), format, 0);
|
||||
}
|
||||
|
||||
public RIFFWriter(File file, String format) throws IOException {
|
||||
this(new RandomAccessFileWriter(file), format, 0);
|
||||
}
|
||||
|
||||
public RIFFWriter(OutputStream stream, String format) throws IOException {
|
||||
this(new RandomAccessByteWriter(stream), format, 0);
|
||||
}
|
||||
|
||||
private RIFFWriter(RandomAccessWriter raf, String format, int chunktype)
|
||||
throws IOException {
|
||||
if (chunktype == 0)
|
||||
if (raf.length() != 0)
|
||||
raf.setLength(0);
|
||||
this.raf = raf;
|
||||
if (raf.getPointer() % 2 != 0)
|
||||
raf.write(0);
|
||||
|
||||
if (chunktype == 0)
|
||||
raf.write("RIFF".getBytes("ascii"));
|
||||
else if (chunktype == 1)
|
||||
raf.write("LIST".getBytes("ascii"));
|
||||
else
|
||||
raf.write((format + " ").substring(0, 4).getBytes("ascii"));
|
||||
|
||||
chunksizepointer = raf.getPointer();
|
||||
this.chunktype = 2;
|
||||
writeUnsignedInt(0);
|
||||
this.chunktype = chunktype;
|
||||
startpointer = raf.getPointer();
|
||||
if (chunktype != 2)
|
||||
raf.write((format + " ").substring(0, 4).getBytes("ascii"));
|
||||
|
||||
}
|
||||
|
||||
public void seek(long pos) throws IOException {
|
||||
raf.seek(pos);
|
||||
}
|
||||
|
||||
public long getFilePointer() throws IOException {
|
||||
return raf.getPointer();
|
||||
}
|
||||
|
||||
public void setWriteOverride(boolean writeoverride) {
|
||||
this.writeoverride = writeoverride;
|
||||
}
|
||||
|
||||
public boolean getWriteOverride() {
|
||||
return writeoverride;
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
if (!open)
|
||||
return;
|
||||
if (childchunk != null) {
|
||||
childchunk.close();
|
||||
childchunk = null;
|
||||
}
|
||||
|
||||
int bakchunktype = chunktype;
|
||||
long fpointer = raf.getPointer();
|
||||
raf.seek(chunksizepointer);
|
||||
chunktype = 2;
|
||||
writeUnsignedInt(fpointer - startpointer);
|
||||
|
||||
if (bakchunktype == 0)
|
||||
raf.close();
|
||||
else
|
||||
raf.seek(fpointer);
|
||||
open = false;
|
||||
raf = null;
|
||||
}
|
||||
|
||||
public void write(int b) throws IOException {
|
||||
if (!writeoverride) {
|
||||
if (chunktype != 2) {
|
||||
throw new IllegalArgumentException(
|
||||
"Only chunks can write bytes!");
|
||||
}
|
||||
if (childchunk != null) {
|
||||
childchunk.close();
|
||||
childchunk = null;
|
||||
}
|
||||
}
|
||||
raf.write(b);
|
||||
}
|
||||
|
||||
public void write(byte b[], int off, int len) throws IOException {
|
||||
if (!writeoverride) {
|
||||
if (chunktype != 2) {
|
||||
throw new IllegalArgumentException(
|
||||
"Only chunks can write bytes!");
|
||||
}
|
||||
if (childchunk != null) {
|
||||
childchunk.close();
|
||||
childchunk = null;
|
||||
}
|
||||
}
|
||||
raf.write(b, off, len);
|
||||
}
|
||||
|
||||
public RIFFWriter writeList(String format) throws IOException {
|
||||
if (chunktype == 2) {
|
||||
throw new IllegalArgumentException(
|
||||
"Only LIST and RIFF can write lists!");
|
||||
}
|
||||
if (childchunk != null) {
|
||||
childchunk.close();
|
||||
childchunk = null;
|
||||
}
|
||||
childchunk = new RIFFWriter(this.raf, format, 1);
|
||||
return childchunk;
|
||||
}
|
||||
|
||||
public RIFFWriter writeChunk(String format) throws IOException {
|
||||
if (chunktype == 2) {
|
||||
throw new IllegalArgumentException(
|
||||
"Only LIST and RIFF can write chunks!");
|
||||
}
|
||||
if (childchunk != null) {
|
||||
childchunk.close();
|
||||
childchunk = null;
|
||||
}
|
||||
childchunk = new RIFFWriter(this.raf, format, 2);
|
||||
return childchunk;
|
||||
}
|
||||
|
||||
// Write ASCII chars to stream
|
||||
public void writeString(String string) throws IOException {
|
||||
byte[] buff = string.getBytes();
|
||||
write(buff);
|
||||
}
|
||||
|
||||
// Write ASCII chars to stream
|
||||
public void writeString(String string, int len) throws IOException {
|
||||
byte[] buff = string.getBytes();
|
||||
if (buff.length > len)
|
||||
write(buff, 0, len);
|
||||
else {
|
||||
write(buff);
|
||||
for (int i = buff.length; i < len; i++)
|
||||
write(0);
|
||||
}
|
||||
}
|
||||
|
||||
// Write 8 bit signed integer to stream
|
||||
public void writeByte(int b) throws IOException {
|
||||
write(b);
|
||||
}
|
||||
|
||||
// Write 16 bit signed integer to stream
|
||||
public void writeShort(short b) throws IOException {
|
||||
write((b >>> 0) & 0xFF);
|
||||
write((b >>> 8) & 0xFF);
|
||||
}
|
||||
|
||||
// Write 32 bit signed integer to stream
|
||||
public void writeInt(int b) throws IOException {
|
||||
write((b >>> 0) & 0xFF);
|
||||
write((b >>> 8) & 0xFF);
|
||||
write((b >>> 16) & 0xFF);
|
||||
write((b >>> 24) & 0xFF);
|
||||
}
|
||||
|
||||
// Write 64 bit signed integer to stream
|
||||
public void writeLong(long b) throws IOException {
|
||||
write((int) (b >>> 0) & 0xFF);
|
||||
write((int) (b >>> 8) & 0xFF);
|
||||
write((int) (b >>> 16) & 0xFF);
|
||||
write((int) (b >>> 24) & 0xFF);
|
||||
write((int) (b >>> 32) & 0xFF);
|
||||
write((int) (b >>> 40) & 0xFF);
|
||||
write((int) (b >>> 48) & 0xFF);
|
||||
write((int) (b >>> 56) & 0xFF);
|
||||
}
|
||||
|
||||
// Write 8 bit unsigned integer to stream
|
||||
public void writeUnsignedByte(int b) throws IOException {
|
||||
writeByte((byte) b);
|
||||
}
|
||||
|
||||
// Write 16 bit unsigned integer to stream
|
||||
public void writeUnsignedShort(int b) throws IOException {
|
||||
writeShort((short) b);
|
||||
}
|
||||
|
||||
// Write 32 bit unsigned integer to stream
|
||||
public void writeUnsignedInt(long b) throws IOException {
|
||||
writeInt((int) b);
|
||||
}
|
||||
}
|
||||
2084
jdkSrc/jdk8/com/sun/media/sound/RealTimeSequencer.java
Normal file
2084
jdkSrc/jdk8/com/sun/media/sound/RealTimeSequencer.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.media.sound;
|
||||
|
||||
import javax.sound.midi.MidiDevice;
|
||||
import javax.sound.midi.MidiUnavailableException;
|
||||
import javax.sound.midi.spi.MidiDeviceProvider;
|
||||
|
||||
/**
|
||||
* Provider for RealTimeSequencer objects.
|
||||
*
|
||||
* @author Florian Bomers
|
||||
*/
|
||||
public final class RealTimeSequencerProvider extends MidiDeviceProvider {
|
||||
|
||||
|
||||
public MidiDevice.Info[] getDeviceInfo() {
|
||||
|
||||
MidiDevice.Info[] localArray = { RealTimeSequencer.info };
|
||||
return localArray;
|
||||
}
|
||||
|
||||
|
||||
public MidiDevice getDevice(MidiDevice.Info info) {
|
||||
if ((info != null) && (!info.equals(RealTimeSequencer.info))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return new RealTimeSequencer();
|
||||
} catch (MidiUnavailableException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
52
jdkSrc/jdk8/com/sun/media/sound/ReferenceCountingDevice.java
Normal file
52
jdkSrc/jdk8/com/sun/media/sound/ReferenceCountingDevice.java
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.media.sound;
|
||||
|
||||
import javax.sound.midi.MidiUnavailableException;
|
||||
import javax.sound.midi.Receiver;
|
||||
import javax.sound.midi.Transmitter;
|
||||
|
||||
|
||||
|
||||
/** MidiDevice that can use reference counting for open/close.
|
||||
* This interface is intended to be used by MidiSystem.getTransmitter() and
|
||||
* MidiSystem.getReceiver().
|
||||
*
|
||||
* @author Matthias Pfisterer
|
||||
*/
|
||||
public interface ReferenceCountingDevice {
|
||||
/** Retrieve a Receiver that opens the device implicitly.
|
||||
* This method is similar to MidiDevice.getReceiver(). However, by calling this one,
|
||||
* the device is opened implicitly. This is needed by MidiSystem.getReceiver().
|
||||
*/
|
||||
public Receiver getReceiverReferenceCounting() throws MidiUnavailableException;
|
||||
|
||||
/** Retrieve a Transmitter that opens the device implicitly.
|
||||
* This method is similar to MidiDevice.getTransmitter(). However, by calling this one,
|
||||
* the device is opened implicitly. This is needed by MidiSystem.getTransmitter().
|
||||
*/
|
||||
public Transmitter getTransmitterReferenceCounting() throws MidiUnavailableException;
|
||||
}
|
||||
33
jdkSrc/jdk8/com/sun/media/sound/SF2GlobalRegion.java
Normal file
33
jdkSrc/jdk8/com/sun/media/sound/SF2GlobalRegion.java
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
/**
|
||||
* Soundfont global region.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public final class SF2GlobalRegion extends SF2Region {
|
||||
}
|
||||
911
jdkSrc/jdk8/com/sun/media/sound/SF2Instrument.java
Normal file
911
jdkSrc/jdk8/com/sun/media/sound/SF2Instrument.java
Normal file
@@ -0,0 +1,911 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.sound.midi.Patch;
|
||||
|
||||
/**
|
||||
* Soundfont instrument.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public final class SF2Instrument extends ModelInstrument {
|
||||
|
||||
String name = "";
|
||||
int preset = 0;
|
||||
int bank = 0;
|
||||
long library = 0;
|
||||
long genre = 0;
|
||||
long morphology = 0;
|
||||
SF2GlobalRegion globalregion = null;
|
||||
List<SF2InstrumentRegion> regions
|
||||
= new ArrayList<SF2InstrumentRegion>();
|
||||
|
||||
public SF2Instrument() {
|
||||
super(null, null, null, null);
|
||||
}
|
||||
|
||||
public SF2Instrument(SF2Soundbank soundbank) {
|
||||
super(soundbank, null, null, null);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Patch getPatch() {
|
||||
if (bank == 128)
|
||||
return new ModelPatch(0, preset, true);
|
||||
else
|
||||
return new ModelPatch(bank << 7, preset, false);
|
||||
}
|
||||
|
||||
public void setPatch(Patch patch) {
|
||||
if (patch instanceof ModelPatch && ((ModelPatch) patch).isPercussion()) {
|
||||
bank = 128;
|
||||
preset = patch.getProgram();
|
||||
} else {
|
||||
bank = patch.getBank() >> 7;
|
||||
preset = patch.getProgram();
|
||||
}
|
||||
}
|
||||
|
||||
public Object getData() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public long getGenre() {
|
||||
return genre;
|
||||
}
|
||||
|
||||
public void setGenre(long genre) {
|
||||
this.genre = genre;
|
||||
}
|
||||
|
||||
public long getLibrary() {
|
||||
return library;
|
||||
}
|
||||
|
||||
public void setLibrary(long library) {
|
||||
this.library = library;
|
||||
}
|
||||
|
||||
public long getMorphology() {
|
||||
return morphology;
|
||||
}
|
||||
|
||||
public void setMorphology(long morphology) {
|
||||
this.morphology = morphology;
|
||||
}
|
||||
|
||||
public List<SF2InstrumentRegion> getRegions() {
|
||||
return regions;
|
||||
}
|
||||
|
||||
public SF2GlobalRegion getGlobalRegion() {
|
||||
return globalregion;
|
||||
}
|
||||
|
||||
public void setGlobalZone(SF2GlobalRegion zone) {
|
||||
globalregion = zone;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
if (bank == 128)
|
||||
return "Drumkit: " + name + " preset #" + preset;
|
||||
else
|
||||
return "Instrument: " + name + " bank #" + bank
|
||||
+ " preset #" + preset;
|
||||
}
|
||||
|
||||
public ModelPerformer[] getPerformers() {
|
||||
int performercount = 0;
|
||||
for (SF2InstrumentRegion presetzone : regions)
|
||||
performercount += presetzone.getLayer().getRegions().size();
|
||||
ModelPerformer[] performers = new ModelPerformer[performercount];
|
||||
int pi = 0;
|
||||
|
||||
SF2GlobalRegion presetglobal = globalregion;
|
||||
for (SF2InstrumentRegion presetzone : regions) {
|
||||
Map<Integer, Short> pgenerators = new HashMap<Integer, Short>();
|
||||
pgenerators.putAll(presetzone.getGenerators());
|
||||
if (presetglobal != null)
|
||||
pgenerators.putAll(presetglobal.getGenerators());
|
||||
|
||||
SF2Layer layer = presetzone.getLayer();
|
||||
SF2GlobalRegion layerglobal = layer.getGlobalRegion();
|
||||
for (SF2LayerRegion layerzone : layer.getRegions()) {
|
||||
ModelPerformer performer = new ModelPerformer();
|
||||
if (layerzone.getSample() != null)
|
||||
performer.setName(layerzone.getSample().getName());
|
||||
else
|
||||
performer.setName(layer.getName());
|
||||
|
||||
performers[pi++] = performer;
|
||||
|
||||
int keyfrom = 0;
|
||||
int keyto = 127;
|
||||
int velfrom = 0;
|
||||
int velto = 127;
|
||||
|
||||
if (layerzone.contains(SF2Region.GENERATOR_EXCLUSIVECLASS)) {
|
||||
performer.setExclusiveClass(layerzone.getInteger(
|
||||
SF2Region.GENERATOR_EXCLUSIVECLASS));
|
||||
}
|
||||
if (layerzone.contains(SF2Region.GENERATOR_KEYRANGE)) {
|
||||
byte[] bytes = layerzone.getBytes(
|
||||
SF2Region.GENERATOR_KEYRANGE);
|
||||
if (bytes[0] >= 0)
|
||||
if (bytes[0] > keyfrom)
|
||||
keyfrom = bytes[0];
|
||||
if (bytes[1] >= 0)
|
||||
if (bytes[1] < keyto)
|
||||
keyto = bytes[1];
|
||||
}
|
||||
if (layerzone.contains(SF2Region.GENERATOR_VELRANGE)) {
|
||||
byte[] bytes = layerzone.getBytes(
|
||||
SF2Region.GENERATOR_VELRANGE);
|
||||
if (bytes[0] >= 0)
|
||||
if (bytes[0] > velfrom)
|
||||
velfrom = bytes[0];
|
||||
if (bytes[1] >= 0)
|
||||
if (bytes[1] < velto)
|
||||
velto = bytes[1];
|
||||
}
|
||||
if (presetzone.contains(SF2Region.GENERATOR_KEYRANGE)) {
|
||||
byte[] bytes = presetzone.getBytes(
|
||||
SF2Region.GENERATOR_KEYRANGE);
|
||||
if (bytes[0] > keyfrom)
|
||||
keyfrom = bytes[0];
|
||||
if (bytes[1] < keyto)
|
||||
keyto = bytes[1];
|
||||
}
|
||||
if (presetzone.contains(SF2Region.GENERATOR_VELRANGE)) {
|
||||
byte[] bytes = presetzone.getBytes(
|
||||
SF2Region.GENERATOR_VELRANGE);
|
||||
if (bytes[0] > velfrom)
|
||||
velfrom = bytes[0];
|
||||
if (bytes[1] < velto)
|
||||
velto = bytes[1];
|
||||
}
|
||||
performer.setKeyFrom(keyfrom);
|
||||
performer.setKeyTo(keyto);
|
||||
performer.setVelFrom(velfrom);
|
||||
performer.setVelTo(velto);
|
||||
|
||||
int startAddrsOffset = layerzone.getShort(
|
||||
SF2Region.GENERATOR_STARTADDRSOFFSET);
|
||||
int endAddrsOffset = layerzone.getShort(
|
||||
SF2Region.GENERATOR_ENDADDRSOFFSET);
|
||||
int startloopAddrsOffset = layerzone.getShort(
|
||||
SF2Region.GENERATOR_STARTLOOPADDRSOFFSET);
|
||||
int endloopAddrsOffset = layerzone.getShort(
|
||||
SF2Region.GENERATOR_ENDLOOPADDRSOFFSET);
|
||||
|
||||
startAddrsOffset += layerzone.getShort(
|
||||
SF2Region.GENERATOR_STARTADDRSCOARSEOFFSET) * 32768;
|
||||
endAddrsOffset += layerzone.getShort(
|
||||
SF2Region.GENERATOR_ENDADDRSCOARSEOFFSET) * 32768;
|
||||
startloopAddrsOffset += layerzone.getShort(
|
||||
SF2Region.GENERATOR_STARTLOOPADDRSCOARSEOFFSET) * 32768;
|
||||
endloopAddrsOffset += layerzone.getShort(
|
||||
SF2Region.GENERATOR_ENDLOOPADDRSCOARSEOFFSET) * 32768;
|
||||
startloopAddrsOffset -= startAddrsOffset;
|
||||
endloopAddrsOffset -= startAddrsOffset;
|
||||
|
||||
SF2Sample sample = layerzone.getSample();
|
||||
int rootkey = sample.originalPitch;
|
||||
if (layerzone.getShort(SF2Region.GENERATOR_OVERRIDINGROOTKEY) != -1) {
|
||||
rootkey = layerzone.getShort(
|
||||
SF2Region.GENERATOR_OVERRIDINGROOTKEY);
|
||||
}
|
||||
float pitchcorrection = (-rootkey * 100) + sample.pitchCorrection;
|
||||
ModelByteBuffer buff = sample.getDataBuffer();
|
||||
ModelByteBuffer buff24 = sample.getData24Buffer();
|
||||
|
||||
if (startAddrsOffset != 0 || endAddrsOffset != 0) {
|
||||
buff = buff.subbuffer(startAddrsOffset * 2,
|
||||
buff.capacity() + endAddrsOffset * 2);
|
||||
if (buff24 != null) {
|
||||
buff24 = buff24.subbuffer(startAddrsOffset,
|
||||
buff24.capacity() + endAddrsOffset);
|
||||
}
|
||||
|
||||
/*
|
||||
if (startAddrsOffset < 0)
|
||||
startAddrsOffset = 0;
|
||||
if (endAddrsOffset > (buff.capacity()/2-startAddrsOffset))
|
||||
startAddrsOffset = (int)buff.capacity()/2-startAddrsOffset;
|
||||
byte[] data = buff.array();
|
||||
int off = (int)buff.arrayOffset() + startAddrsOffset*2;
|
||||
int len = (int)buff.capacity() + endAddrsOffset*2;
|
||||
if (off+len > data.length)
|
||||
len = data.length - off;
|
||||
buff = new ModelByteBuffer(data, off, len);
|
||||
if(buff24 != null) {
|
||||
data = buff.array();
|
||||
off = (int)buff.arrayOffset() + startAddrsOffset;
|
||||
len = (int)buff.capacity() + endAddrsOffset;
|
||||
buff24 = new ModelByteBuffer(data, off, len);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
ModelByteBufferWavetable osc = new ModelByteBufferWavetable(
|
||||
buff, sample.getFormat(), pitchcorrection);
|
||||
if (buff24 != null)
|
||||
osc.set8BitExtensionBuffer(buff24);
|
||||
|
||||
Map<Integer, Short> generators = new HashMap<Integer, Short>();
|
||||
if (layerglobal != null)
|
||||
generators.putAll(layerglobal.getGenerators());
|
||||
generators.putAll(layerzone.getGenerators());
|
||||
for (Map.Entry<Integer, Short> gen : pgenerators.entrySet()) {
|
||||
short val;
|
||||
if (!generators.containsKey(gen.getKey()))
|
||||
val = layerzone.getShort(gen.getKey());
|
||||
else
|
||||
val = generators.get(gen.getKey());
|
||||
val += gen.getValue();
|
||||
generators.put(gen.getKey(), val);
|
||||
}
|
||||
|
||||
// SampleMode:
|
||||
// 0 indicates a sound reproduced with no loop
|
||||
// 1 indicates a sound which loops continuously
|
||||
// 2 is unused but should be interpreted as indicating no loop
|
||||
// 3 indicates a sound which loops for the duration of key
|
||||
// depression then proceeds to play the remainder of the sample.
|
||||
int sampleMode = getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_SAMPLEMODES);
|
||||
if ((sampleMode == 1) || (sampleMode == 3)) {
|
||||
if (sample.startLoop >= 0 && sample.endLoop > 0) {
|
||||
osc.setLoopStart((int)(sample.startLoop
|
||||
+ startloopAddrsOffset));
|
||||
osc.setLoopLength((int)(sample.endLoop - sample.startLoop
|
||||
+ endloopAddrsOffset - startloopAddrsOffset));
|
||||
if (sampleMode == 1)
|
||||
osc.setLoopType(ModelWavetable.LOOP_TYPE_FORWARD);
|
||||
if (sampleMode == 3)
|
||||
osc.setLoopType(ModelWavetable.LOOP_TYPE_RELEASE);
|
||||
}
|
||||
}
|
||||
performer.getOscillators().add(osc);
|
||||
|
||||
|
||||
short volDelay = getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_DELAYVOLENV);
|
||||
short volAttack = getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_ATTACKVOLENV);
|
||||
short volHold = getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_HOLDVOLENV);
|
||||
short volDecay = getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_DECAYVOLENV);
|
||||
short volSustain = getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_SUSTAINVOLENV);
|
||||
short volRelease = getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_RELEASEVOLENV);
|
||||
|
||||
if (volHold != -12000) {
|
||||
short volKeyNumToHold = getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_KEYNUMTOVOLENVHOLD);
|
||||
volHold += 60 * volKeyNumToHold;
|
||||
float fvalue = -volKeyNumToHold * 128;
|
||||
ModelIdentifier src = ModelSource.SOURCE_NOTEON_KEYNUMBER;
|
||||
ModelIdentifier dest = ModelDestination.DESTINATION_EG1_HOLD;
|
||||
performer.getConnectionBlocks().add(
|
||||
new ModelConnectionBlock(new ModelSource(src), fvalue,
|
||||
new ModelDestination(dest)));
|
||||
}
|
||||
if (volDecay != -12000) {
|
||||
short volKeyNumToDecay = getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_KEYNUMTOVOLENVDECAY);
|
||||
volDecay += 60 * volKeyNumToDecay;
|
||||
float fvalue = -volKeyNumToDecay * 128;
|
||||
ModelIdentifier src = ModelSource.SOURCE_NOTEON_KEYNUMBER;
|
||||
ModelIdentifier dest = ModelDestination.DESTINATION_EG1_DECAY;
|
||||
performer.getConnectionBlocks().add(
|
||||
new ModelConnectionBlock(new ModelSource(src), fvalue,
|
||||
new ModelDestination(dest)));
|
||||
}
|
||||
|
||||
addTimecentValue(performer,
|
||||
ModelDestination.DESTINATION_EG1_DELAY, volDelay);
|
||||
addTimecentValue(performer,
|
||||
ModelDestination.DESTINATION_EG1_ATTACK, volAttack);
|
||||
addTimecentValue(performer,
|
||||
ModelDestination.DESTINATION_EG1_HOLD, volHold);
|
||||
addTimecentValue(performer,
|
||||
ModelDestination.DESTINATION_EG1_DECAY, volDecay);
|
||||
//float fvolsustain = (960-volSustain)*(1000.0f/960.0f);
|
||||
|
||||
volSustain = (short)(1000 - volSustain);
|
||||
if (volSustain < 0)
|
||||
volSustain = 0;
|
||||
if (volSustain > 1000)
|
||||
volSustain = 1000;
|
||||
|
||||
addValue(performer,
|
||||
ModelDestination.DESTINATION_EG1_SUSTAIN, volSustain);
|
||||
addTimecentValue(performer,
|
||||
ModelDestination.DESTINATION_EG1_RELEASE, volRelease);
|
||||
|
||||
if (getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_MODENVTOFILTERFC) != 0
|
||||
|| getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_MODENVTOPITCH) != 0) {
|
||||
short modDelay = getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_DELAYMODENV);
|
||||
short modAttack = getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_ATTACKMODENV);
|
||||
short modHold = getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_HOLDMODENV);
|
||||
short modDecay = getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_DECAYMODENV);
|
||||
short modSustain = getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_SUSTAINMODENV);
|
||||
short modRelease = getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_RELEASEMODENV);
|
||||
|
||||
|
||||
if (modHold != -12000) {
|
||||
short modKeyNumToHold = getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_KEYNUMTOMODENVHOLD);
|
||||
modHold += 60 * modKeyNumToHold;
|
||||
float fvalue = -modKeyNumToHold * 128;
|
||||
ModelIdentifier src = ModelSource.SOURCE_NOTEON_KEYNUMBER;
|
||||
ModelIdentifier dest = ModelDestination.DESTINATION_EG2_HOLD;
|
||||
performer.getConnectionBlocks().add(
|
||||
new ModelConnectionBlock(new ModelSource(src),
|
||||
fvalue, new ModelDestination(dest)));
|
||||
}
|
||||
if (modDecay != -12000) {
|
||||
short modKeyNumToDecay = getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_KEYNUMTOMODENVDECAY);
|
||||
modDecay += 60 * modKeyNumToDecay;
|
||||
float fvalue = -modKeyNumToDecay * 128;
|
||||
ModelIdentifier src = ModelSource.SOURCE_NOTEON_KEYNUMBER;
|
||||
ModelIdentifier dest = ModelDestination.DESTINATION_EG2_DECAY;
|
||||
performer.getConnectionBlocks().add(
|
||||
new ModelConnectionBlock(new ModelSource(src),
|
||||
fvalue, new ModelDestination(dest)));
|
||||
}
|
||||
|
||||
addTimecentValue(performer,
|
||||
ModelDestination.DESTINATION_EG2_DELAY, modDelay);
|
||||
addTimecentValue(performer,
|
||||
ModelDestination.DESTINATION_EG2_ATTACK, modAttack);
|
||||
addTimecentValue(performer,
|
||||
ModelDestination.DESTINATION_EG2_HOLD, modHold);
|
||||
addTimecentValue(performer,
|
||||
ModelDestination.DESTINATION_EG2_DECAY, modDecay);
|
||||
if (modSustain < 0)
|
||||
modSustain = 0;
|
||||
if (modSustain > 1000)
|
||||
modSustain = 1000;
|
||||
addValue(performer, ModelDestination.DESTINATION_EG2_SUSTAIN,
|
||||
1000 - modSustain);
|
||||
addTimecentValue(performer,
|
||||
ModelDestination.DESTINATION_EG2_RELEASE, modRelease);
|
||||
|
||||
if (getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_MODENVTOFILTERFC) != 0) {
|
||||
double fvalue = getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_MODENVTOFILTERFC);
|
||||
ModelIdentifier src = ModelSource.SOURCE_EG2;
|
||||
ModelIdentifier dest
|
||||
= ModelDestination.DESTINATION_FILTER_FREQ;
|
||||
performer.getConnectionBlocks().add(
|
||||
new ModelConnectionBlock(new ModelSource(src),
|
||||
fvalue, new ModelDestination(dest)));
|
||||
}
|
||||
|
||||
if (getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_MODENVTOPITCH) != 0) {
|
||||
double fvalue = getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_MODENVTOPITCH);
|
||||
ModelIdentifier src = ModelSource.SOURCE_EG2;
|
||||
ModelIdentifier dest = ModelDestination.DESTINATION_PITCH;
|
||||
performer.getConnectionBlocks().add(
|
||||
new ModelConnectionBlock(new ModelSource(src),
|
||||
fvalue, new ModelDestination(dest)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_MODLFOTOFILTERFC) != 0
|
||||
|| getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_MODLFOTOPITCH) != 0
|
||||
|| getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_MODLFOTOVOLUME) != 0) {
|
||||
short lfo_freq = getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_FREQMODLFO);
|
||||
short lfo_delay = getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_DELAYMODLFO);
|
||||
addTimecentValue(performer,
|
||||
ModelDestination.DESTINATION_LFO1_DELAY, lfo_delay);
|
||||
addValue(performer,
|
||||
ModelDestination.DESTINATION_LFO1_FREQ, lfo_freq);
|
||||
}
|
||||
|
||||
short vib_freq = getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_FREQVIBLFO);
|
||||
short vib_delay = getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_DELAYVIBLFO);
|
||||
addTimecentValue(performer,
|
||||
ModelDestination.DESTINATION_LFO2_DELAY, vib_delay);
|
||||
addValue(performer,
|
||||
ModelDestination.DESTINATION_LFO2_FREQ, vib_freq);
|
||||
|
||||
|
||||
if (getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_VIBLFOTOPITCH) != 0) {
|
||||
double fvalue = getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_VIBLFOTOPITCH);
|
||||
ModelIdentifier src = ModelSource.SOURCE_LFO2;
|
||||
ModelIdentifier dest = ModelDestination.DESTINATION_PITCH;
|
||||
performer.getConnectionBlocks().add(
|
||||
new ModelConnectionBlock(
|
||||
new ModelSource(src,
|
||||
ModelStandardTransform.DIRECTION_MIN2MAX,
|
||||
ModelStandardTransform.POLARITY_BIPOLAR),
|
||||
fvalue, new ModelDestination(dest)));
|
||||
}
|
||||
|
||||
if (getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_MODLFOTOFILTERFC) != 0) {
|
||||
double fvalue = getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_MODLFOTOFILTERFC);
|
||||
ModelIdentifier src = ModelSource.SOURCE_LFO1;
|
||||
ModelIdentifier dest = ModelDestination.DESTINATION_FILTER_FREQ;
|
||||
performer.getConnectionBlocks().add(
|
||||
new ModelConnectionBlock(
|
||||
new ModelSource(src,
|
||||
ModelStandardTransform.DIRECTION_MIN2MAX,
|
||||
ModelStandardTransform.POLARITY_BIPOLAR),
|
||||
fvalue, new ModelDestination(dest)));
|
||||
}
|
||||
|
||||
if (getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_MODLFOTOPITCH) != 0) {
|
||||
double fvalue = getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_MODLFOTOPITCH);
|
||||
ModelIdentifier src = ModelSource.SOURCE_LFO1;
|
||||
ModelIdentifier dest = ModelDestination.DESTINATION_PITCH;
|
||||
performer.getConnectionBlocks().add(
|
||||
new ModelConnectionBlock(
|
||||
new ModelSource(src,
|
||||
ModelStandardTransform.DIRECTION_MIN2MAX,
|
||||
ModelStandardTransform.POLARITY_BIPOLAR),
|
||||
fvalue, new ModelDestination(dest)));
|
||||
}
|
||||
|
||||
if (getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_MODLFOTOVOLUME) != 0) {
|
||||
double fvalue = getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_MODLFOTOVOLUME);
|
||||
ModelIdentifier src = ModelSource.SOURCE_LFO1;
|
||||
ModelIdentifier dest = ModelDestination.DESTINATION_GAIN;
|
||||
performer.getConnectionBlocks().add(
|
||||
new ModelConnectionBlock(
|
||||
new ModelSource(src,
|
||||
ModelStandardTransform.DIRECTION_MIN2MAX,
|
||||
ModelStandardTransform.POLARITY_BIPOLAR),
|
||||
fvalue, new ModelDestination(dest)));
|
||||
}
|
||||
|
||||
if (layerzone.getShort(SF2Region.GENERATOR_KEYNUM) != -1) {
|
||||
double val = layerzone.getShort(SF2Region.GENERATOR_KEYNUM)/128.0;
|
||||
addValue(performer, ModelDestination.DESTINATION_KEYNUMBER, val);
|
||||
}
|
||||
|
||||
if (layerzone.getShort(SF2Region.GENERATOR_VELOCITY) != -1) {
|
||||
double val = layerzone.getShort(SF2Region.GENERATOR_VELOCITY)
|
||||
/ 128.0;
|
||||
addValue(performer, ModelDestination.DESTINATION_VELOCITY, val);
|
||||
}
|
||||
|
||||
if (getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_INITIALFILTERFC) < 13500) {
|
||||
short filter_freq = getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_INITIALFILTERFC);
|
||||
short filter_q = getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_INITIALFILTERQ);
|
||||
addValue(performer,
|
||||
ModelDestination.DESTINATION_FILTER_FREQ, filter_freq);
|
||||
addValue(performer,
|
||||
ModelDestination.DESTINATION_FILTER_Q, filter_q);
|
||||
}
|
||||
|
||||
int tune = 100 * getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_COARSETUNE);
|
||||
tune += getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_FINETUNE);
|
||||
if (tune != 0) {
|
||||
addValue(performer,
|
||||
ModelDestination.DESTINATION_PITCH, (short) tune);
|
||||
}
|
||||
if (getGeneratorValue(generators, SF2Region.GENERATOR_PAN) != 0) {
|
||||
short val = getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_PAN);
|
||||
addValue(performer, ModelDestination.DESTINATION_PAN, val);
|
||||
}
|
||||
if (getGeneratorValue(generators, SF2Region.GENERATOR_INITIALATTENUATION) != 0) {
|
||||
short val = getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_INITIALATTENUATION);
|
||||
addValue(performer,
|
||||
ModelDestination.DESTINATION_GAIN, -0.376287f * val);
|
||||
}
|
||||
if (getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_CHORUSEFFECTSSEND) != 0) {
|
||||
short val = getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_CHORUSEFFECTSSEND);
|
||||
addValue(performer, ModelDestination.DESTINATION_CHORUS, val);
|
||||
}
|
||||
if (getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_REVERBEFFECTSSEND) != 0) {
|
||||
short val = getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_REVERBEFFECTSSEND);
|
||||
addValue(performer, ModelDestination.DESTINATION_REVERB, val);
|
||||
}
|
||||
if (getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_SCALETUNING) != 100) {
|
||||
short fvalue = getGeneratorValue(generators,
|
||||
SF2Region.GENERATOR_SCALETUNING);
|
||||
if (fvalue == 0) {
|
||||
ModelIdentifier dest = ModelDestination.DESTINATION_PITCH;
|
||||
performer.getConnectionBlocks().add(
|
||||
new ModelConnectionBlock(null, rootkey * 100,
|
||||
new ModelDestination(dest)));
|
||||
} else {
|
||||
ModelIdentifier dest = ModelDestination.DESTINATION_PITCH;
|
||||
performer.getConnectionBlocks().add(
|
||||
new ModelConnectionBlock(null, rootkey * (100 - fvalue),
|
||||
new ModelDestination(dest)));
|
||||
}
|
||||
|
||||
ModelIdentifier src = ModelSource.SOURCE_NOTEON_KEYNUMBER;
|
||||
ModelIdentifier dest = ModelDestination.DESTINATION_PITCH;
|
||||
performer.getConnectionBlocks().add(
|
||||
new ModelConnectionBlock(new ModelSource(src),
|
||||
128 * fvalue, new ModelDestination(dest)));
|
||||
|
||||
}
|
||||
|
||||
performer.getConnectionBlocks().add(
|
||||
new ModelConnectionBlock(
|
||||
new ModelSource(ModelSource.SOURCE_NOTEON_VELOCITY,
|
||||
new ModelTransform() {
|
||||
public double transform(double value) {
|
||||
if (value < 0.5)
|
||||
return 1 - value * 2;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
}),
|
||||
-2400,
|
||||
new ModelDestination(
|
||||
ModelDestination.DESTINATION_FILTER_FREQ)));
|
||||
|
||||
|
||||
performer.getConnectionBlocks().add(
|
||||
new ModelConnectionBlock(
|
||||
new ModelSource(ModelSource.SOURCE_LFO2,
|
||||
ModelStandardTransform.DIRECTION_MIN2MAX,
|
||||
ModelStandardTransform.POLARITY_BIPOLAR,
|
||||
ModelStandardTransform.TRANSFORM_LINEAR),
|
||||
new ModelSource(new ModelIdentifier("midi_cc", "1", 0),
|
||||
ModelStandardTransform.DIRECTION_MIN2MAX,
|
||||
ModelStandardTransform.POLARITY_UNIPOLAR,
|
||||
ModelStandardTransform.TRANSFORM_LINEAR),
|
||||
50, new ModelDestination(
|
||||
ModelDestination.DESTINATION_PITCH)));
|
||||
|
||||
if (layer.getGlobalRegion() != null) {
|
||||
for (SF2Modulator modulator
|
||||
: layer.getGlobalRegion().getModulators()) {
|
||||
convertModulator(performer, modulator);
|
||||
}
|
||||
}
|
||||
for (SF2Modulator modulator : layerzone.getModulators())
|
||||
convertModulator(performer, modulator);
|
||||
|
||||
if (presetglobal != null) {
|
||||
for (SF2Modulator modulator : presetglobal.getModulators())
|
||||
convertModulator(performer, modulator);
|
||||
}
|
||||
for (SF2Modulator modulator : presetzone.getModulators())
|
||||
convertModulator(performer, modulator);
|
||||
|
||||
}
|
||||
}
|
||||
return performers;
|
||||
}
|
||||
|
||||
private void convertModulator(ModelPerformer performer,
|
||||
SF2Modulator modulator) {
|
||||
ModelSource src1 = convertSource(modulator.getSourceOperator());
|
||||
ModelSource src2 = convertSource(modulator.getAmountSourceOperator());
|
||||
if (src1 == null && modulator.getSourceOperator() != 0)
|
||||
return;
|
||||
if (src2 == null && modulator.getAmountSourceOperator() != 0)
|
||||
return;
|
||||
double amount = modulator.getAmount();
|
||||
double[] amountcorrection = new double[1];
|
||||
ModelSource[] extrasrc = new ModelSource[1];
|
||||
amountcorrection[0] = 1;
|
||||
ModelDestination dst = convertDestination(
|
||||
modulator.getDestinationOperator(), amountcorrection, extrasrc);
|
||||
amount *= amountcorrection[0];
|
||||
if (dst == null)
|
||||
return;
|
||||
if (modulator.getTransportOperator() == SF2Modulator.TRANSFORM_ABSOLUTE) {
|
||||
((ModelStandardTransform)dst.getTransform()).setTransform(
|
||||
ModelStandardTransform.TRANSFORM_ABSOLUTE);
|
||||
}
|
||||
ModelConnectionBlock conn = new ModelConnectionBlock(src1, src2, amount, dst);
|
||||
if (extrasrc[0] != null)
|
||||
conn.addSource(extrasrc[0]);
|
||||
performer.getConnectionBlocks().add(conn);
|
||||
|
||||
}
|
||||
|
||||
private static ModelSource convertSource(int src) {
|
||||
if (src == 0)
|
||||
return null;
|
||||
ModelIdentifier id = null;
|
||||
int idsrc = src & 0x7F;
|
||||
if ((src & SF2Modulator.SOURCE_MIDI_CONTROL) != 0) {
|
||||
id = new ModelIdentifier("midi_cc", Integer.toString(idsrc));
|
||||
} else {
|
||||
if (idsrc == SF2Modulator.SOURCE_NOTE_ON_VELOCITY)
|
||||
id = ModelSource.SOURCE_NOTEON_VELOCITY;
|
||||
if (idsrc == SF2Modulator.SOURCE_NOTE_ON_KEYNUMBER)
|
||||
id = ModelSource.SOURCE_NOTEON_KEYNUMBER;
|
||||
if (idsrc == SF2Modulator.SOURCE_POLY_PRESSURE)
|
||||
id = ModelSource.SOURCE_MIDI_POLY_PRESSURE;
|
||||
if (idsrc == SF2Modulator.SOURCE_CHANNEL_PRESSURE)
|
||||
id = ModelSource.SOURCE_MIDI_CHANNEL_PRESSURE;
|
||||
if (idsrc == SF2Modulator.SOURCE_PITCH_WHEEL)
|
||||
id = ModelSource.SOURCE_MIDI_PITCH;
|
||||
if (idsrc == SF2Modulator.SOURCE_PITCH_SENSITIVITY)
|
||||
id = new ModelIdentifier("midi_rpn", "0");
|
||||
}
|
||||
if (id == null)
|
||||
return null;
|
||||
|
||||
ModelSource msrc = new ModelSource(id);
|
||||
ModelStandardTransform transform
|
||||
= (ModelStandardTransform) msrc.getTransform();
|
||||
|
||||
if ((SF2Modulator.SOURCE_DIRECTION_MAX_MIN & src) != 0)
|
||||
transform.setDirection(ModelStandardTransform.DIRECTION_MAX2MIN);
|
||||
else
|
||||
transform.setDirection(ModelStandardTransform.DIRECTION_MIN2MAX);
|
||||
|
||||
if ((SF2Modulator.SOURCE_POLARITY_BIPOLAR & src) != 0)
|
||||
transform.setPolarity(ModelStandardTransform.POLARITY_BIPOLAR);
|
||||
else
|
||||
transform.setPolarity(ModelStandardTransform.POLARITY_UNIPOLAR);
|
||||
|
||||
if ((SF2Modulator.SOURCE_TYPE_CONCAVE & src) != 0)
|
||||
transform.setTransform(ModelStandardTransform.TRANSFORM_CONCAVE);
|
||||
if ((SF2Modulator.SOURCE_TYPE_CONVEX & src) != 0)
|
||||
transform.setTransform(ModelStandardTransform.TRANSFORM_CONVEX);
|
||||
if ((SF2Modulator.SOURCE_TYPE_SWITCH & src) != 0)
|
||||
transform.setTransform(ModelStandardTransform.TRANSFORM_SWITCH);
|
||||
|
||||
return msrc;
|
||||
}
|
||||
|
||||
static ModelDestination convertDestination(int dst,
|
||||
double[] amountcorrection, ModelSource[] extrasrc) {
|
||||
ModelIdentifier id = null;
|
||||
switch (dst) {
|
||||
case SF2Region.GENERATOR_INITIALFILTERFC:
|
||||
id = ModelDestination.DESTINATION_FILTER_FREQ;
|
||||
break;
|
||||
case SF2Region.GENERATOR_INITIALFILTERQ:
|
||||
id = ModelDestination.DESTINATION_FILTER_Q;
|
||||
break;
|
||||
case SF2Region.GENERATOR_CHORUSEFFECTSSEND:
|
||||
id = ModelDestination.DESTINATION_CHORUS;
|
||||
break;
|
||||
case SF2Region.GENERATOR_REVERBEFFECTSSEND:
|
||||
id = ModelDestination.DESTINATION_REVERB;
|
||||
break;
|
||||
case SF2Region.GENERATOR_PAN:
|
||||
id = ModelDestination.DESTINATION_PAN;
|
||||
break;
|
||||
case SF2Region.GENERATOR_DELAYMODLFO:
|
||||
id = ModelDestination.DESTINATION_LFO1_DELAY;
|
||||
break;
|
||||
case SF2Region.GENERATOR_FREQMODLFO:
|
||||
id = ModelDestination.DESTINATION_LFO1_FREQ;
|
||||
break;
|
||||
case SF2Region.GENERATOR_DELAYVIBLFO:
|
||||
id = ModelDestination.DESTINATION_LFO2_DELAY;
|
||||
break;
|
||||
case SF2Region.GENERATOR_FREQVIBLFO:
|
||||
id = ModelDestination.DESTINATION_LFO2_FREQ;
|
||||
break;
|
||||
|
||||
case SF2Region.GENERATOR_DELAYMODENV:
|
||||
id = ModelDestination.DESTINATION_EG2_DELAY;
|
||||
break;
|
||||
case SF2Region.GENERATOR_ATTACKMODENV:
|
||||
id = ModelDestination.DESTINATION_EG2_ATTACK;
|
||||
break;
|
||||
case SF2Region.GENERATOR_HOLDMODENV:
|
||||
id = ModelDestination.DESTINATION_EG2_HOLD;
|
||||
break;
|
||||
case SF2Region.GENERATOR_DECAYMODENV:
|
||||
id = ModelDestination.DESTINATION_EG2_DECAY;
|
||||
break;
|
||||
case SF2Region.GENERATOR_SUSTAINMODENV:
|
||||
id = ModelDestination.DESTINATION_EG2_SUSTAIN;
|
||||
amountcorrection[0] = -1;
|
||||
break;
|
||||
case SF2Region.GENERATOR_RELEASEMODENV:
|
||||
id = ModelDestination.DESTINATION_EG2_RELEASE;
|
||||
break;
|
||||
case SF2Region.GENERATOR_DELAYVOLENV:
|
||||
id = ModelDestination.DESTINATION_EG1_DELAY;
|
||||
break;
|
||||
case SF2Region.GENERATOR_ATTACKVOLENV:
|
||||
id = ModelDestination.DESTINATION_EG1_ATTACK;
|
||||
break;
|
||||
case SF2Region.GENERATOR_HOLDVOLENV:
|
||||
id = ModelDestination.DESTINATION_EG1_HOLD;
|
||||
break;
|
||||
case SF2Region.GENERATOR_DECAYVOLENV:
|
||||
id = ModelDestination.DESTINATION_EG1_DECAY;
|
||||
break;
|
||||
case SF2Region.GENERATOR_SUSTAINVOLENV:
|
||||
id = ModelDestination.DESTINATION_EG1_SUSTAIN;
|
||||
amountcorrection[0] = -1;
|
||||
break;
|
||||
case SF2Region.GENERATOR_RELEASEVOLENV:
|
||||
id = ModelDestination.DESTINATION_EG1_RELEASE;
|
||||
break;
|
||||
case SF2Region.GENERATOR_KEYNUM:
|
||||
id = ModelDestination.DESTINATION_KEYNUMBER;
|
||||
break;
|
||||
case SF2Region.GENERATOR_VELOCITY:
|
||||
id = ModelDestination.DESTINATION_VELOCITY;
|
||||
break;
|
||||
|
||||
case SF2Region.GENERATOR_COARSETUNE:
|
||||
amountcorrection[0] = 100;
|
||||
id = ModelDestination.DESTINATION_PITCH;
|
||||
break;
|
||||
|
||||
case SF2Region.GENERATOR_FINETUNE:
|
||||
id = ModelDestination.DESTINATION_PITCH;
|
||||
break;
|
||||
|
||||
case SF2Region.GENERATOR_INITIALATTENUATION:
|
||||
id = ModelDestination.DESTINATION_GAIN;
|
||||
amountcorrection[0] = -0.376287f;
|
||||
break;
|
||||
|
||||
case SF2Region.GENERATOR_VIBLFOTOPITCH:
|
||||
id = ModelDestination.DESTINATION_PITCH;
|
||||
extrasrc[0] = new ModelSource(
|
||||
ModelSource.SOURCE_LFO2,
|
||||
ModelStandardTransform.DIRECTION_MIN2MAX,
|
||||
ModelStandardTransform.POLARITY_BIPOLAR);
|
||||
break;
|
||||
|
||||
case SF2Region.GENERATOR_MODLFOTOPITCH:
|
||||
id = ModelDestination.DESTINATION_PITCH;
|
||||
extrasrc[0] = new ModelSource(
|
||||
ModelSource.SOURCE_LFO1,
|
||||
ModelStandardTransform.DIRECTION_MIN2MAX,
|
||||
ModelStandardTransform.POLARITY_BIPOLAR);
|
||||
break;
|
||||
|
||||
case SF2Region.GENERATOR_MODLFOTOFILTERFC:
|
||||
id = ModelDestination.DESTINATION_FILTER_FREQ;
|
||||
extrasrc[0] = new ModelSource(
|
||||
ModelSource.SOURCE_LFO1,
|
||||
ModelStandardTransform.DIRECTION_MIN2MAX,
|
||||
ModelStandardTransform.POLARITY_BIPOLAR);
|
||||
break;
|
||||
|
||||
case SF2Region.GENERATOR_MODLFOTOVOLUME:
|
||||
id = ModelDestination.DESTINATION_GAIN;
|
||||
amountcorrection[0] = -0.376287f;
|
||||
extrasrc[0] = new ModelSource(
|
||||
ModelSource.SOURCE_LFO1,
|
||||
ModelStandardTransform.DIRECTION_MIN2MAX,
|
||||
ModelStandardTransform.POLARITY_BIPOLAR);
|
||||
break;
|
||||
|
||||
case SF2Region.GENERATOR_MODENVTOPITCH:
|
||||
id = ModelDestination.DESTINATION_PITCH;
|
||||
extrasrc[0] = new ModelSource(
|
||||
ModelSource.SOURCE_EG2,
|
||||
ModelStandardTransform.DIRECTION_MIN2MAX,
|
||||
ModelStandardTransform.POLARITY_BIPOLAR);
|
||||
break;
|
||||
|
||||
case SF2Region.GENERATOR_MODENVTOFILTERFC:
|
||||
id = ModelDestination.DESTINATION_FILTER_FREQ;
|
||||
extrasrc[0] = new ModelSource(
|
||||
ModelSource.SOURCE_EG2,
|
||||
ModelStandardTransform.DIRECTION_MIN2MAX,
|
||||
ModelStandardTransform.POLARITY_BIPOLAR);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (id != null)
|
||||
return new ModelDestination(id);
|
||||
return null;
|
||||
}
|
||||
|
||||
private void addTimecentValue(ModelPerformer performer,
|
||||
ModelIdentifier dest, short value) {
|
||||
double fvalue;
|
||||
if (value == -12000)
|
||||
fvalue = Double.NEGATIVE_INFINITY;
|
||||
else
|
||||
fvalue = value;
|
||||
performer.getConnectionBlocks().add(
|
||||
new ModelConnectionBlock(fvalue, new ModelDestination(dest)));
|
||||
}
|
||||
|
||||
private void addValue(ModelPerformer performer,
|
||||
ModelIdentifier dest, short value) {
|
||||
double fvalue = value;
|
||||
performer.getConnectionBlocks().add(
|
||||
new ModelConnectionBlock(fvalue, new ModelDestination(dest)));
|
||||
}
|
||||
|
||||
private void addValue(ModelPerformer performer,
|
||||
ModelIdentifier dest, double value) {
|
||||
double fvalue = value;
|
||||
performer.getConnectionBlocks().add(
|
||||
new ModelConnectionBlock(fvalue, new ModelDestination(dest)));
|
||||
}
|
||||
|
||||
private short getGeneratorValue(Map<Integer, Short> generators, int gen) {
|
||||
if (generators.containsKey(gen))
|
||||
return generators.get(gen);
|
||||
return SF2Region.getDefaultValue(gen);
|
||||
}
|
||||
}
|
||||
43
jdkSrc/jdk8/com/sun/media/sound/SF2InstrumentRegion.java
Normal file
43
jdkSrc/jdk8/com/sun/media/sound/SF2InstrumentRegion.java
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
/**
|
||||
* Soundfont instrument region.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public final class SF2InstrumentRegion extends SF2Region {
|
||||
|
||||
SF2Layer layer;
|
||||
|
||||
public SF2Layer getLayer() {
|
||||
return layer;
|
||||
}
|
||||
|
||||
public void setLayer(SF2Layer layer) {
|
||||
this.layer = layer;
|
||||
}
|
||||
}
|
||||
78
jdkSrc/jdk8/com/sun/media/sound/SF2Layer.java
Normal file
78
jdkSrc/jdk8/com/sun/media/sound/SF2Layer.java
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.sound.midi.SoundbankResource;
|
||||
|
||||
/**
|
||||
* Soundfont layer.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public final class SF2Layer extends SoundbankResource {
|
||||
|
||||
String name = "";
|
||||
SF2GlobalRegion globalregion = null;
|
||||
List<SF2LayerRegion> regions = new ArrayList<SF2LayerRegion>();
|
||||
|
||||
public SF2Layer(SF2Soundbank soundBank) {
|
||||
super(soundBank, null, null);
|
||||
}
|
||||
|
||||
public SF2Layer() {
|
||||
super(null, null, null);
|
||||
}
|
||||
|
||||
public Object getData() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public List<SF2LayerRegion> getRegions() {
|
||||
return regions;
|
||||
}
|
||||
|
||||
public SF2GlobalRegion getGlobalRegion() {
|
||||
return globalregion;
|
||||
}
|
||||
|
||||
public void setGlobalZone(SF2GlobalRegion zone) {
|
||||
globalregion = zone;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "Layer: " + name;
|
||||
}
|
||||
}
|
||||
43
jdkSrc/jdk8/com/sun/media/sound/SF2LayerRegion.java
Normal file
43
jdkSrc/jdk8/com/sun/media/sound/SF2LayerRegion.java
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
/**
|
||||
* Soundfont layer region.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public final class SF2LayerRegion extends SF2Region {
|
||||
|
||||
SF2Sample sample;
|
||||
|
||||
public SF2Sample getSample() {
|
||||
return sample;
|
||||
}
|
||||
|
||||
public void setSample(SF2Sample sample) {
|
||||
this.sample = sample;
|
||||
}
|
||||
}
|
||||
97
jdkSrc/jdk8/com/sun/media/sound/SF2Modulator.java
Normal file
97
jdkSrc/jdk8/com/sun/media/sound/SF2Modulator.java
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
/**
|
||||
* Soundfont modulator container.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public final class SF2Modulator {
|
||||
|
||||
public final static int SOURCE_NONE = 0;
|
||||
public final static int SOURCE_NOTE_ON_VELOCITY = 2;
|
||||
public final static int SOURCE_NOTE_ON_KEYNUMBER = 3;
|
||||
public final static int SOURCE_POLY_PRESSURE = 10;
|
||||
public final static int SOURCE_CHANNEL_PRESSURE = 13;
|
||||
public final static int SOURCE_PITCH_WHEEL = 14;
|
||||
public final static int SOURCE_PITCH_SENSITIVITY = 16;
|
||||
public final static int SOURCE_MIDI_CONTROL = 128 * 1;
|
||||
public final static int SOURCE_DIRECTION_MIN_MAX = 256 * 0;
|
||||
public final static int SOURCE_DIRECTION_MAX_MIN = 256 * 1;
|
||||
public final static int SOURCE_POLARITY_UNIPOLAR = 512 * 0;
|
||||
public final static int SOURCE_POLARITY_BIPOLAR = 512 * 1;
|
||||
public final static int SOURCE_TYPE_LINEAR = 1024 * 0;
|
||||
public final static int SOURCE_TYPE_CONCAVE = 1024 * 1;
|
||||
public final static int SOURCE_TYPE_CONVEX = 1024 * 2;
|
||||
public final static int SOURCE_TYPE_SWITCH = 1024 * 3;
|
||||
public final static int TRANSFORM_LINEAR = 0;
|
||||
public final static int TRANSFORM_ABSOLUTE = 2;
|
||||
int sourceOperator;
|
||||
int destinationOperator;
|
||||
short amount;
|
||||
int amountSourceOperator;
|
||||
int transportOperator;
|
||||
|
||||
public short getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public void setAmount(short amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public int getAmountSourceOperator() {
|
||||
return amountSourceOperator;
|
||||
}
|
||||
|
||||
public void setAmountSourceOperator(int amountSourceOperator) {
|
||||
this.amountSourceOperator = amountSourceOperator;
|
||||
}
|
||||
|
||||
public int getTransportOperator() {
|
||||
return transportOperator;
|
||||
}
|
||||
|
||||
public void setTransportOperator(int transportOperator) {
|
||||
this.transportOperator = transportOperator;
|
||||
}
|
||||
|
||||
public int getDestinationOperator() {
|
||||
return destinationOperator;
|
||||
}
|
||||
|
||||
public void setDestinationOperator(int destinationOperator) {
|
||||
this.destinationOperator = destinationOperator;
|
||||
}
|
||||
|
||||
public int getSourceOperator() {
|
||||
return sourceOperator;
|
||||
}
|
||||
|
||||
public void setSourceOperator(int sourceOperator) {
|
||||
this.sourceOperator = sourceOperator;
|
||||
}
|
||||
}
|
||||
167
jdkSrc/jdk8/com/sun/media/sound/SF2Region.java
Normal file
167
jdkSrc/jdk8/com/sun/media/sound/SF2Region.java
Normal file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Soundfont general region.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public class SF2Region {
|
||||
|
||||
public final static int GENERATOR_STARTADDRSOFFSET = 0;
|
||||
public final static int GENERATOR_ENDADDRSOFFSET = 1;
|
||||
public final static int GENERATOR_STARTLOOPADDRSOFFSET = 2;
|
||||
public final static int GENERATOR_ENDLOOPADDRSOFFSET = 3;
|
||||
public final static int GENERATOR_STARTADDRSCOARSEOFFSET = 4;
|
||||
public final static int GENERATOR_MODLFOTOPITCH = 5;
|
||||
public final static int GENERATOR_VIBLFOTOPITCH = 6;
|
||||
public final static int GENERATOR_MODENVTOPITCH = 7;
|
||||
public final static int GENERATOR_INITIALFILTERFC = 8;
|
||||
public final static int GENERATOR_INITIALFILTERQ = 9;
|
||||
public final static int GENERATOR_MODLFOTOFILTERFC = 10;
|
||||
public final static int GENERATOR_MODENVTOFILTERFC = 11;
|
||||
public final static int GENERATOR_ENDADDRSCOARSEOFFSET = 12;
|
||||
public final static int GENERATOR_MODLFOTOVOLUME = 13;
|
||||
public final static int GENERATOR_UNUSED1 = 14;
|
||||
public final static int GENERATOR_CHORUSEFFECTSSEND = 15;
|
||||
public final static int GENERATOR_REVERBEFFECTSSEND = 16;
|
||||
public final static int GENERATOR_PAN = 17;
|
||||
public final static int GENERATOR_UNUSED2 = 18;
|
||||
public final static int GENERATOR_UNUSED3 = 19;
|
||||
public final static int GENERATOR_UNUSED4 = 20;
|
||||
public final static int GENERATOR_DELAYMODLFO = 21;
|
||||
public final static int GENERATOR_FREQMODLFO = 22;
|
||||
public final static int GENERATOR_DELAYVIBLFO = 23;
|
||||
public final static int GENERATOR_FREQVIBLFO = 24;
|
||||
public final static int GENERATOR_DELAYMODENV = 25;
|
||||
public final static int GENERATOR_ATTACKMODENV = 26;
|
||||
public final static int GENERATOR_HOLDMODENV = 27;
|
||||
public final static int GENERATOR_DECAYMODENV = 28;
|
||||
public final static int GENERATOR_SUSTAINMODENV = 29;
|
||||
public final static int GENERATOR_RELEASEMODENV = 30;
|
||||
public final static int GENERATOR_KEYNUMTOMODENVHOLD = 31;
|
||||
public final static int GENERATOR_KEYNUMTOMODENVDECAY = 32;
|
||||
public final static int GENERATOR_DELAYVOLENV = 33;
|
||||
public final static int GENERATOR_ATTACKVOLENV = 34;
|
||||
public final static int GENERATOR_HOLDVOLENV = 35;
|
||||
public final static int GENERATOR_DECAYVOLENV = 36;
|
||||
public final static int GENERATOR_SUSTAINVOLENV = 37;
|
||||
public final static int GENERATOR_RELEASEVOLENV = 38;
|
||||
public final static int GENERATOR_KEYNUMTOVOLENVHOLD = 39;
|
||||
public final static int GENERATOR_KEYNUMTOVOLENVDECAY = 40;
|
||||
public final static int GENERATOR_INSTRUMENT = 41;
|
||||
public final static int GENERATOR_RESERVED1 = 42;
|
||||
public final static int GENERATOR_KEYRANGE = 43;
|
||||
public final static int GENERATOR_VELRANGE = 44;
|
||||
public final static int GENERATOR_STARTLOOPADDRSCOARSEOFFSET = 45;
|
||||
public final static int GENERATOR_KEYNUM = 46;
|
||||
public final static int GENERATOR_VELOCITY = 47;
|
||||
public final static int GENERATOR_INITIALATTENUATION = 48;
|
||||
public final static int GENERATOR_RESERVED2 = 49;
|
||||
public final static int GENERATOR_ENDLOOPADDRSCOARSEOFFSET = 50;
|
||||
public final static int GENERATOR_COARSETUNE = 51;
|
||||
public final static int GENERATOR_FINETUNE = 52;
|
||||
public final static int GENERATOR_SAMPLEID = 53;
|
||||
public final static int GENERATOR_SAMPLEMODES = 54;
|
||||
public final static int GENERATOR_RESERVED3 = 55;
|
||||
public final static int GENERATOR_SCALETUNING = 56;
|
||||
public final static int GENERATOR_EXCLUSIVECLASS = 57;
|
||||
public final static int GENERATOR_OVERRIDINGROOTKEY = 58;
|
||||
public final static int GENERATOR_UNUSED5 = 59;
|
||||
public final static int GENERATOR_ENDOPR = 60;
|
||||
protected Map<Integer, Short> generators = new HashMap<Integer, Short>();
|
||||
protected List<SF2Modulator> modulators = new ArrayList<SF2Modulator>();
|
||||
|
||||
public Map<Integer, Short> getGenerators() {
|
||||
return generators;
|
||||
}
|
||||
|
||||
public boolean contains(int generator) {
|
||||
return generators.containsKey(generator);
|
||||
}
|
||||
|
||||
static public short getDefaultValue(int generator) {
|
||||
if (generator == 8) return (short)13500;
|
||||
if (generator == 21) return (short)-12000;
|
||||
if (generator == 23) return (short)-12000;
|
||||
if (generator == 25) return (short)-12000;
|
||||
if (generator == 26) return (short)-12000;
|
||||
if (generator == 27) return (short)-12000;
|
||||
if (generator == 28) return (short)-12000;
|
||||
if (generator == 30) return (short)-12000;
|
||||
if (generator == 33) return (short)-12000;
|
||||
if (generator == 34) return (short)-12000;
|
||||
if (generator == 35) return (short)-12000;
|
||||
if (generator == 36) return (short)-12000;
|
||||
if (generator == 38) return (short)-12000;
|
||||
if (generator == 43) return (short)0x7F00;
|
||||
if (generator == 44) return (short)0x7F00;
|
||||
if (generator == 46) return (short)-1;
|
||||
if (generator == 47) return (short)-1;
|
||||
if (generator == 56) return (short)100;
|
||||
if (generator == 58) return (short)-1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
public short getShort(int generator) {
|
||||
if (!contains(generator))
|
||||
return getDefaultValue(generator);
|
||||
return generators.get(generator);
|
||||
}
|
||||
|
||||
public void putShort(int generator, short value) {
|
||||
generators.put(generator, value);
|
||||
}
|
||||
|
||||
public byte[] getBytes(int generator) {
|
||||
int val = getInteger(generator);
|
||||
byte[] bytes = new byte[2];
|
||||
bytes[0] = (byte) (0xFF & val);
|
||||
bytes[1] = (byte) ((0xFF00 & val) >> 8);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public void putBytes(int generator, byte[] bytes) {
|
||||
generators.put(generator, (short) (bytes[0] + (bytes[1] << 8)));
|
||||
}
|
||||
|
||||
public int getInteger(int generator) {
|
||||
return 0xFFFF & getShort(generator);
|
||||
}
|
||||
|
||||
public void putInteger(int generator, int value) {
|
||||
generators.put(generator, (short) value);
|
||||
}
|
||||
|
||||
public List<SF2Modulator> getModulators() {
|
||||
return modulators;
|
||||
}
|
||||
}
|
||||
216
jdkSrc/jdk8/com/sun/media/sound/SF2Sample.java
Normal file
216
jdkSrc/jdk8/com/sun/media/sound/SF2Sample.java
Normal file
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import javax.sound.midi.Soundbank;
|
||||
import javax.sound.midi.SoundbankResource;
|
||||
import javax.sound.sampled.AudioFormat;
|
||||
import javax.sound.sampled.AudioInputStream;
|
||||
|
||||
/**
|
||||
* Soundfont sample storage.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public final class SF2Sample extends SoundbankResource {
|
||||
|
||||
String name = "";
|
||||
long startLoop = 0;
|
||||
long endLoop = 0;
|
||||
long sampleRate = 44100;
|
||||
int originalPitch = 60;
|
||||
byte pitchCorrection = 0;
|
||||
int sampleLink = 0;
|
||||
int sampleType = 0;
|
||||
ModelByteBuffer data;
|
||||
ModelByteBuffer data24;
|
||||
|
||||
public SF2Sample(Soundbank soundBank) {
|
||||
super(soundBank, null, AudioInputStream.class);
|
||||
}
|
||||
|
||||
public SF2Sample() {
|
||||
super(null, null, AudioInputStream.class);
|
||||
}
|
||||
|
||||
public Object getData() {
|
||||
|
||||
AudioFormat format = getFormat();
|
||||
/*
|
||||
if (sampleFile != null) {
|
||||
FileInputStream fis;
|
||||
try {
|
||||
fis = new FileInputStream(sampleFile);
|
||||
RIFFReader riff = new RIFFReader(fis);
|
||||
if (!riff.getFormat().equals("RIFF")) {
|
||||
throw new RIFFInvalidDataException(
|
||||
"Input stream is not a valid RIFF stream!");
|
||||
}
|
||||
if (!riff.getType().equals("sfbk")) {
|
||||
throw new RIFFInvalidDataException(
|
||||
"Input stream is not a valid SoundFont!");
|
||||
}
|
||||
while (riff.hasNextChunk()) {
|
||||
RIFFReader chunk = riff.nextChunk();
|
||||
if (chunk.getFormat().equals("LIST")) {
|
||||
if (chunk.getType().equals("sdta")) {
|
||||
while(chunk.hasNextChunk()) {
|
||||
RIFFReader chunkchunk = chunk.nextChunk();
|
||||
if(chunkchunk.getFormat().equals("smpl")) {
|
||||
chunkchunk.skip(sampleOffset);
|
||||
return new AudioInputStream(chunkchunk,
|
||||
format, sampleLen);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
return new Throwable(e.toString());
|
||||
}
|
||||
}
|
||||
*/
|
||||
InputStream is = data.getInputStream();
|
||||
if (is == null)
|
||||
return null;
|
||||
return new AudioInputStream(is, format, data.capacity());
|
||||
}
|
||||
|
||||
public ModelByteBuffer getDataBuffer() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public ModelByteBuffer getData24Buffer() {
|
||||
return data24;
|
||||
}
|
||||
|
||||
public AudioFormat getFormat() {
|
||||
return new AudioFormat(sampleRate, 16, 1, true, false);
|
||||
}
|
||||
|
||||
public void setData(ModelByteBuffer data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public void setData(byte[] data) {
|
||||
this.data = new ModelByteBuffer(data);
|
||||
}
|
||||
|
||||
public void setData(byte[] data, int offset, int length) {
|
||||
this.data = new ModelByteBuffer(data, offset, length);
|
||||
}
|
||||
|
||||
public void setData24(ModelByteBuffer data24) {
|
||||
this.data24 = data24;
|
||||
}
|
||||
|
||||
public void setData24(byte[] data24) {
|
||||
this.data24 = new ModelByteBuffer(data24);
|
||||
}
|
||||
|
||||
public void setData24(byte[] data24, int offset, int length) {
|
||||
this.data24 = new ModelByteBuffer(data24, offset, length);
|
||||
}
|
||||
|
||||
/*
|
||||
public void setData(File file, int offset, int length) {
|
||||
this.data = null;
|
||||
this.sampleFile = file;
|
||||
this.sampleOffset = offset;
|
||||
this.sampleLen = length;
|
||||
}
|
||||
*/
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public long getEndLoop() {
|
||||
return endLoop;
|
||||
}
|
||||
|
||||
public void setEndLoop(long endLoop) {
|
||||
this.endLoop = endLoop;
|
||||
}
|
||||
|
||||
public int getOriginalPitch() {
|
||||
return originalPitch;
|
||||
}
|
||||
|
||||
public void setOriginalPitch(int originalPitch) {
|
||||
this.originalPitch = originalPitch;
|
||||
}
|
||||
|
||||
public byte getPitchCorrection() {
|
||||
return pitchCorrection;
|
||||
}
|
||||
|
||||
public void setPitchCorrection(byte pitchCorrection) {
|
||||
this.pitchCorrection = pitchCorrection;
|
||||
}
|
||||
|
||||
public int getSampleLink() {
|
||||
return sampleLink;
|
||||
}
|
||||
|
||||
public void setSampleLink(int sampleLink) {
|
||||
this.sampleLink = sampleLink;
|
||||
}
|
||||
|
||||
public long getSampleRate() {
|
||||
return sampleRate;
|
||||
}
|
||||
|
||||
public void setSampleRate(long sampleRate) {
|
||||
this.sampleRate = sampleRate;
|
||||
}
|
||||
|
||||
public int getSampleType() {
|
||||
return sampleType;
|
||||
}
|
||||
|
||||
public void setSampleType(int sampleType) {
|
||||
this.sampleType = sampleType;
|
||||
}
|
||||
|
||||
public long getStartLoop() {
|
||||
return startLoop;
|
||||
}
|
||||
|
||||
public void setStartLoop(long startLoop) {
|
||||
this.startLoop = startLoop;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "Sample: " + name;
|
||||
}
|
||||
}
|
||||
989
jdkSrc/jdk8/com/sun/media/sound/SF2Soundbank.java
Normal file
989
jdkSrc/jdk8/com/sun/media/sound/SF2Soundbank.java
Normal file
@@ -0,0 +1,989 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.sound.midi.Instrument;
|
||||
import javax.sound.midi.Patch;
|
||||
import javax.sound.midi.Soundbank;
|
||||
import javax.sound.midi.SoundbankResource;
|
||||
|
||||
/**
|
||||
* A SoundFont 2.04 soundbank reader.
|
||||
*
|
||||
* Based on SoundFont 2.04 specification from:
|
||||
* <p> http://developer.creative.com <br>
|
||||
* http://www.soundfont.com/ ;
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public final class SF2Soundbank implements Soundbank {
|
||||
|
||||
// version of the Sound Font RIFF file
|
||||
int major = 2;
|
||||
int minor = 1;
|
||||
// target Sound Engine
|
||||
String targetEngine = "EMU8000";
|
||||
// Sound Font Bank Name
|
||||
String name = "untitled";
|
||||
// Sound ROM Name
|
||||
String romName = null;
|
||||
// Sound ROM Version
|
||||
int romVersionMajor = -1;
|
||||
int romVersionMinor = -1;
|
||||
// Date of Creation of the Bank
|
||||
String creationDate = null;
|
||||
// Sound Designers and Engineers for the Bank
|
||||
String engineers = null;
|
||||
// Product for which the Bank was intended
|
||||
String product = null;
|
||||
// Copyright message
|
||||
String copyright = null;
|
||||
// Comments
|
||||
String comments = null;
|
||||
// The SoundFont tools used to create and alter the bank
|
||||
String tools = null;
|
||||
// The Sample Data loaded from the SoundFont
|
||||
private ModelByteBuffer sampleData = null;
|
||||
private ModelByteBuffer sampleData24 = null;
|
||||
private File sampleFile = null;
|
||||
private boolean largeFormat = false;
|
||||
private final List<SF2Instrument> instruments = new ArrayList<SF2Instrument>();
|
||||
private final List<SF2Layer> layers = new ArrayList<SF2Layer>();
|
||||
private final List<SF2Sample> samples = new ArrayList<SF2Sample>();
|
||||
|
||||
public SF2Soundbank() {
|
||||
}
|
||||
|
||||
public SF2Soundbank(URL url) throws IOException {
|
||||
|
||||
InputStream is = url.openStream();
|
||||
try {
|
||||
readSoundbank(is);
|
||||
} finally {
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
|
||||
public SF2Soundbank(File file) throws IOException {
|
||||
largeFormat = true;
|
||||
sampleFile = file;
|
||||
InputStream is = new FileInputStream(file);
|
||||
try {
|
||||
readSoundbank(is);
|
||||
} finally {
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
|
||||
public SF2Soundbank(InputStream inputstream) throws IOException {
|
||||
readSoundbank(inputstream);
|
||||
}
|
||||
|
||||
private void readSoundbank(InputStream inputstream) throws IOException {
|
||||
RIFFReader riff = new RIFFReader(inputstream);
|
||||
if (!riff.getFormat().equals("RIFF")) {
|
||||
throw new RIFFInvalidFormatException(
|
||||
"Input stream is not a valid RIFF stream!");
|
||||
}
|
||||
if (!riff.getType().equals("sfbk")) {
|
||||
throw new RIFFInvalidFormatException(
|
||||
"Input stream is not a valid SoundFont!");
|
||||
}
|
||||
while (riff.hasNextChunk()) {
|
||||
RIFFReader chunk = riff.nextChunk();
|
||||
if (chunk.getFormat().equals("LIST")) {
|
||||
if (chunk.getType().equals("INFO"))
|
||||
readInfoChunk(chunk);
|
||||
if (chunk.getType().equals("sdta"))
|
||||
readSdtaChunk(chunk);
|
||||
if (chunk.getType().equals("pdta"))
|
||||
readPdtaChunk(chunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void readInfoChunk(RIFFReader riff) throws IOException {
|
||||
while (riff.hasNextChunk()) {
|
||||
RIFFReader chunk = riff.nextChunk();
|
||||
String format = chunk.getFormat();
|
||||
if (format.equals("ifil")) {
|
||||
major = chunk.readUnsignedShort();
|
||||
minor = chunk.readUnsignedShort();
|
||||
} else if (format.equals("isng")) {
|
||||
this.targetEngine = chunk.readString(chunk.available());
|
||||
} else if (format.equals("INAM")) {
|
||||
this.name = chunk.readString(chunk.available());
|
||||
} else if (format.equals("irom")) {
|
||||
this.romName = chunk.readString(chunk.available());
|
||||
} else if (format.equals("iver")) {
|
||||
romVersionMajor = chunk.readUnsignedShort();
|
||||
romVersionMinor = chunk.readUnsignedShort();
|
||||
} else if (format.equals("ICRD")) {
|
||||
this.creationDate = chunk.readString(chunk.available());
|
||||
} else if (format.equals("IENG")) {
|
||||
this.engineers = chunk.readString(chunk.available());
|
||||
} else if (format.equals("IPRD")) {
|
||||
this.product = chunk.readString(chunk.available());
|
||||
} else if (format.equals("ICOP")) {
|
||||
this.copyright = chunk.readString(chunk.available());
|
||||
} else if (format.equals("ICMT")) {
|
||||
this.comments = chunk.readString(chunk.available());
|
||||
} else if (format.equals("ISFT")) {
|
||||
this.tools = chunk.readString(chunk.available());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void readSdtaChunk(RIFFReader riff) throws IOException {
|
||||
while (riff.hasNextChunk()) {
|
||||
RIFFReader chunk = riff.nextChunk();
|
||||
if (chunk.getFormat().equals("smpl")) {
|
||||
if (!largeFormat) {
|
||||
byte[] sampleData = new byte[chunk.available()];
|
||||
|
||||
int read = 0;
|
||||
int avail = chunk.available();
|
||||
while (read != avail) {
|
||||
if (avail - read > 65536) {
|
||||
chunk.readFully(sampleData, read, 65536);
|
||||
read += 65536;
|
||||
} else {
|
||||
chunk.readFully(sampleData, read, avail - read);
|
||||
read = avail;
|
||||
}
|
||||
|
||||
}
|
||||
this.sampleData = new ModelByteBuffer(sampleData);
|
||||
//chunk.read(sampleData);
|
||||
} else {
|
||||
this.sampleData = new ModelByteBuffer(sampleFile,
|
||||
chunk.getFilePointer(), chunk.available());
|
||||
}
|
||||
}
|
||||
if (chunk.getFormat().equals("sm24")) {
|
||||
if (!largeFormat) {
|
||||
byte[] sampleData24 = new byte[chunk.available()];
|
||||
//chunk.read(sampleData24);
|
||||
|
||||
int read = 0;
|
||||
int avail = chunk.available();
|
||||
while (read != avail) {
|
||||
if (avail - read > 65536) {
|
||||
chunk.readFully(sampleData24, read, 65536);
|
||||
read += 65536;
|
||||
} else {
|
||||
chunk.readFully(sampleData24, read, avail - read);
|
||||
read = avail;
|
||||
}
|
||||
|
||||
}
|
||||
this.sampleData24 = new ModelByteBuffer(sampleData24);
|
||||
} else {
|
||||
this.sampleData24 = new ModelByteBuffer(sampleFile,
|
||||
chunk.getFilePointer(), chunk.available());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void readPdtaChunk(RIFFReader riff) throws IOException {
|
||||
|
||||
List<SF2Instrument> presets = new ArrayList<SF2Instrument>();
|
||||
List<Integer> presets_bagNdx = new ArrayList<Integer>();
|
||||
List<SF2InstrumentRegion> presets_splits_gen
|
||||
= new ArrayList<SF2InstrumentRegion>();
|
||||
List<SF2InstrumentRegion> presets_splits_mod
|
||||
= new ArrayList<SF2InstrumentRegion>();
|
||||
|
||||
List<SF2Layer> instruments = new ArrayList<SF2Layer>();
|
||||
List<Integer> instruments_bagNdx = new ArrayList<Integer>();
|
||||
List<SF2LayerRegion> instruments_splits_gen
|
||||
= new ArrayList<SF2LayerRegion>();
|
||||
List<SF2LayerRegion> instruments_splits_mod
|
||||
= new ArrayList<SF2LayerRegion>();
|
||||
|
||||
while (riff.hasNextChunk()) {
|
||||
RIFFReader chunk = riff.nextChunk();
|
||||
String format = chunk.getFormat();
|
||||
if (format.equals("phdr")) {
|
||||
// Preset Header / Instrument
|
||||
if (chunk.available() % 38 != 0)
|
||||
throw new RIFFInvalidDataException();
|
||||
int count = chunk.available() / 38;
|
||||
for (int i = 0; i < count; i++) {
|
||||
SF2Instrument preset = new SF2Instrument(this);
|
||||
preset.name = chunk.readString(20);
|
||||
preset.preset = chunk.readUnsignedShort();
|
||||
preset.bank = chunk.readUnsignedShort();
|
||||
presets_bagNdx.add(chunk.readUnsignedShort());
|
||||
preset.library = chunk.readUnsignedInt();
|
||||
preset.genre = chunk.readUnsignedInt();
|
||||
preset.morphology = chunk.readUnsignedInt();
|
||||
presets.add(preset);
|
||||
if (i != count - 1)
|
||||
this.instruments.add(preset);
|
||||
}
|
||||
} else if (format.equals("pbag")) {
|
||||
// Preset Zones / Instruments splits
|
||||
if (chunk.available() % 4 != 0)
|
||||
throw new RIFFInvalidDataException();
|
||||
int count = chunk.available() / 4;
|
||||
|
||||
// Skip first record
|
||||
{
|
||||
int gencount = chunk.readUnsignedShort();
|
||||
int modcount = chunk.readUnsignedShort();
|
||||
while (presets_splits_gen.size() < gencount)
|
||||
presets_splits_gen.add(null);
|
||||
while (presets_splits_mod.size() < modcount)
|
||||
presets_splits_mod.add(null);
|
||||
count--;
|
||||
}
|
||||
|
||||
if (presets_bagNdx.isEmpty()) {
|
||||
throw new RIFFInvalidDataException();
|
||||
}
|
||||
int offset = presets_bagNdx.get(0);
|
||||
// Offset should be 0 (but just case)
|
||||
for (int i = 0; i < offset; i++) {
|
||||
if (count == 0)
|
||||
throw new RIFFInvalidDataException();
|
||||
int gencount = chunk.readUnsignedShort();
|
||||
int modcount = chunk.readUnsignedShort();
|
||||
while (presets_splits_gen.size() < gencount)
|
||||
presets_splits_gen.add(null);
|
||||
while (presets_splits_mod.size() < modcount)
|
||||
presets_splits_mod.add(null);
|
||||
count--;
|
||||
}
|
||||
|
||||
for (int i = 0; i < presets_bagNdx.size() - 1; i++) {
|
||||
int zone_count = presets_bagNdx.get(i + 1)
|
||||
- presets_bagNdx.get(i);
|
||||
SF2Instrument preset = presets.get(i);
|
||||
for (int ii = 0; ii < zone_count; ii++) {
|
||||
if (count == 0)
|
||||
throw new RIFFInvalidDataException();
|
||||
int gencount = chunk.readUnsignedShort();
|
||||
int modcount = chunk.readUnsignedShort();
|
||||
SF2InstrumentRegion split = new SF2InstrumentRegion();
|
||||
preset.regions.add(split);
|
||||
while (presets_splits_gen.size() < gencount)
|
||||
presets_splits_gen.add(split);
|
||||
while (presets_splits_mod.size() < modcount)
|
||||
presets_splits_mod.add(split);
|
||||
count--;
|
||||
}
|
||||
}
|
||||
} else if (format.equals("pmod")) {
|
||||
// Preset Modulators / Split Modulators
|
||||
for (int i = 0; i < presets_splits_mod.size(); i++) {
|
||||
SF2Modulator modulator = new SF2Modulator();
|
||||
modulator.sourceOperator = chunk.readUnsignedShort();
|
||||
modulator.destinationOperator = chunk.readUnsignedShort();
|
||||
modulator.amount = chunk.readShort();
|
||||
modulator.amountSourceOperator = chunk.readUnsignedShort();
|
||||
modulator.transportOperator = chunk.readUnsignedShort();
|
||||
SF2InstrumentRegion split = presets_splits_mod.get(i);
|
||||
if (split != null)
|
||||
split.modulators.add(modulator);
|
||||
}
|
||||
} else if (format.equals("pgen")) {
|
||||
// Preset Generators / Split Generators
|
||||
for (int i = 0; i < presets_splits_gen.size(); i++) {
|
||||
int operator = chunk.readUnsignedShort();
|
||||
short amount = chunk.readShort();
|
||||
SF2InstrumentRegion split = presets_splits_gen.get(i);
|
||||
if (split != null)
|
||||
split.generators.put(operator, amount);
|
||||
}
|
||||
} else if (format.equals("inst")) {
|
||||
// Instrument Header / Layers
|
||||
if (chunk.available() % 22 != 0)
|
||||
throw new RIFFInvalidDataException();
|
||||
int count = chunk.available() / 22;
|
||||
for (int i = 0; i < count; i++) {
|
||||
SF2Layer layer = new SF2Layer(this);
|
||||
layer.name = chunk.readString(20);
|
||||
instruments_bagNdx.add(chunk.readUnsignedShort());
|
||||
instruments.add(layer);
|
||||
if (i != count - 1)
|
||||
this.layers.add(layer);
|
||||
}
|
||||
} else if (format.equals("ibag")) {
|
||||
// Instrument Zones / Layer splits
|
||||
if (chunk.available() % 4 != 0)
|
||||
throw new RIFFInvalidDataException();
|
||||
int count = chunk.available() / 4;
|
||||
|
||||
// Skip first record
|
||||
{
|
||||
int gencount = chunk.readUnsignedShort();
|
||||
int modcount = chunk.readUnsignedShort();
|
||||
while (instruments_splits_gen.size() < gencount)
|
||||
instruments_splits_gen.add(null);
|
||||
while (instruments_splits_mod.size() < modcount)
|
||||
instruments_splits_mod.add(null);
|
||||
count--;
|
||||
}
|
||||
|
||||
if (instruments_bagNdx.isEmpty()) {
|
||||
throw new RIFFInvalidDataException();
|
||||
}
|
||||
int offset = instruments_bagNdx.get(0);
|
||||
// Offset should be 0 (but just case)
|
||||
for (int i = 0; i < offset; i++) {
|
||||
if (count == 0)
|
||||
throw new RIFFInvalidDataException();
|
||||
int gencount = chunk.readUnsignedShort();
|
||||
int modcount = chunk.readUnsignedShort();
|
||||
while (instruments_splits_gen.size() < gencount)
|
||||
instruments_splits_gen.add(null);
|
||||
while (instruments_splits_mod.size() < modcount)
|
||||
instruments_splits_mod.add(null);
|
||||
count--;
|
||||
}
|
||||
|
||||
for (int i = 0; i < instruments_bagNdx.size() - 1; i++) {
|
||||
int zone_count = instruments_bagNdx.get(i + 1) - instruments_bagNdx.get(i);
|
||||
SF2Layer layer = layers.get(i);
|
||||
for (int ii = 0; ii < zone_count; ii++) {
|
||||
if (count == 0)
|
||||
throw new RIFFInvalidDataException();
|
||||
int gencount = chunk.readUnsignedShort();
|
||||
int modcount = chunk.readUnsignedShort();
|
||||
SF2LayerRegion split = new SF2LayerRegion();
|
||||
layer.regions.add(split);
|
||||
while (instruments_splits_gen.size() < gencount)
|
||||
instruments_splits_gen.add(split);
|
||||
while (instruments_splits_mod.size() < modcount)
|
||||
instruments_splits_mod.add(split);
|
||||
count--;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (format.equals("imod")) {
|
||||
// Instrument Modulators / Split Modulators
|
||||
for (int i = 0; i < instruments_splits_mod.size(); i++) {
|
||||
SF2Modulator modulator = new SF2Modulator();
|
||||
modulator.sourceOperator = chunk.readUnsignedShort();
|
||||
modulator.destinationOperator = chunk.readUnsignedShort();
|
||||
modulator.amount = chunk.readShort();
|
||||
modulator.amountSourceOperator = chunk.readUnsignedShort();
|
||||
modulator.transportOperator = chunk.readUnsignedShort();
|
||||
if (i < 0 || i >= instruments_splits_gen.size()) {
|
||||
throw new RIFFInvalidDataException();
|
||||
}
|
||||
SF2LayerRegion split = instruments_splits_gen.get(i);
|
||||
if (split != null)
|
||||
split.modulators.add(modulator);
|
||||
}
|
||||
} else if (format.equals("igen")) {
|
||||
// Instrument Generators / Split Generators
|
||||
for (int i = 0; i < instruments_splits_gen.size(); i++) {
|
||||
int operator = chunk.readUnsignedShort();
|
||||
short amount = chunk.readShort();
|
||||
SF2LayerRegion split = instruments_splits_gen.get(i);
|
||||
if (split != null)
|
||||
split.generators.put(operator, amount);
|
||||
}
|
||||
} else if (format.equals("shdr")) {
|
||||
// Sample Headers
|
||||
if (chunk.available() % 46 != 0)
|
||||
throw new RIFFInvalidDataException();
|
||||
int count = chunk.available() / 46;
|
||||
for (int i = 0; i < count; i++) {
|
||||
SF2Sample sample = new SF2Sample(this);
|
||||
sample.name = chunk.readString(20);
|
||||
long start = chunk.readUnsignedInt();
|
||||
long end = chunk.readUnsignedInt();
|
||||
if (sampleData != null)
|
||||
sample.data = sampleData.subbuffer(start * 2, end * 2, true);
|
||||
if (sampleData24 != null)
|
||||
sample.data24 = sampleData24.subbuffer(start, end, true);
|
||||
/*
|
||||
sample.data = new ModelByteBuffer(sampleData, (int)(start*2),
|
||||
(int)((end - start)*2));
|
||||
if (sampleData24 != null)
|
||||
sample.data24 = new ModelByteBuffer(sampleData24,
|
||||
(int)start, (int)(end - start));
|
||||
*/
|
||||
sample.startLoop = chunk.readUnsignedInt() - start;
|
||||
sample.endLoop = chunk.readUnsignedInt() - start;
|
||||
if (sample.startLoop < 0)
|
||||
sample.startLoop = -1;
|
||||
if (sample.endLoop < 0)
|
||||
sample.endLoop = -1;
|
||||
sample.sampleRate = chunk.readUnsignedInt();
|
||||
sample.originalPitch = chunk.readUnsignedByte();
|
||||
sample.pitchCorrection = chunk.readByte();
|
||||
sample.sampleLink = chunk.readUnsignedShort();
|
||||
sample.sampleType = chunk.readUnsignedShort();
|
||||
if (i != count - 1)
|
||||
this.samples.add(sample);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Iterator<SF2Layer> liter = this.layers.iterator();
|
||||
while (liter.hasNext()) {
|
||||
SF2Layer layer = liter.next();
|
||||
Iterator<SF2LayerRegion> siter = layer.regions.iterator();
|
||||
SF2Region globalsplit = null;
|
||||
while (siter.hasNext()) {
|
||||
SF2LayerRegion split = siter.next();
|
||||
if (split.generators.get(SF2LayerRegion.GENERATOR_SAMPLEID) != null) {
|
||||
int sampleid = split.generators.get(
|
||||
SF2LayerRegion.GENERATOR_SAMPLEID);
|
||||
split.generators.remove(SF2LayerRegion.GENERATOR_SAMPLEID);
|
||||
if (sampleid < 0 || sampleid >= samples.size()) {
|
||||
throw new RIFFInvalidDataException();
|
||||
}
|
||||
split.sample = samples.get(sampleid);
|
||||
} else {
|
||||
globalsplit = split;
|
||||
}
|
||||
}
|
||||
if (globalsplit != null) {
|
||||
layer.getRegions().remove(globalsplit);
|
||||
SF2GlobalRegion gsplit = new SF2GlobalRegion();
|
||||
gsplit.generators = globalsplit.generators;
|
||||
gsplit.modulators = globalsplit.modulators;
|
||||
layer.setGlobalZone(gsplit);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Iterator<SF2Instrument> iiter = this.instruments.iterator();
|
||||
while (iiter.hasNext()) {
|
||||
SF2Instrument instrument = iiter.next();
|
||||
Iterator<SF2InstrumentRegion> siter = instrument.regions.iterator();
|
||||
SF2Region globalsplit = null;
|
||||
while (siter.hasNext()) {
|
||||
SF2InstrumentRegion split = siter.next();
|
||||
if (split.generators.get(SF2LayerRegion.GENERATOR_INSTRUMENT) != null) {
|
||||
int instrumentid = split.generators.get(
|
||||
SF2InstrumentRegion.GENERATOR_INSTRUMENT);
|
||||
split.generators.remove(SF2LayerRegion.GENERATOR_INSTRUMENT);
|
||||
if (instrumentid < 0 || instrumentid >= layers.size()) {
|
||||
throw new RIFFInvalidDataException();
|
||||
}
|
||||
split.layer = layers.get(instrumentid);
|
||||
} else {
|
||||
globalsplit = split;
|
||||
}
|
||||
}
|
||||
|
||||
if (globalsplit != null) {
|
||||
instrument.getRegions().remove(globalsplit);
|
||||
SF2GlobalRegion gsplit = new SF2GlobalRegion();
|
||||
gsplit.generators = globalsplit.generators;
|
||||
gsplit.modulators = globalsplit.modulators;
|
||||
instrument.setGlobalZone(gsplit);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void save(String name) throws IOException {
|
||||
writeSoundbank(new RIFFWriter(name, "sfbk"));
|
||||
}
|
||||
|
||||
public void save(File file) throws IOException {
|
||||
writeSoundbank(new RIFFWriter(file, "sfbk"));
|
||||
}
|
||||
|
||||
public void save(OutputStream out) throws IOException {
|
||||
writeSoundbank(new RIFFWriter(out, "sfbk"));
|
||||
}
|
||||
|
||||
private void writeSoundbank(RIFFWriter writer) throws IOException {
|
||||
writeInfo(writer.writeList("INFO"));
|
||||
writeSdtaChunk(writer.writeList("sdta"));
|
||||
writePdtaChunk(writer.writeList("pdta"));
|
||||
writer.close();
|
||||
}
|
||||
|
||||
private void writeInfoStringChunk(RIFFWriter writer, String name,
|
||||
String value) throws IOException {
|
||||
if (value == null)
|
||||
return;
|
||||
RIFFWriter chunk = writer.writeChunk(name);
|
||||
chunk.writeString(value);
|
||||
int len = value.getBytes("ascii").length;
|
||||
chunk.write(0);
|
||||
len++;
|
||||
if (len % 2 != 0)
|
||||
chunk.write(0);
|
||||
}
|
||||
|
||||
private void writeInfo(RIFFWriter writer) throws IOException {
|
||||
if (this.targetEngine == null)
|
||||
this.targetEngine = "EMU8000";
|
||||
if (this.name == null)
|
||||
this.name = "";
|
||||
|
||||
RIFFWriter ifil_chunk = writer.writeChunk("ifil");
|
||||
ifil_chunk.writeUnsignedShort(this.major);
|
||||
ifil_chunk.writeUnsignedShort(this.minor);
|
||||
writeInfoStringChunk(writer, "isng", this.targetEngine);
|
||||
writeInfoStringChunk(writer, "INAM", this.name);
|
||||
writeInfoStringChunk(writer, "irom", this.romName);
|
||||
if (romVersionMajor != -1) {
|
||||
RIFFWriter iver_chunk = writer.writeChunk("iver");
|
||||
iver_chunk.writeUnsignedShort(this.romVersionMajor);
|
||||
iver_chunk.writeUnsignedShort(this.romVersionMinor);
|
||||
}
|
||||
writeInfoStringChunk(writer, "ICRD", this.creationDate);
|
||||
writeInfoStringChunk(writer, "IENG", this.engineers);
|
||||
writeInfoStringChunk(writer, "IPRD", this.product);
|
||||
writeInfoStringChunk(writer, "ICOP", this.copyright);
|
||||
writeInfoStringChunk(writer, "ICMT", this.comments);
|
||||
writeInfoStringChunk(writer, "ISFT", this.tools);
|
||||
|
||||
writer.close();
|
||||
}
|
||||
|
||||
private void writeSdtaChunk(RIFFWriter writer) throws IOException {
|
||||
|
||||
byte[] pad = new byte[32];
|
||||
|
||||
RIFFWriter smpl_chunk = writer.writeChunk("smpl");
|
||||
for (SF2Sample sample : samples) {
|
||||
ModelByteBuffer data = sample.getDataBuffer();
|
||||
data.writeTo(smpl_chunk);
|
||||
/*
|
||||
smpl_chunk.write(data.array(),
|
||||
data.arrayOffset(),
|
||||
data.capacity());
|
||||
*/
|
||||
smpl_chunk.write(pad);
|
||||
smpl_chunk.write(pad);
|
||||
}
|
||||
if (major < 2)
|
||||
return;
|
||||
if (major == 2 && minor < 4)
|
||||
return;
|
||||
|
||||
|
||||
for (SF2Sample sample : samples) {
|
||||
ModelByteBuffer data24 = sample.getData24Buffer();
|
||||
if (data24 == null)
|
||||
return;
|
||||
}
|
||||
|
||||
RIFFWriter sm24_chunk = writer.writeChunk("sm24");
|
||||
for (SF2Sample sample : samples) {
|
||||
ModelByteBuffer data = sample.getData24Buffer();
|
||||
data.writeTo(sm24_chunk);
|
||||
/*
|
||||
sm24_chunk.write(data.array(),
|
||||
data.arrayOffset(),
|
||||
data.capacity());*/
|
||||
smpl_chunk.write(pad);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeModulators(RIFFWriter writer, List<SF2Modulator> modulators)
|
||||
throws IOException {
|
||||
for (SF2Modulator modulator : modulators) {
|
||||
writer.writeUnsignedShort(modulator.sourceOperator);
|
||||
writer.writeUnsignedShort(modulator.destinationOperator);
|
||||
writer.writeShort(modulator.amount);
|
||||
writer.writeUnsignedShort(modulator.amountSourceOperator);
|
||||
writer.writeUnsignedShort(modulator.transportOperator);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeGenerators(RIFFWriter writer, Map<Integer, Short> generators)
|
||||
throws IOException {
|
||||
Short keyrange = (Short) generators.get(SF2Region.GENERATOR_KEYRANGE);
|
||||
Short velrange = (Short) generators.get(SF2Region.GENERATOR_VELRANGE);
|
||||
if (keyrange != null) {
|
||||
writer.writeUnsignedShort(SF2Region.GENERATOR_KEYRANGE);
|
||||
writer.writeShort(keyrange);
|
||||
}
|
||||
if (velrange != null) {
|
||||
writer.writeUnsignedShort(SF2Region.GENERATOR_VELRANGE);
|
||||
writer.writeShort(velrange);
|
||||
}
|
||||
for (Map.Entry<Integer, Short> generator : generators.entrySet()) {
|
||||
if (generator.getKey() == SF2Region.GENERATOR_KEYRANGE)
|
||||
continue;
|
||||
if (generator.getKey() == SF2Region.GENERATOR_VELRANGE)
|
||||
continue;
|
||||
writer.writeUnsignedShort(generator.getKey());
|
||||
writer.writeShort(generator.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private void writePdtaChunk(RIFFWriter writer) throws IOException {
|
||||
|
||||
RIFFWriter phdr_chunk = writer.writeChunk("phdr");
|
||||
int phdr_zone_count = 0;
|
||||
for (SF2Instrument preset : this.instruments) {
|
||||
phdr_chunk.writeString(preset.name, 20);
|
||||
phdr_chunk.writeUnsignedShort(preset.preset);
|
||||
phdr_chunk.writeUnsignedShort(preset.bank);
|
||||
phdr_chunk.writeUnsignedShort(phdr_zone_count);
|
||||
if (preset.getGlobalRegion() != null)
|
||||
phdr_zone_count += 1;
|
||||
phdr_zone_count += preset.getRegions().size();
|
||||
phdr_chunk.writeUnsignedInt(preset.library);
|
||||
phdr_chunk.writeUnsignedInt(preset.genre);
|
||||
phdr_chunk.writeUnsignedInt(preset.morphology);
|
||||
}
|
||||
phdr_chunk.writeString("EOP", 20);
|
||||
phdr_chunk.writeUnsignedShort(0);
|
||||
phdr_chunk.writeUnsignedShort(0);
|
||||
phdr_chunk.writeUnsignedShort(phdr_zone_count);
|
||||
phdr_chunk.writeUnsignedInt(0);
|
||||
phdr_chunk.writeUnsignedInt(0);
|
||||
phdr_chunk.writeUnsignedInt(0);
|
||||
|
||||
|
||||
RIFFWriter pbag_chunk = writer.writeChunk("pbag");
|
||||
int pbag_gencount = 0;
|
||||
int pbag_modcount = 0;
|
||||
for (SF2Instrument preset : this.instruments) {
|
||||
if (preset.getGlobalRegion() != null) {
|
||||
pbag_chunk.writeUnsignedShort(pbag_gencount);
|
||||
pbag_chunk.writeUnsignedShort(pbag_modcount);
|
||||
pbag_gencount += preset.getGlobalRegion().getGenerators().size();
|
||||
pbag_modcount += preset.getGlobalRegion().getModulators().size();
|
||||
}
|
||||
for (SF2InstrumentRegion region : preset.getRegions()) {
|
||||
pbag_chunk.writeUnsignedShort(pbag_gencount);
|
||||
pbag_chunk.writeUnsignedShort(pbag_modcount);
|
||||
if (layers.indexOf(region.layer) != -1) {
|
||||
// One generator is used to reference to instrument record
|
||||
pbag_gencount += 1;
|
||||
}
|
||||
pbag_gencount += region.getGenerators().size();
|
||||
pbag_modcount += region.getModulators().size();
|
||||
|
||||
}
|
||||
}
|
||||
pbag_chunk.writeUnsignedShort(pbag_gencount);
|
||||
pbag_chunk.writeUnsignedShort(pbag_modcount);
|
||||
|
||||
RIFFWriter pmod_chunk = writer.writeChunk("pmod");
|
||||
for (SF2Instrument preset : this.instruments) {
|
||||
if (preset.getGlobalRegion() != null) {
|
||||
writeModulators(pmod_chunk,
|
||||
preset.getGlobalRegion().getModulators());
|
||||
}
|
||||
for (SF2InstrumentRegion region : preset.getRegions())
|
||||
writeModulators(pmod_chunk, region.getModulators());
|
||||
}
|
||||
pmod_chunk.write(new byte[10]);
|
||||
|
||||
RIFFWriter pgen_chunk = writer.writeChunk("pgen");
|
||||
for (SF2Instrument preset : this.instruments) {
|
||||
if (preset.getGlobalRegion() != null) {
|
||||
writeGenerators(pgen_chunk,
|
||||
preset.getGlobalRegion().getGenerators());
|
||||
}
|
||||
for (SF2InstrumentRegion region : preset.getRegions()) {
|
||||
writeGenerators(pgen_chunk, region.getGenerators());
|
||||
int ix = (int) layers.indexOf(region.layer);
|
||||
if (ix != -1) {
|
||||
pgen_chunk.writeUnsignedShort(SF2Region.GENERATOR_INSTRUMENT);
|
||||
pgen_chunk.writeShort((short) ix);
|
||||
}
|
||||
}
|
||||
}
|
||||
pgen_chunk.write(new byte[4]);
|
||||
|
||||
RIFFWriter inst_chunk = writer.writeChunk("inst");
|
||||
int inst_zone_count = 0;
|
||||
for (SF2Layer instrument : this.layers) {
|
||||
inst_chunk.writeString(instrument.name, 20);
|
||||
inst_chunk.writeUnsignedShort(inst_zone_count);
|
||||
if (instrument.getGlobalRegion() != null)
|
||||
inst_zone_count += 1;
|
||||
inst_zone_count += instrument.getRegions().size();
|
||||
}
|
||||
inst_chunk.writeString("EOI", 20);
|
||||
inst_chunk.writeUnsignedShort(inst_zone_count);
|
||||
|
||||
|
||||
RIFFWriter ibag_chunk = writer.writeChunk("ibag");
|
||||
int ibag_gencount = 0;
|
||||
int ibag_modcount = 0;
|
||||
for (SF2Layer instrument : this.layers) {
|
||||
if (instrument.getGlobalRegion() != null) {
|
||||
ibag_chunk.writeUnsignedShort(ibag_gencount);
|
||||
ibag_chunk.writeUnsignedShort(ibag_modcount);
|
||||
ibag_gencount
|
||||
+= instrument.getGlobalRegion().getGenerators().size();
|
||||
ibag_modcount
|
||||
+= instrument.getGlobalRegion().getModulators().size();
|
||||
}
|
||||
for (SF2LayerRegion region : instrument.getRegions()) {
|
||||
ibag_chunk.writeUnsignedShort(ibag_gencount);
|
||||
ibag_chunk.writeUnsignedShort(ibag_modcount);
|
||||
if (samples.indexOf(region.sample) != -1) {
|
||||
// One generator is used to reference to instrument record
|
||||
ibag_gencount += 1;
|
||||
}
|
||||
ibag_gencount += region.getGenerators().size();
|
||||
ibag_modcount += region.getModulators().size();
|
||||
|
||||
}
|
||||
}
|
||||
ibag_chunk.writeUnsignedShort(ibag_gencount);
|
||||
ibag_chunk.writeUnsignedShort(ibag_modcount);
|
||||
|
||||
|
||||
RIFFWriter imod_chunk = writer.writeChunk("imod");
|
||||
for (SF2Layer instrument : this.layers) {
|
||||
if (instrument.getGlobalRegion() != null) {
|
||||
writeModulators(imod_chunk,
|
||||
instrument.getGlobalRegion().getModulators());
|
||||
}
|
||||
for (SF2LayerRegion region : instrument.getRegions())
|
||||
writeModulators(imod_chunk, region.getModulators());
|
||||
}
|
||||
imod_chunk.write(new byte[10]);
|
||||
|
||||
RIFFWriter igen_chunk = writer.writeChunk("igen");
|
||||
for (SF2Layer instrument : this.layers) {
|
||||
if (instrument.getGlobalRegion() != null) {
|
||||
writeGenerators(igen_chunk,
|
||||
instrument.getGlobalRegion().getGenerators());
|
||||
}
|
||||
for (SF2LayerRegion region : instrument.getRegions()) {
|
||||
writeGenerators(igen_chunk, region.getGenerators());
|
||||
int ix = samples.indexOf(region.sample);
|
||||
if (ix != -1) {
|
||||
igen_chunk.writeUnsignedShort(SF2Region.GENERATOR_SAMPLEID);
|
||||
igen_chunk.writeShort((short) ix);
|
||||
}
|
||||
}
|
||||
}
|
||||
igen_chunk.write(new byte[4]);
|
||||
|
||||
|
||||
RIFFWriter shdr_chunk = writer.writeChunk("shdr");
|
||||
long sample_pos = 0;
|
||||
for (SF2Sample sample : samples) {
|
||||
shdr_chunk.writeString(sample.name, 20);
|
||||
long start = sample_pos;
|
||||
sample_pos += sample.data.capacity() / 2;
|
||||
long end = sample_pos;
|
||||
long startLoop = sample.startLoop + start;
|
||||
long endLoop = sample.endLoop + start;
|
||||
if (startLoop < start)
|
||||
startLoop = start;
|
||||
if (endLoop > end)
|
||||
endLoop = end;
|
||||
shdr_chunk.writeUnsignedInt(start);
|
||||
shdr_chunk.writeUnsignedInt(end);
|
||||
shdr_chunk.writeUnsignedInt(startLoop);
|
||||
shdr_chunk.writeUnsignedInt(endLoop);
|
||||
shdr_chunk.writeUnsignedInt(sample.sampleRate);
|
||||
shdr_chunk.writeUnsignedByte(sample.originalPitch);
|
||||
shdr_chunk.writeByte(sample.pitchCorrection);
|
||||
shdr_chunk.writeUnsignedShort(sample.sampleLink);
|
||||
shdr_chunk.writeUnsignedShort(sample.sampleType);
|
||||
sample_pos += 32;
|
||||
}
|
||||
shdr_chunk.writeString("EOS", 20);
|
||||
shdr_chunk.write(new byte[26]);
|
||||
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return major + "." + minor;
|
||||
}
|
||||
|
||||
public String getVendor() {
|
||||
return engineers;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return comments;
|
||||
}
|
||||
|
||||
public void setName(String s) {
|
||||
name = s;
|
||||
}
|
||||
|
||||
public void setVendor(String s) {
|
||||
engineers = s;
|
||||
}
|
||||
|
||||
public void setDescription(String s) {
|
||||
comments = s;
|
||||
}
|
||||
|
||||
public SoundbankResource[] getResources() {
|
||||
SoundbankResource[] resources
|
||||
= new SoundbankResource[layers.size() + samples.size()];
|
||||
int j = 0;
|
||||
for (int i = 0; i < layers.size(); i++)
|
||||
resources[j++] = layers.get(i);
|
||||
for (int i = 0; i < samples.size(); i++)
|
||||
resources[j++] = samples.get(i);
|
||||
return resources;
|
||||
}
|
||||
|
||||
public SF2Instrument[] getInstruments() {
|
||||
SF2Instrument[] inslist_array
|
||||
= instruments.toArray(new SF2Instrument[instruments.size()]);
|
||||
Arrays.sort(inslist_array, new ModelInstrumentComparator());
|
||||
return inslist_array;
|
||||
}
|
||||
|
||||
public SF2Layer[] getLayers() {
|
||||
return layers.toArray(new SF2Layer[layers.size()]);
|
||||
}
|
||||
|
||||
public SF2Sample[] getSamples() {
|
||||
return samples.toArray(new SF2Sample[samples.size()]);
|
||||
}
|
||||
|
||||
public Instrument getInstrument(Patch patch) {
|
||||
int program = patch.getProgram();
|
||||
int bank = patch.getBank();
|
||||
boolean percussion = false;
|
||||
if (patch instanceof ModelPatch)
|
||||
percussion = ((ModelPatch)patch).isPercussion();
|
||||
for (Instrument instrument : instruments) {
|
||||
Patch patch2 = instrument.getPatch();
|
||||
int program2 = patch2.getProgram();
|
||||
int bank2 = patch2.getBank();
|
||||
if (program == program2 && bank == bank2) {
|
||||
boolean percussion2 = false;
|
||||
if (patch2 instanceof ModelPatch)
|
||||
percussion2 = ((ModelPatch) patch2).isPercussion();
|
||||
if (percussion == percussion2)
|
||||
return instrument;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getCreationDate() {
|
||||
return creationDate;
|
||||
}
|
||||
|
||||
public void setCreationDate(String creationDate) {
|
||||
this.creationDate = creationDate;
|
||||
}
|
||||
|
||||
public String getProduct() {
|
||||
return product;
|
||||
}
|
||||
|
||||
public void setProduct(String product) {
|
||||
this.product = product;
|
||||
}
|
||||
|
||||
public String getRomName() {
|
||||
return romName;
|
||||
}
|
||||
|
||||
public void setRomName(String romName) {
|
||||
this.romName = romName;
|
||||
}
|
||||
|
||||
public int getRomVersionMajor() {
|
||||
return romVersionMajor;
|
||||
}
|
||||
|
||||
public void setRomVersionMajor(int romVersionMajor) {
|
||||
this.romVersionMajor = romVersionMajor;
|
||||
}
|
||||
|
||||
public int getRomVersionMinor() {
|
||||
return romVersionMinor;
|
||||
}
|
||||
|
||||
public void setRomVersionMinor(int romVersionMinor) {
|
||||
this.romVersionMinor = romVersionMinor;
|
||||
}
|
||||
|
||||
public String getTargetEngine() {
|
||||
return targetEngine;
|
||||
}
|
||||
|
||||
public void setTargetEngine(String targetEngine) {
|
||||
this.targetEngine = targetEngine;
|
||||
}
|
||||
|
||||
public String getTools() {
|
||||
return tools;
|
||||
}
|
||||
|
||||
public void setTools(String tools) {
|
||||
this.tools = tools;
|
||||
}
|
||||
|
||||
public void addResource(SoundbankResource resource) {
|
||||
if (resource instanceof SF2Instrument)
|
||||
instruments.add((SF2Instrument)resource);
|
||||
if (resource instanceof SF2Layer)
|
||||
layers.add((SF2Layer)resource);
|
||||
if (resource instanceof SF2Sample)
|
||||
samples.add((SF2Sample)resource);
|
||||
}
|
||||
|
||||
public void removeResource(SoundbankResource resource) {
|
||||
if (resource instanceof SF2Instrument)
|
||||
instruments.remove((SF2Instrument)resource);
|
||||
if (resource instanceof SF2Layer)
|
||||
layers.remove((SF2Layer)resource);
|
||||
if (resource instanceof SF2Sample)
|
||||
samples.remove((SF2Sample)resource);
|
||||
}
|
||||
|
||||
public void addInstrument(SF2Instrument resource) {
|
||||
instruments.add(resource);
|
||||
}
|
||||
|
||||
public void removeInstrument(SF2Instrument resource) {
|
||||
instruments.remove(resource);
|
||||
}
|
||||
}
|
||||
73
jdkSrc/jdk8/com/sun/media/sound/SF2SoundbankReader.java
Normal file
73
jdkSrc/jdk8/com/sun/media/sound/SF2SoundbankReader.java
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import javax.sound.midi.InvalidMidiDataException;
|
||||
import javax.sound.midi.Soundbank;
|
||||
import javax.sound.midi.spi.SoundbankReader;
|
||||
|
||||
/**
|
||||
* This class is used to connect the SF2SoundBank class
|
||||
* to the SoundbankReader SPI interface.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public final class SF2SoundbankReader extends SoundbankReader {
|
||||
|
||||
public Soundbank getSoundbank(URL url)
|
||||
throws InvalidMidiDataException, IOException {
|
||||
try {
|
||||
return new SF2Soundbank(url);
|
||||
} catch (RIFFInvalidFormatException e) {
|
||||
return null;
|
||||
} catch(IOException ioe) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Soundbank getSoundbank(InputStream stream)
|
||||
throws InvalidMidiDataException, IOException {
|
||||
try {
|
||||
stream.mark(512);
|
||||
return new SF2Soundbank(stream);
|
||||
} catch (RIFFInvalidFormatException e) {
|
||||
stream.reset();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Soundbank getSoundbank(File file)
|
||||
throws InvalidMidiDataException, IOException {
|
||||
try {
|
||||
return new SF2Soundbank(file);
|
||||
} catch (RIFFInvalidFormatException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
196
jdkSrc/jdk8/com/sun/media/sound/SimpleInstrument.java
Normal file
196
jdkSrc/jdk8/com/sun/media/sound/SimpleInstrument.java
Normal file
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.sound.midi.Patch;
|
||||
|
||||
/**
|
||||
* A simple instrument that is made of other ModelInstrument, ModelPerformer
|
||||
* objects.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public class SimpleInstrument extends ModelInstrument {
|
||||
|
||||
private static class SimpleInstrumentPart {
|
||||
ModelPerformer[] performers;
|
||||
int keyFrom;
|
||||
int keyTo;
|
||||
int velFrom;
|
||||
int velTo;
|
||||
int exclusiveClass;
|
||||
}
|
||||
protected int preset = 0;
|
||||
protected int bank = 0;
|
||||
protected boolean percussion = false;
|
||||
protected String name = "";
|
||||
protected List<SimpleInstrumentPart> parts
|
||||
= new ArrayList<SimpleInstrumentPart>();
|
||||
|
||||
public SimpleInstrument() {
|
||||
super(null, null, null, null);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
parts.clear();
|
||||
}
|
||||
|
||||
public void add(ModelPerformer[] performers, int keyFrom, int keyTo,
|
||||
int velFrom, int velTo, int exclusiveClass) {
|
||||
SimpleInstrumentPart part = new SimpleInstrumentPart();
|
||||
part.performers = performers;
|
||||
part.keyFrom = keyFrom;
|
||||
part.keyTo = keyTo;
|
||||
part.velFrom = velFrom;
|
||||
part.velTo = velTo;
|
||||
part.exclusiveClass = exclusiveClass;
|
||||
parts.add(part);
|
||||
}
|
||||
|
||||
public void add(ModelPerformer[] performers, int keyFrom, int keyTo,
|
||||
int velFrom, int velTo) {
|
||||
add(performers, keyFrom, keyTo, velFrom, velTo, -1);
|
||||
}
|
||||
|
||||
public void add(ModelPerformer[] performers, int keyFrom, int keyTo) {
|
||||
add(performers, keyFrom, keyTo, 0, 127, -1);
|
||||
}
|
||||
|
||||
public void add(ModelPerformer[] performers) {
|
||||
add(performers, 0, 127, 0, 127, -1);
|
||||
}
|
||||
|
||||
public void add(ModelPerformer performer, int keyFrom, int keyTo,
|
||||
int velFrom, int velTo, int exclusiveClass) {
|
||||
add(new ModelPerformer[]{performer}, keyFrom, keyTo, velFrom, velTo,
|
||||
exclusiveClass);
|
||||
}
|
||||
|
||||
public void add(ModelPerformer performer, int keyFrom, int keyTo,
|
||||
int velFrom, int velTo) {
|
||||
add(new ModelPerformer[]{performer}, keyFrom, keyTo, velFrom, velTo);
|
||||
}
|
||||
|
||||
public void add(ModelPerformer performer, int keyFrom, int keyTo) {
|
||||
add(new ModelPerformer[]{performer}, keyFrom, keyTo);
|
||||
}
|
||||
|
||||
public void add(ModelPerformer performer) {
|
||||
add(new ModelPerformer[]{performer});
|
||||
}
|
||||
|
||||
public void add(ModelInstrument ins, int keyFrom, int keyTo, int velFrom,
|
||||
int velTo, int exclusiveClass) {
|
||||
add(ins.getPerformers(), keyFrom, keyTo, velFrom, velTo, exclusiveClass);
|
||||
}
|
||||
|
||||
public void add(ModelInstrument ins, int keyFrom, int keyTo, int velFrom,
|
||||
int velTo) {
|
||||
add(ins.getPerformers(), keyFrom, keyTo, velFrom, velTo);
|
||||
}
|
||||
|
||||
public void add(ModelInstrument ins, int keyFrom, int keyTo) {
|
||||
add(ins.getPerformers(), keyFrom, keyTo);
|
||||
}
|
||||
|
||||
public void add(ModelInstrument ins) {
|
||||
add(ins.getPerformers());
|
||||
}
|
||||
|
||||
public ModelPerformer[] getPerformers() {
|
||||
|
||||
int percount = 0;
|
||||
for (SimpleInstrumentPart part : parts)
|
||||
if (part.performers != null)
|
||||
percount += part.performers.length;
|
||||
|
||||
ModelPerformer[] performers = new ModelPerformer[percount];
|
||||
int px = 0;
|
||||
for (SimpleInstrumentPart part : parts) {
|
||||
if (part.performers != null) {
|
||||
for (ModelPerformer mperfm : part.performers) {
|
||||
ModelPerformer performer = new ModelPerformer();
|
||||
performer.setName(getName());
|
||||
performers[px++] = performer;
|
||||
|
||||
performer.setDefaultConnectionsEnabled(
|
||||
mperfm.isDefaultConnectionsEnabled());
|
||||
performer.setKeyFrom(mperfm.getKeyFrom());
|
||||
performer.setKeyTo(mperfm.getKeyTo());
|
||||
performer.setVelFrom(mperfm.getVelFrom());
|
||||
performer.setVelTo(mperfm.getVelTo());
|
||||
performer.setExclusiveClass(mperfm.getExclusiveClass());
|
||||
performer.setSelfNonExclusive(mperfm.isSelfNonExclusive());
|
||||
performer.setReleaseTriggered(mperfm.isReleaseTriggered());
|
||||
if (part.exclusiveClass != -1)
|
||||
performer.setExclusiveClass(part.exclusiveClass);
|
||||
if (part.keyFrom > performer.getKeyFrom())
|
||||
performer.setKeyFrom(part.keyFrom);
|
||||
if (part.keyTo < performer.getKeyTo())
|
||||
performer.setKeyTo(part.keyTo);
|
||||
if (part.velFrom > performer.getVelFrom())
|
||||
performer.setVelFrom(part.velFrom);
|
||||
if (part.velTo < performer.getVelTo())
|
||||
performer.setVelTo(part.velTo);
|
||||
performer.getOscillators().addAll(mperfm.getOscillators());
|
||||
performer.getConnectionBlocks().addAll(
|
||||
mperfm.getConnectionBlocks());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return performers;
|
||||
}
|
||||
|
||||
public Object getData() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public ModelPatch getPatch() {
|
||||
return new ModelPatch(bank, preset, percussion);
|
||||
}
|
||||
|
||||
public void setPatch(Patch patch) {
|
||||
if (patch instanceof ModelPatch && ((ModelPatch)patch).isPercussion()) {
|
||||
percussion = true;
|
||||
bank = patch.getBank();
|
||||
preset = patch.getProgram();
|
||||
} else {
|
||||
percussion = false;
|
||||
bank = patch.getBank();
|
||||
preset = patch.getProgram();
|
||||
}
|
||||
}
|
||||
}
|
||||
145
jdkSrc/jdk8/com/sun/media/sound/SimpleSoundbank.java
Normal file
145
jdkSrc/jdk8/com/sun/media/sound/SimpleSoundbank.java
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import javax.sound.midi.Instrument;
|
||||
import javax.sound.midi.Patch;
|
||||
import javax.sound.midi.Soundbank;
|
||||
import javax.sound.midi.SoundbankResource;
|
||||
|
||||
/**
|
||||
* A simple soundbank that contains instruments and soundbankresources.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public class SimpleSoundbank implements Soundbank {
|
||||
|
||||
String name = "";
|
||||
String version = "";
|
||||
String vendor = "";
|
||||
String description = "";
|
||||
List<SoundbankResource> resources = new ArrayList<SoundbankResource>();
|
||||
List<Instrument> instruments = new ArrayList<Instrument>();
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public String getVendor() {
|
||||
return vendor;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setVendor(String vendor) {
|
||||
this.vendor = vendor;
|
||||
}
|
||||
|
||||
public void setVersion(String version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public SoundbankResource[] getResources() {
|
||||
return resources.toArray(new SoundbankResource[resources.size()]);
|
||||
}
|
||||
|
||||
public Instrument[] getInstruments() {
|
||||
Instrument[] inslist_array
|
||||
= instruments.toArray(new Instrument[resources.size()]);
|
||||
Arrays.sort(inslist_array, new ModelInstrumentComparator());
|
||||
return inslist_array;
|
||||
}
|
||||
|
||||
public Instrument getInstrument(Patch patch) {
|
||||
int program = patch.getProgram();
|
||||
int bank = patch.getBank();
|
||||
boolean percussion = false;
|
||||
if (patch instanceof ModelPatch)
|
||||
percussion = ((ModelPatch)patch).isPercussion();
|
||||
for (Instrument instrument : instruments) {
|
||||
Patch patch2 = instrument.getPatch();
|
||||
int program2 = patch2.getProgram();
|
||||
int bank2 = patch2.getBank();
|
||||
if (program == program2 && bank == bank2) {
|
||||
boolean percussion2 = false;
|
||||
if (patch2 instanceof ModelPatch)
|
||||
percussion2 = ((ModelPatch)patch2).isPercussion();
|
||||
if (percussion == percussion2)
|
||||
return instrument;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void addResource(SoundbankResource resource) {
|
||||
if (resource instanceof Instrument)
|
||||
instruments.add((Instrument) resource);
|
||||
else
|
||||
resources.add(resource);
|
||||
}
|
||||
|
||||
public void removeResource(SoundbankResource resource) {
|
||||
if (resource instanceof Instrument)
|
||||
instruments.remove((Instrument) resource);
|
||||
else
|
||||
resources.remove(resource);
|
||||
}
|
||||
|
||||
public void addInstrument(Instrument resource) {
|
||||
instruments.add(resource);
|
||||
}
|
||||
|
||||
public void removeInstrument(Instrument resource) {
|
||||
instruments.remove(resource);
|
||||
}
|
||||
|
||||
public void addAllInstruments(Soundbank soundbank) {
|
||||
for (Instrument ins : soundbank.getInstruments())
|
||||
addInstrument(ins);
|
||||
}
|
||||
|
||||
public void removeAllInstruments(Soundbank soundbank) {
|
||||
for (Instrument ins : soundbank.getInstruments())
|
||||
removeInstrument(ins);
|
||||
}
|
||||
}
|
||||
390
jdkSrc/jdk8/com/sun/media/sound/SoftAbstractResampler.java
Normal file
390
jdkSrc/jdk8/com/sun/media/sound/SoftAbstractResampler.java
Normal file
@@ -0,0 +1,390 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.sound.midi.MidiChannel;
|
||||
import javax.sound.midi.VoiceStatus;
|
||||
|
||||
/**
|
||||
* Abstract resampler class.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public abstract class SoftAbstractResampler implements SoftResampler {
|
||||
|
||||
private class ModelAbstractResamplerStream implements SoftResamplerStreamer {
|
||||
|
||||
AudioFloatInputStream stream;
|
||||
boolean stream_eof = false;
|
||||
int loopmode;
|
||||
boolean loopdirection = true; // true = forward
|
||||
float loopstart;
|
||||
float looplen;
|
||||
float target_pitch;
|
||||
float[] current_pitch = new float[1];
|
||||
boolean started;
|
||||
boolean eof;
|
||||
int sector_pos = 0;
|
||||
int sector_size = 400;
|
||||
int sector_loopstart = -1;
|
||||
boolean markset = false;
|
||||
int marklimit = 0;
|
||||
int streampos = 0;
|
||||
int nrofchannels = 2;
|
||||
boolean noteOff_flag = false;
|
||||
float[][] ibuffer;
|
||||
boolean ibuffer_order = true;
|
||||
float[] sbuffer;
|
||||
int pad;
|
||||
int pad2;
|
||||
float[] ix = new float[1];
|
||||
int[] ox = new int[1];
|
||||
float samplerateconv = 1;
|
||||
float pitchcorrection = 0;
|
||||
|
||||
ModelAbstractResamplerStream() {
|
||||
pad = getPadding();
|
||||
pad2 = getPadding() * 2;
|
||||
ibuffer = new float[2][sector_size + pad2];
|
||||
ibuffer_order = true;
|
||||
}
|
||||
|
||||
public void noteOn(MidiChannel channel, VoiceStatus voice,
|
||||
int noteNumber, int velocity) {
|
||||
}
|
||||
|
||||
public void noteOff(int velocity) {
|
||||
noteOff_flag = true;
|
||||
}
|
||||
|
||||
public void open(ModelWavetable osc, float outputsamplerate)
|
||||
throws IOException {
|
||||
|
||||
eof = false;
|
||||
nrofchannels = osc.getChannels();
|
||||
if (ibuffer.length < nrofchannels) {
|
||||
ibuffer = new float[nrofchannels][sector_size + pad2];
|
||||
}
|
||||
|
||||
stream = osc.openStream();
|
||||
streampos = 0;
|
||||
stream_eof = false;
|
||||
pitchcorrection = osc.getPitchcorrection();
|
||||
samplerateconv
|
||||
= stream.getFormat().getSampleRate() / outputsamplerate;
|
||||
looplen = osc.getLoopLength();
|
||||
loopstart = osc.getLoopStart();
|
||||
sector_loopstart = (int) (loopstart / sector_size);
|
||||
sector_loopstart = sector_loopstart - 1;
|
||||
|
||||
sector_pos = 0;
|
||||
|
||||
if (sector_loopstart < 0)
|
||||
sector_loopstart = 0;
|
||||
started = false;
|
||||
loopmode = osc.getLoopType();
|
||||
|
||||
if (loopmode != 0) {
|
||||
markset = false;
|
||||
marklimit = nrofchannels * (int) (looplen + pad2 + 1);
|
||||
} else
|
||||
markset = true;
|
||||
// loopmode = 0;
|
||||
|
||||
target_pitch = samplerateconv;
|
||||
current_pitch[0] = samplerateconv;
|
||||
|
||||
ibuffer_order = true;
|
||||
loopdirection = true;
|
||||
noteOff_flag = false;
|
||||
|
||||
for (int i = 0; i < nrofchannels; i++)
|
||||
Arrays.fill(ibuffer[i], sector_size, sector_size + pad2, 0);
|
||||
ix[0] = pad;
|
||||
eof = false;
|
||||
|
||||
ix[0] = sector_size + pad;
|
||||
sector_pos = -1;
|
||||
streampos = -sector_size;
|
||||
|
||||
nextBuffer();
|
||||
}
|
||||
|
||||
public void setPitch(float pitch) {
|
||||
/*
|
||||
this.pitch = (float) Math.pow(2f,
|
||||
(pitchcorrection + pitch) / 1200.0f)
|
||||
* samplerateconv;
|
||||
*/
|
||||
this.target_pitch = (float)Math.exp(
|
||||
(pitchcorrection + pitch) * (Math.log(2.0) / 1200.0))
|
||||
* samplerateconv;
|
||||
|
||||
if (!started)
|
||||
current_pitch[0] = this.target_pitch;
|
||||
}
|
||||
|
||||
public void nextBuffer() throws IOException {
|
||||
if (ix[0] < pad) {
|
||||
if (markset) {
|
||||
// reset to target sector
|
||||
stream.reset();
|
||||
ix[0] += streampos - (sector_loopstart * sector_size);
|
||||
sector_pos = sector_loopstart;
|
||||
streampos = sector_pos * sector_size;
|
||||
|
||||
// and go one sector backward
|
||||
ix[0] += sector_size;
|
||||
sector_pos -= 1;
|
||||
streampos -= sector_size;
|
||||
stream_eof = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (ix[0] >= sector_size + pad) {
|
||||
if (stream_eof) {
|
||||
eof = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (ix[0] >= sector_size * 4 + pad) {
|
||||
int skips = (int)((ix[0] - sector_size * 4 + pad) / sector_size);
|
||||
ix[0] -= sector_size * skips;
|
||||
sector_pos += skips;
|
||||
streampos += sector_size * skips;
|
||||
stream.skip(sector_size * skips);
|
||||
}
|
||||
|
||||
while (ix[0] >= sector_size + pad) {
|
||||
if (!markset) {
|
||||
if (sector_pos + 1 == sector_loopstart) {
|
||||
stream.mark(marklimit);
|
||||
markset = true;
|
||||
}
|
||||
}
|
||||
ix[0] -= sector_size;
|
||||
sector_pos++;
|
||||
streampos += sector_size;
|
||||
|
||||
for (int c = 0; c < nrofchannels; c++) {
|
||||
float[] cbuffer = ibuffer[c];
|
||||
for (int i = 0; i < pad2; i++)
|
||||
cbuffer[i] = cbuffer[i + sector_size];
|
||||
}
|
||||
|
||||
int ret;
|
||||
if (nrofchannels == 1)
|
||||
ret = stream.read(ibuffer[0], pad2, sector_size);
|
||||
else {
|
||||
int slen = sector_size * nrofchannels;
|
||||
if (sbuffer == null || sbuffer.length < slen)
|
||||
sbuffer = new float[slen];
|
||||
int sret = stream.read(sbuffer, 0, slen);
|
||||
if (sret == -1)
|
||||
ret = -1;
|
||||
else {
|
||||
ret = sret / nrofchannels;
|
||||
for (int i = 0; i < nrofchannels; i++) {
|
||||
float[] buff = ibuffer[i];
|
||||
int ix = i;
|
||||
int ix_step = nrofchannels;
|
||||
int ox = pad2;
|
||||
for (int j = 0; j < ret; j++, ix += ix_step, ox++)
|
||||
buff[ox] = sbuffer[ix];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (ret == -1) {
|
||||
ret = 0;
|
||||
stream_eof = true;
|
||||
for (int i = 0; i < nrofchannels; i++)
|
||||
Arrays.fill(ibuffer[i], pad2, pad2 + sector_size, 0f);
|
||||
return;
|
||||
}
|
||||
if (ret != sector_size) {
|
||||
for (int i = 0; i < nrofchannels; i++)
|
||||
Arrays.fill(ibuffer[i], pad2 + ret, pad2 + sector_size, 0f);
|
||||
}
|
||||
|
||||
ibuffer_order = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void reverseBuffers() {
|
||||
ibuffer_order = !ibuffer_order;
|
||||
for (int c = 0; c < nrofchannels; c++) {
|
||||
float[] cbuff = ibuffer[c];
|
||||
int len = cbuff.length - 1;
|
||||
int len2 = cbuff.length / 2;
|
||||
for (int i = 0; i < len2; i++) {
|
||||
float x = cbuff[i];
|
||||
cbuff[i] = cbuff[len - i];
|
||||
cbuff[len - i] = x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int read(float[][] buffer, int offset, int len)
|
||||
throws IOException {
|
||||
|
||||
if (eof)
|
||||
return -1;
|
||||
|
||||
if (noteOff_flag)
|
||||
if ((loopmode & 2) != 0)
|
||||
if (loopdirection)
|
||||
loopmode = 0;
|
||||
|
||||
|
||||
float pitchstep = (target_pitch - current_pitch[0]) / len;
|
||||
float[] current_pitch = this.current_pitch;
|
||||
started = true;
|
||||
|
||||
int[] ox = this.ox;
|
||||
ox[0] = offset;
|
||||
int ox_end = len + offset;
|
||||
|
||||
float ixend = sector_size + pad;
|
||||
if (!loopdirection)
|
||||
ixend = pad;
|
||||
while (ox[0] != ox_end) {
|
||||
nextBuffer();
|
||||
if (!loopdirection) {
|
||||
// If we are in backward playing part of pingpong
|
||||
// or reverse loop
|
||||
|
||||
if (streampos < (loopstart + pad)) {
|
||||
ixend = loopstart - streampos + pad2;
|
||||
if (ix[0] <= ixend) {
|
||||
if ((loopmode & 4) != 0) {
|
||||
// Ping pong loop, change loopdirection
|
||||
loopdirection = true;
|
||||
ixend = sector_size + pad;
|
||||
continue;
|
||||
}
|
||||
|
||||
ix[0] += looplen;
|
||||
ixend = pad;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (ibuffer_order != loopdirection)
|
||||
reverseBuffers();
|
||||
|
||||
ix[0] = (sector_size + pad2) - ix[0];
|
||||
ixend = (sector_size + pad2) - ixend;
|
||||
ixend++;
|
||||
|
||||
float bak_ix = ix[0];
|
||||
int bak_ox = ox[0];
|
||||
float bak_pitch = current_pitch[0];
|
||||
for (int i = 0; i < nrofchannels; i++) {
|
||||
if (buffer[i] != null) {
|
||||
ix[0] = bak_ix;
|
||||
ox[0] = bak_ox;
|
||||
current_pitch[0] = bak_pitch;
|
||||
interpolate(ibuffer[i], ix, ixend, current_pitch,
|
||||
pitchstep, buffer[i], ox, ox_end);
|
||||
}
|
||||
}
|
||||
|
||||
ix[0] = (sector_size + pad2) - ix[0];
|
||||
ixend--;
|
||||
ixend = (sector_size + pad2) - ixend;
|
||||
|
||||
if (eof) {
|
||||
current_pitch[0] = this.target_pitch;
|
||||
return ox[0] - offset;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
if (loopmode != 0) {
|
||||
if (streampos + sector_size > (looplen + loopstart + pad)) {
|
||||
ixend = loopstart + looplen - streampos + pad2;
|
||||
if (ix[0] >= ixend) {
|
||||
if ((loopmode & 4) != 0 || (loopmode & 8) != 0) {
|
||||
// Ping pong or revese loop, change loopdirection
|
||||
loopdirection = false;
|
||||
ixend = pad;
|
||||
continue;
|
||||
}
|
||||
ixend = sector_size + pad;
|
||||
ix[0] -= looplen;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ibuffer_order != loopdirection)
|
||||
reverseBuffers();
|
||||
|
||||
float bak_ix = ix[0];
|
||||
int bak_ox = ox[0];
|
||||
float bak_pitch = current_pitch[0];
|
||||
for (int i = 0; i < nrofchannels; i++) {
|
||||
if (buffer[i] != null) {
|
||||
ix[0] = bak_ix;
|
||||
ox[0] = bak_ox;
|
||||
current_pitch[0] = bak_pitch;
|
||||
interpolate(ibuffer[i], ix, ixend, current_pitch,
|
||||
pitchstep, buffer[i], ox, ox_end);
|
||||
}
|
||||
}
|
||||
|
||||
if (eof) {
|
||||
current_pitch[0] = this.target_pitch;
|
||||
return ox[0] - offset;
|
||||
}
|
||||
}
|
||||
|
||||
current_pitch[0] = this.target_pitch;
|
||||
return len;
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
stream.close();
|
||||
}
|
||||
}
|
||||
|
||||
public abstract int getPadding();
|
||||
|
||||
public abstract void interpolate(float[] in, float[] in_offset,
|
||||
float in_end, float[] pitch, float pitchstep, float[] out,
|
||||
int[] out_offset, int out_end);
|
||||
|
||||
public final SoftResamplerStreamer openStreamer() {
|
||||
return new ModelAbstractResamplerStream();
|
||||
}
|
||||
}
|
||||
128
jdkSrc/jdk8/com/sun/media/sound/SoftAudioBuffer.java
Normal file
128
jdkSrc/jdk8/com/sun/media/sound/SoftAudioBuffer.java
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.sound.sampled.AudioFormat;
|
||||
|
||||
/**
|
||||
* This class is used to store audio buffer.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public final class SoftAudioBuffer {
|
||||
|
||||
private int size;
|
||||
private float[] buffer;
|
||||
private boolean empty = true;
|
||||
private AudioFormat format;
|
||||
private AudioFloatConverter converter;
|
||||
private byte[] converter_buffer;
|
||||
|
||||
public SoftAudioBuffer(int size, AudioFormat format) {
|
||||
this.size = size;
|
||||
this.format = format;
|
||||
converter = AudioFloatConverter.getConverter(format);
|
||||
}
|
||||
|
||||
public void swap(SoftAudioBuffer swap)
|
||||
{
|
||||
int bak_size = size;
|
||||
float[] bak_buffer = buffer;
|
||||
boolean bak_empty = empty;
|
||||
AudioFormat bak_format = format;
|
||||
AudioFloatConverter bak_converter = converter;
|
||||
byte[] bak_converter_buffer = converter_buffer;
|
||||
|
||||
size = swap.size;
|
||||
buffer = swap.buffer;
|
||||
empty = swap.empty;
|
||||
format = swap.format;
|
||||
converter = swap.converter;
|
||||
converter_buffer = swap.converter_buffer;
|
||||
|
||||
swap.size = bak_size;
|
||||
swap.buffer = bak_buffer;
|
||||
swap.empty = bak_empty;
|
||||
swap.format = bak_format;
|
||||
swap.converter = bak_converter;
|
||||
swap.converter_buffer = bak_converter_buffer;
|
||||
}
|
||||
|
||||
public AudioFormat getFormat() {
|
||||
return format;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
if (!empty) {
|
||||
Arrays.fill(buffer, 0);
|
||||
empty = true;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isSilent() {
|
||||
return empty;
|
||||
}
|
||||
|
||||
public float[] array() {
|
||||
empty = false;
|
||||
if (buffer == null)
|
||||
buffer = new float[size];
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public void get(byte[] buffer, int channel) {
|
||||
|
||||
int framesize_pc = (format.getFrameSize() / format.getChannels());
|
||||
int c_len = size * framesize_pc;
|
||||
if (converter_buffer == null || converter_buffer.length < c_len)
|
||||
converter_buffer = new byte[c_len];
|
||||
|
||||
if (format.getChannels() == 1) {
|
||||
converter.toByteArray(array(), size, buffer);
|
||||
} else {
|
||||
converter.toByteArray(array(), size, converter_buffer);
|
||||
if (channel >= format.getChannels())
|
||||
return;
|
||||
int z_stepover = format.getChannels() * framesize_pc;
|
||||
int k_stepover = framesize_pc;
|
||||
for (int j = 0; j < framesize_pc; j++) {
|
||||
int k = j;
|
||||
int z = channel * framesize_pc + j;
|
||||
for (int i = 0; i < size; i++) {
|
||||
buffer[z] = converter_buffer[k];
|
||||
z += z_stepover;
|
||||
k += k_stepover;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
48
jdkSrc/jdk8/com/sun/media/sound/SoftAudioProcessor.java
Normal file
48
jdkSrc/jdk8/com/sun/media/sound/SoftAudioProcessor.java
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.media.sound;
|
||||
|
||||
/**
|
||||
* Audio processor interface.
|
||||
*
|
||||
* @author Karl Helgason
|
||||
*/
|
||||
public interface SoftAudioProcessor {
|
||||
|
||||
public void globalParameterControlChange(int[] slothpath, long param,
|
||||
long value);
|
||||
|
||||
public void init(float samplerate, float controlrate);
|
||||
|
||||
public void setInput(int pin, SoftAudioBuffer input);
|
||||
|
||||
public void setOutput(int pin, SoftAudioBuffer output);
|
||||
|
||||
public void setMixMode(boolean mix);
|
||||
|
||||
public void processAudio();
|
||||
|
||||
public void processControlLogic();
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user