[]>();
+
+ T oldMethod = null;
+ Class>[] oldParams = null;
+ boolean ambiguous = false;
+
+ for (T newMethod : methods) {
+ if (isValid(newMethod)) {
+ Class>[] newParams = getParameters(newMethod);
+ if (newParams.length == this.args.length) {
+ PrimitiveWrapperMap.replacePrimitivesWithWrappers(newParams);
+ if (isAssignable(newParams, this.args)) {
+ if (oldMethod == null) {
+ oldMethod = newMethod;
+ oldParams = newParams;
+ } else {
+ boolean useNew = isAssignable(oldParams, newParams);
+ boolean useOld = isAssignable(newParams, oldParams);
+
+ if (useOld == useNew) {
+ ambiguous = true;
+ } else if (useNew) {
+ oldMethod = newMethod;
+ oldParams = newParams;
+ ambiguous = false;
+ }
+ }
+ }
+ }
+ if (isVarArgs(newMethod)) {
+ int length = newParams.length - 1;
+ if (length <= this.args.length) {
+ Class>[] array = new Class>[this.args.length];
+ System.arraycopy(newParams, 0, array, 0, length);
+ if (length < this.args.length) {
+ Class> type = newParams[length].getComponentType();
+ if (type.isPrimitive()) {
+ type = PrimitiveWrapperMap.getType(type.getName());
+ }
+ for (int i = length; i < this.args.length; i++) {
+ array[i] = type;
+ }
+ }
+ map.put(newMethod, array);
+ }
+ }
+ }
+ }
+ for (T newMethod : methods) {
+ Class>[] newParams = map.get(newMethod);
+ if (newParams != null) {
+ if (isAssignable(newParams, this.args)) {
+ if (oldMethod == null) {
+ oldMethod = newMethod;
+ oldParams = newParams;
+ } else {
+ boolean useNew = isAssignable(oldParams, newParams);
+ boolean useOld = isAssignable(newParams, oldParams);
+
+ if (useOld == useNew) {
+ if (oldParams == map.get(oldMethod)) {
+ ambiguous = true;
+ }
+ } else if (useNew) {
+ oldMethod = newMethod;
+ oldParams = newParams;
+ ambiguous = false;
+ }
+ }
+ }
+ }
+ }
+
+ if (ambiguous) {
+ throw new NoSuchMethodException("Ambiguous methods are found");
+ }
+ if (oldMethod == null) {
+ throw new NoSuchMethodException("Method is not found");
+ }
+ return oldMethod;
+ }
+
+ /**
+ * Determines if every class in {@code min} array is either the same as,
+ * or is a superclass of, the corresponding class in {@code max} array.
+ * The length of every array must equal the number of arguments.
+ * This comparison is performed in the {@link #find} method
+ * before the first call of the isAssignable method.
+ * If an argument equals {@code null}
+ * the appropriate pair of classes does not take into consideration.
+ *
+ * @param min the array of classes to be checked
+ * @param max the array of classes that is used to check
+ * @return {@code true} if all classes in {@code min} array
+ * are assignable from corresponding classes in {@code max} array,
+ * {@code false} otherwise
+ *
+ * @see Class#isAssignableFrom
+ */
+ private boolean isAssignable(Class>[] min, Class>[] max) {
+ for (int i = 0; i < this.args.length; i++) {
+ if (null != this.args[i]) {
+ if (!min[i].isAssignableFrom(max[i])) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/beans/finder/ClassFinder.java
--- a/jdk/src/share/classes/com/sun/beans/finder/ClassFinder.java Thu Jan 29 21:46:48 2009 -0800
+++ b/jdk/src/share/classes/com/sun/beans/finder/ClassFinder.java Tue Feb 03 22:02:55 2009 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2006-2008 Sun Microsystems, Inc. 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
@@ -25,7 +25,7 @@
package com.sun.beans.finder;
/**
- * This is utility class that provides static
methods
+ * This is utility class that provides {@code static} methods
* to find a class with the specified name using the specified class loader.
*
* @since 1.7
@@ -33,137 +33,138 @@
* @author Sergey A. Malenkov
*/
public final class ClassFinder {
+
/**
- * Returns the Class
object associated
+ * Returns the {@code Class} object associated
* with the class or interface with the given string name,
* using the default class loader.
*
- * The name
can denote an array class
+ * The {@code name} can denote an array class
* (see {@link Class#getName} for details).
*
* @param name fully qualified name of the desired class
* @return class object representing the desired class
*
- * @exception ClassNotFoundException if the class cannot be located
- * by the specified class loader
+ * @throws ClassNotFoundException if the class cannot be located
+ * by the specified class loader
*
* @see Class#forName(String)
* @see Class#forName(String,boolean,ClassLoader)
* @see ClassLoader#getSystemClassLoader()
* @see Thread#getContextClassLoader()
*/
- public static Class findClass( String name ) throws ClassNotFoundException {
+ public static Class> findClass(String name) throws ClassNotFoundException {
try {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
- if ( loader == null ) {
+ if (loader == null) {
// can be null in IE (see 6204697)
loader = ClassLoader.getSystemClassLoader();
}
- if ( loader != null ) {
- return Class.forName( name, false, loader );
+ if (loader != null) {
+ return Class.forName(name, false, loader);
}
- } catch ( ClassNotFoundException exception ) {
+ } catch (ClassNotFoundException exception) {
// use current class loader instead
- } catch ( SecurityException exception ) {
+ } catch (SecurityException exception) {
// use current class loader instead
}
- return Class.forName( name );
+ return Class.forName(name);
}
/**
- * Returns the Class
object associated with
+ * Returns the {@code Class} object associated with
* the class or interface with the given string name,
* using the given class loader.
*
- * The name
can denote an array class
+ * The {@code name} can denote an array class
* (see {@link Class#getName} for details).
*
- * If the parameter loader
is null,
+ * If the parameter {@code loader} is null,
* the class is loaded through the default class loader.
*
* @param name fully qualified name of the desired class
* @param loader class loader from which the class must be loaded
* @return class object representing the desired class
*
- * @exception ClassNotFoundException if the class cannot be located
- * by the specified class loader
+ * @throws ClassNotFoundException if the class cannot be located
+ * by the specified class loader
*
* @see #findClass(String,ClassLoader)
* @see Class#forName(String,boolean,ClassLoader)
*/
- public static Class findClass( String name, ClassLoader loader ) throws ClassNotFoundException {
- if ( loader != null ) {
+ public static Class> findClass(String name, ClassLoader loader) throws ClassNotFoundException {
+ if (loader != null) {
try {
- return Class.forName( name, false, loader );
- } catch ( ClassNotFoundException exception ) {
+ return Class.forName(name, false, loader);
+ } catch (ClassNotFoundException exception) {
// use default class loader instead
- } catch ( SecurityException exception ) {
+ } catch (SecurityException exception) {
// use default class loader instead
}
}
- return findClass( name );
+ return findClass(name);
}
/**
- * Returns the Class
object associated
+ * Returns the {@code Class} object associated
* with the class or interface with the given string name,
* using the default class loader.
*
- * The name
can denote an array class
+ * The {@code name} can denote an array class
* (see {@link Class#getName} for details).
*
* This method can be used to obtain
- * any of the Class
objects
- * representing void
or primitive Java types:
- * char
, byte
, short
,
- * int
, long
, float
,
- * double
and boolean
.
+ * any of the {@code Class} objects
+ * representing {@code void} or primitive Java types:
+ * {@code char}, {@code byte}, {@code short},
+ * {@code int}, {@code long}, {@code float},
+ * {@code double} and {@code boolean}.
*
* @param name fully qualified name of the desired class
* @return class object representing the desired class
*
- * @exception ClassNotFoundException if the class cannot be located
- * by the specified class loader
+ * @throws ClassNotFoundException if the class cannot be located
+ * by the specified class loader
*
* @see #resolveClass(String,ClassLoader)
*/
- public static Class resolveClass( String name ) throws ClassNotFoundException {
- return resolveClass( name, null );
+ public static Class> resolveClass(String name) throws ClassNotFoundException {
+ return resolveClass(name, null);
}
/**
- * Returns the Class
object associated with
+ * Returns the {@code Class} object associated with
* the class or interface with the given string name,
* using the given class loader.
*
- * The name
can denote an array class
+ * The {@code name} can denote an array class
* (see {@link Class#getName} for details).
*
- * If the parameter loader
is null,
+ * If the parameter {@code loader} is null,
* the class is loaded through the default class loader.
*
* This method can be used to obtain
- * any of the Class
objects
- * representing void
or primitive Java types:
- * char
, byte
, short
,
- * int
, long
, float
,
- * double
and boolean
.
+ * any of the {@code Class} objects
+ * representing {@code void} or primitive Java types:
+ * {@code char}, {@code byte}, {@code short},
+ * {@code int}, {@code long}, {@code float},
+ * {@code double} and {@code boolean}.
*
* @param name fully qualified name of the desired class
* @param loader class loader from which the class must be loaded
* @return class object representing the desired class
*
- * @exception ClassNotFoundException if the class cannot be located
- * by the specified class loader
+ * @throws ClassNotFoundException if the class cannot be located
+ * by the specified class loader
*
* @see #findClass(String,ClassLoader)
* @see PrimitiveTypeMap#getType(String)
*/
- public static Class resolveClass( String name, ClassLoader loader ) throws ClassNotFoundException {
- Class type = PrimitiveTypeMap.getType( name );
- return ( type == null )
- ? findClass( name, loader )
+ public static Class> resolveClass(String name, ClassLoader loader) throws ClassNotFoundException {
+ Class> type = PrimitiveTypeMap.getType(name);
+ return (type == null)
+ ? findClass(name, loader)
: type;
}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/beans/finder/ConstructorFinder.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/beans/finder/ConstructorFinder.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.beans.finder;
+
+import com.sun.beans.WeakCache;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Modifier;
+
+/**
+ * This utility class provides {@code static} methods
+ * to find a public constructor with specified parameter types
+ * in specified class.
+ *
+ * @since 1.7
+ *
+ * @author Sergey A. Malenkov
+ */
+public final class ConstructorFinder extends AbstractFinder> {
+ private static final WeakCache> CACHE = new WeakCache>();
+
+ /**
+ * Finds public constructor
+ * that is declared in public class.
+ *
+ * @param type the class that can have constructor
+ * @param args parameter types that is used to find constructor
+ * @return object that represents found constructor
+ * @throws NoSuchMethodException if constructor could not be found
+ * or some constructors are found
+ */
+ public static Constructor> findConstructor(Class> type, Class>...args) throws NoSuchMethodException {
+ if (type.isPrimitive()) {
+ throw new NoSuchMethodException("Primitive wrapper does not contain constructors");
+ }
+ if (type.isInterface()) {
+ throw new NoSuchMethodException("Interface does not contain constructors");
+ }
+ if (Modifier.isAbstract(type.getModifiers())) {
+ throw new NoSuchMethodException("Abstract class cannot be instantiated");
+ }
+ if (!Modifier.isPublic(type.getModifiers())) {
+ throw new NoSuchMethodException("Class is not accessible");
+ }
+ PrimitiveWrapperMap.replacePrimitivesWithWrappers(args);
+ Signature signature = new Signature(type, args);
+
+ Constructor> constructor = CACHE.get(signature);
+ if (constructor != null) {
+ return constructor;
+ }
+ constructor = new ConstructorFinder(args).find(type.getConstructors());
+ CACHE.put(signature, constructor);
+ return constructor;
+ }
+
+ /**
+ * Creates constructor finder with specified array of parameter types.
+ *
+ * @param args the array of parameter types
+ */
+ private ConstructorFinder(Class>[] args) {
+ super(args);
+ }
+
+ /**
+ * Returns an array of {@code Class} objects
+ * that represent the formal parameter types of the constructor
+ * Returns an empty array if the constructor takes no parameters.
+ *
+ * @param constructor the object that represents constructor
+ * @return the parameter types of the constructor
+ */
+ @Override
+ protected Class>[] getParameters(Constructor> constructor) {
+ return constructor.getParameterTypes();
+ }
+
+ /**
+ * Returns {@code true} if and only if the constructor
+ * was declared to take a variable number of arguments.
+ *
+ * @param constructor the object that represents constructor
+ * @return {@code true} if the constructor was declared
+ * to take a variable number of arguments;
+ * {@code false} otherwise
+ */
+ @Override
+ protected boolean isVarArgs(Constructor> constructor) {
+ return constructor.isVarArgs();
+ }
+
+ /**
+ * Checks validness of the constructor.
+ * The valid constructor should be public.
+ *
+ * @param constructor the object that represents constructor
+ * @return {@code true} if the constructor is valid,
+ * {@code false} otherwise
+ */
+ @Override
+ protected boolean isValid(Constructor> constructor) {
+ return Modifier.isPublic(constructor.getModifiers());
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/beans/finder/FieldFinder.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/beans/finder/FieldFinder.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.beans.finder;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+/**
+ * This utility class provides {@code static} methods
+ * to find a public field with specified name
+ * in specified class.
+ *
+ * @since 1.7
+ *
+ * @author Sergey A. Malenkov
+ */
+public final class FieldFinder {
+
+ /**
+ * Finds public field (static or non-static)
+ * that is declared in public class.
+ *
+ * @param type the class that can have field
+ * @param name the name of field to find
+ * @return object that represents found field
+ * @throws NoSuchFieldException if field is not found
+ * @see Class#getField
+ */
+ public static Field findField(Class> type, String name) throws NoSuchFieldException {
+ if (name == null) {
+ throw new IllegalArgumentException("Field name is not set");
+ }
+ Field field = type.getField(name);
+ if (!Modifier.isPublic(field.getModifiers())) {
+ throw new NoSuchFieldException("Field '" + name + "' is not public");
+ }
+ if (!Modifier.isPublic(field.getDeclaringClass().getModifiers())) {
+ throw new NoSuchFieldException("Field '" + name + "' is not accessible");
+ }
+ return field;
+ }
+
+ /**
+ * Finds public non-static field
+ * that is declared in public class.
+ *
+ * @param type the class that can have field
+ * @param name the name of field to find
+ * @return object that represents found field
+ * @throws NoSuchFieldException if field is not found
+ * @see Class#getField
+ */
+ public static Field findInstanceField(Class> type, String name) throws NoSuchFieldException {
+ Field field = findField(type, name);
+ if (Modifier.isStatic(field.getModifiers())) {
+ throw new NoSuchFieldException("Field '" + name + "' is static");
+ }
+ return field;
+ }
+
+ /**
+ * Finds public static field
+ * that is declared in public class.
+ *
+ * @param type the class that can have field
+ * @param name the name of field to find
+ * @return object that represents found field
+ * @throws NoSuchFieldException if field is not found
+ * @see Class#getField
+ */
+ public static Field findStaticField(Class> type, String name) throws NoSuchFieldException {
+ Field field = findField(type, name);
+ if (!Modifier.isStatic(field.getModifiers())) {
+ throw new NoSuchFieldException("Field '" + name + "' is not static");
+ }
+ return field;
+ }
+
+ /**
+ * Disable instantiation.
+ */
+ private FieldFinder() {
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/beans/finder/MethodFinder.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/beans/finder/MethodFinder.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,231 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.beans.finder;
+
+import com.sun.beans.TypeResolver;
+import com.sun.beans.WeakCache;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.Arrays;
+
+/**
+ * This utility class provides {@code static} methods
+ * to find a public method with specified name and parameter types
+ * in specified class.
+ *
+ * @since 1.7
+ *
+ * @author Sergey A. Malenkov
+ */
+public final class MethodFinder extends AbstractFinder {
+ private static final WeakCache CACHE = new WeakCache();
+
+ /**
+ * Finds public method (static or non-static)
+ * that is accessible from public class.
+ *
+ * @param type the class that can have method
+ * @param name the name of method to find
+ * @param args parameter types that is used to find method
+ * @return object that represents found method
+ * @throws NoSuchMethodException if method could not be found
+ * or some methods are found
+ */
+ public static Method findMethod(Class> type, String name, Class>...args) throws NoSuchMethodException {
+ if (name == null) {
+ throw new IllegalArgumentException("Method name is not set");
+ }
+ PrimitiveWrapperMap.replacePrimitivesWithWrappers(args);
+ Signature signature = new Signature(type, name, args);
+
+ Method method = CACHE.get(signature);
+ if (method != null) {
+ return method;
+ }
+ method = findAccessibleMethod(new MethodFinder(name, args).find(type.getMethods()));
+ CACHE.put(signature, method);
+ return method;
+ }
+
+ /**
+ * Finds public non-static method
+ * that is accessible from public class.
+ *
+ * @param type the class that can have method
+ * @param name the name of method to find
+ * @param args parameter types that is used to find method
+ * @return object that represents found method
+ * @throws NoSuchMethodException if method could not be found
+ * or some methods are found
+ */
+ public static Method findInstanceMethod(Class> type, String name, Class>... args) throws NoSuchMethodException {
+ Method method = findMethod(type, name, args);
+ if (Modifier.isStatic(method.getModifiers())) {
+ throw new NoSuchMethodException("Method '" + name + "' is static");
+ }
+ return method;
+ }
+
+ /**
+ * Finds public static method
+ * that is accessible from public class.
+ *
+ * @param type the class that can have method
+ * @param name the name of method to find
+ * @param args parameter types that is used to find method
+ * @return object that represents found method
+ * @throws NoSuchMethodException if method could not be found
+ * or some methods are found
+ */
+ public static Method findStaticMethod(Class> type, String name, Class>...args) throws NoSuchMethodException {
+ Method method = findMethod(type, name, args);
+ if (!Modifier.isStatic(method.getModifiers())) {
+ throw new NoSuchMethodException("Method '" + name + "' is not static");
+ }
+ return method;
+ }
+
+ /**
+ * Finds method that is accessible from public class or interface through class hierarchy.
+ *
+ * @param method object that represents found method
+ * @return object that represents accessible method
+ * @throws NoSuchMethodException if method is not accessible or is not found
+ * in specified superclass or interface
+ */
+ private static Method findAccessibleMethod(Method method) throws NoSuchMethodException {
+ Class> type = method.getDeclaringClass();
+ if (Modifier.isPublic(type.getModifiers())) {
+ return method;
+ }
+ if (Modifier.isStatic(method.getModifiers())) {
+ throw new NoSuchMethodException("Method '" + method.getName() + "' is not accessible");
+ }
+ for (Type generic : type.getGenericInterfaces()) {
+ try {
+ return findAccessibleMethod(method, generic);
+ }
+ catch (NoSuchMethodException exception) {
+ // try to find in superclass or another interface
+ }
+ }
+ return findAccessibleMethod(method, type.getGenericSuperclass());
+ }
+
+ /**
+ * Finds method that accessible from specified class.
+ *
+ * @param method object that represents found method
+ * @param generic generic type that is used to find accessible method
+ * @return object that represents accessible method
+ * @throws NoSuchMethodException if method is not accessible or is not found
+ * in specified superclass or interface
+ */
+ private static Method findAccessibleMethod(Method method, Type generic) throws NoSuchMethodException {
+ String name = method.getName();
+ Class>[] params = method.getParameterTypes();
+ if (generic instanceof Class) {
+ Class> type = (Class>) generic;
+ return findAccessibleMethod(type.getMethod(name, params));
+ }
+ if (generic instanceof ParameterizedType) {
+ ParameterizedType pt = (ParameterizedType) generic;
+ Class> type = (Class>) pt.getRawType();
+ for (Method m : type.getMethods()) {
+ if (m.getName().equals(name)) {
+ Class>[] pts = m.getParameterTypes();
+ if (pts.length == params.length) {
+ if (Arrays.equals(params, pts)) {
+ return findAccessibleMethod(m);
+ }
+ Type[] gpts = m.getGenericParameterTypes();
+ if (Arrays.equals(params, TypeResolver.erase(TypeResolver.resolve(pt, gpts)))) {
+ return findAccessibleMethod(m);
+ }
+ }
+ }
+ }
+ }
+ throw new NoSuchMethodException("Method '" + name + "' is not accessible");
+ }
+
+
+ private final String name;
+
+ /**
+ * Creates method finder with specified array of parameter types.
+ *
+ * @param name the name of method to find
+ * @param args the array of parameter types
+ */
+ private MethodFinder(String name, Class>[] args) {
+ super(args);
+ this.name = name;
+ }
+
+ /**
+ * Returns an array of {@code Class} objects
+ * that represent the formal parameter types of the method
+ * Returns an empty array if the method takes no parameters.
+ *
+ * @param method the object that represents method
+ * @return the parameter types of the method
+ */
+ @Override
+ protected Class>[] getParameters(Method method) {
+ return method.getParameterTypes();
+ }
+
+ /**
+ * Returns {@code true} if and only if the method
+ * was declared to take a variable number of arguments.
+ *
+ * @param method the object that represents method
+ * @return {@code true} if the method was declared
+ * to take a variable number of arguments;
+ * {@code false} otherwise
+ */
+ @Override
+ protected boolean isVarArgs(Method method) {
+ return method.isVarArgs();
+ }
+
+ /**
+ * Checks validness of the method.
+ * The valid method should be public and
+ * should have the specified name.
+ *
+ * @param method the object that represents method
+ * @return {@code true} if the method is valid,
+ * {@code false} otherwise
+ */
+ @Override
+ protected boolean isValid(Method method) {
+ return Modifier.isPublic(method.getModifiers()) && method.getName().equals(this.name);
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/beans/finder/PrimitiveTypeMap.java
--- a/jdk/src/share/classes/com/sun/beans/finder/PrimitiveTypeMap.java Thu Jan 29 21:46:48 2009 -0800
+++ b/jdk/src/share/classes/com/sun/beans/finder/PrimitiveTypeMap.java Tue Feb 03 22:02:55 2009 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2006-2008 Sun Microsystems, Inc. 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
@@ -36,29 +36,30 @@
* @author Sergey A. Malenkov
*/
final class PrimitiveTypeMap {
+
/**
* Returns primitive type class by its name.
*
* @param name the name of primitive type
* @return found primitive type class,
- * or null
if not found
+ * or {@code null} if not found
*/
- static Class getType( String name ) {
- return map.get( name );
+ static Class> getType(String name) {
+ return map.get(name);
}
- private static final Map map = new HashMap( 9 );
+ private static final Map> map = new HashMap>(9);
static {
- map.put( boolean.class.getName(), boolean.class );
- map.put( char.class.getName(), char.class );
- map.put( byte.class.getName(), byte.class );
- map.put( short.class.getName(), short.class );
- map.put( int.class.getName(), int.class );
- map.put( long.class.getName(), long.class );
- map.put( float.class.getName(), float.class );
- map.put( double.class.getName(), double.class );
- map.put( void.class.getName(), void.class );
+ map.put(boolean.class.getName(), boolean.class);
+ map.put(char.class.getName(), char.class);
+ map.put(byte.class.getName(), byte.class);
+ map.put(short.class.getName(), short.class);
+ map.put(int.class.getName(), int.class);
+ map.put(long.class.getName(), long.class);
+ map.put(float.class.getName(), float.class);
+ map.put(double.class.getName(), double.class);
+ map.put(void.class.getName(), void.class);
}
/**
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/beans/finder/PrimitiveWrapperMap.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/beans/finder/PrimitiveWrapperMap.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.beans.finder;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This utility class associates
+ * name of primitive type with appropriate wrapper.
+ *
+ * @since 1.7
+ *
+ * @author Sergey A. Malenkov
+ */
+public final class PrimitiveWrapperMap {
+
+ /**
+ * Replaces all primitive types in specified array with wrappers.
+ *
+ * @param types array of classes where all primitive types
+ * will be replaced by appropriate wrappers
+ */
+ static void replacePrimitivesWithWrappers(Class>[] types) {
+ for (int i = 0; i < types.length; i++) {
+ if (types[i] != null) {
+ if (types[i].isPrimitive()) {
+ types[i] = getType(types[i].getName());
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns wrapper for primitive type by its name.
+ *
+ * @param name the name of primitive type
+ * @return found wrapper for primitive type,
+ * or {@code null} if not found
+ */
+ public static Class> getType(String name) {
+ return map.get(name);
+ }
+
+ private static final Map> map = new HashMap>(9);
+
+ static {
+ map.put(Boolean.TYPE.getName(), Boolean.class);
+ map.put(Character.TYPE.getName(), Character.class);
+ map.put(Byte.TYPE.getName(), Byte.class);
+ map.put(Short.TYPE.getName(), Short.class);
+ map.put(Integer.TYPE.getName(), Integer.class);
+ map.put(Long.TYPE.getName(), Long.class);
+ map.put(Float.TYPE.getName(), Float.class);
+ map.put(Double.TYPE.getName(), Double.class);
+ map.put(Void.TYPE.getName(), Void.class);
+ }
+
+ /**
+ * Disable instantiation.
+ */
+ private PrimitiveWrapperMap() {
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/beans/finder/Signature.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/beans/finder/Signature.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.beans.finder;
+
+/**
+ * This class is designed to be a key of a cache
+ * of constructors or methods.
+ *
+ * @since 1.7
+ *
+ * @author Sergey A. Malenkov
+ */
+final class Signature {
+ private final Class> type;
+ private final String name;
+ private final Class>[] args;
+
+ private volatile int code;
+
+ /**
+ * Constructs signature for constructor.
+ *
+ * @param type the class that contains constructor
+ * @param args the types of constructor's parameters
+ */
+ Signature(Class> type, Class>[] args) {
+ this(type, null, args);
+ }
+
+ /**
+ * Constructs signature for method.
+ *
+ * @param type the class that contains method
+ * @param name the name of the method
+ * @param args the types of method's parameters
+ */
+ Signature(Class> type, String name, Class>[] args) {
+ this.type = type;
+ this.name = name;
+ this.args = args;
+ }
+
+ /**
+ * Indicates whether some other object is "equal to" this one.
+ *
+ * @param object the reference object with which to compare
+ * @return {@code true} if this object is the same as the
+ * {@code object} argument, {@code false} otherwise
+ * @see #hashCode()
+ */
+ @Override
+ public boolean equals(Object object) {
+ if (this == object) {
+ return true;
+ }
+ if (object instanceof Signature) {
+ Signature signature = (Signature) object;
+ return isEqual(signature.type, this.type)
+ && isEqual(signature.name, this.name)
+ && isEqual(signature.args, this.args);
+ }
+ return false;
+ }
+
+ /**
+ * Indicates whether some object is "equal to" another one.
+ * This method supports {@code null} values.
+ *
+ * @param obj1 the first reference object that will compared
+ * @param obj2 the second reference object that will compared
+ * @return {@code true} if first object is the same as the second object,
+ * {@code false} otherwise
+ */
+ private static boolean isEqual(Object obj1, Object obj2) {
+ return (obj1 == null)
+ ? obj2 == null
+ : obj1.equals(obj2);
+ }
+
+ /**
+ * Indicates whether some array is "equal to" another one.
+ * This method supports {@code null} values.
+ *
+ * @param args1 the first reference array that will compared
+ * @param args2 the second reference array that will compared
+ * @return {@code true} if first array is the same as the second array,
+ * {@code false} otherwise
+ */
+ private static boolean isEqual(Class>[] args1, Class>[] args2) {
+ if ((args1 == null) || (args2 == null)) {
+ return args1 == args2;
+ }
+ if (args1.length != args2.length) {
+ return false;
+ }
+ for (int i = 0; i < args1.length; i++) {
+ if (!isEqual(args1[i], args2[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns a hash code value for the object.
+ * This method is supported for the benefit of hashtables
+ * such as {@link java.util.HashMap} or {@link java.util.HashSet}.
+ * Hash code computed using algorithm
+ * suggested in Effective Java, Item 8.
+ *
+ * @return a hash code value for this object
+ * @see #equals(Object)
+ */
+ @Override
+ public int hashCode() {
+ if (this.code == 0) {
+ int code = 17;
+ code = addHashCode(code, this.type);
+ code = addHashCode(code, this.name);
+
+ if (this.args != null) {
+ for (Class> arg : this.args) {
+ code = addHashCode(code, arg);
+ }
+ }
+ this.code = code;
+ }
+ return this.code;
+ }
+
+ /**
+ * Adds hash code value if specified object.
+ * This is a part of the algorithm
+ * suggested in Effective Java, Item 8.
+ *
+ * @param code current hash code value
+ * @param object object that updates hash code value
+ * @return updated hash code value
+ * @see #hashCode()
+ */
+ private static int addHashCode(int code, Object object) {
+ code *= 37;
+ return (object != null)
+ ? code + object.hashCode()
+ : code;
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/java/swing/plaf/gtk/GTKColorChooserPanel.java
--- a/jdk/src/share/classes/com/sun/java/swing/plaf/gtk/GTKColorChooserPanel.java Thu Jan 29 21:46:48 2009 -0800
+++ b/jdk/src/share/classes/com/sun/java/swing/plaf/gtk/GTKColorChooserPanel.java Tue Feb 03 22:02:55 2009 -0800
@@ -799,9 +799,9 @@
Graphics g = triangleImage.getGraphics();
g.setColor(new Color(0, 0, 0, 0));
g.fillRect(0, 0, a, a);
- g.translate((int)(a / 2), 0);
+ g.translate(a / 2, 0);
paintTriangle(g, triangleSize, getColor());
- g.translate((int)(-a / 2), 0);
+ g.translate(-a / 2, 0);
g.dispose();
g = wheelImage.getGraphics();
@@ -897,7 +897,7 @@
return false;
}
// Rotate to origin and and verify x is valid.
- int triangleSize = (int)innerR * 3 / 2;
+ int triangleSize = innerR * 3 / 2;
double x1 = Math.cos(angle) * x - Math.sin(angle) * y;
double y1 = Math.sin(angle) * x + Math.cos(angle) * y;
if (x1 < -(innerR / 2)) {
@@ -960,7 +960,7 @@
*/
private void setSaturationAndBrightness(float s, float b) {
int innerR = getTriangleCircumscribedRadius();
- int triangleSize = (int)innerR * 3 / 2;
+ int triangleSize = innerR * 3 / 2;
double x = b * triangleSize;
double maxY = x * Math.tan(Math.toRadians(30.0));
double y = 2 * maxY * s - maxY;
@@ -1156,7 +1156,7 @@
* @param x X location to get color for
* @param y Y location to get color for
* @param rad Radius from center of color wheel
- * @param integer with red, green and blue components
+ * @return integer with red, green and blue components
*/
private int colorWheelLocationToRGB(int x, int y, double rad) {
double angle = Math.acos((double)x / rad);
@@ -1165,12 +1165,12 @@
if (angle < PI_3) {
if (y < 0) {
// FFFF00 - FF0000
- rgb = 0xFF0000 | (int)Math.min(255,
+ rgb = 0xFF0000 | Math.min(255,
(int)(255 * angle / PI_3)) << 8;
}
else {
// FF0000 - FF00FF
- rgb = 0xFF0000 | (int)Math.min(255,
+ rgb = 0xFF0000 | Math.min(255,
(int)(255 * angle / PI_3));
}
}
@@ -1178,12 +1178,12 @@
angle -= PI_3;
if (y < 0) {
// 00FF00 - FFFF00
- rgb = 0x00FF00 | (int)Math.max(0, 255 -
+ rgb = 0x00FF00 | Math.max(0, 255 -
(int)(255 * angle / PI_3)) << 16;
}
else {
// FF00FF - 0000FF
- rgb = 0x0000FF | (int)Math.max(0, 255 -
+ rgb = 0x0000FF | Math.max(0, 255 -
(int)(255 * angle / PI_3)) << 16;
}
}
@@ -1191,12 +1191,12 @@
angle -= 2 * PI_3;
if (y < 0) {
// 00FFFF - 00FF00
- rgb = 0x00FF00 | (int)Math.min(255,
+ rgb = 0x00FF00 | Math.min(255,
(int)(255 * angle / PI_3));
}
else {
// 0000FF - 00FFFF
- rgb = 0x0000FF | (int)Math.min(255,
+ rgb = 0x0000FF | Math.min(255,
(int)(255 * angle / PI_3)) << 8;
}
}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/java/swing/plaf/gtk/GTKEngine.java
--- a/jdk/src/share/classes/com/sun/java/swing/plaf/gtk/GTKEngine.java Thu Jan 29 21:46:48 2009 -0800
+++ b/jdk/src/share/classes/com/sun/java/swing/plaf/gtk/GTKEngine.java Tue Feb 03 22:02:55 2009 -0800
@@ -112,7 +112,7 @@
}
- private static HashMap regionToWidgetTypeMap;
+ private static HashMap regionToWidgetTypeMap;
private ImageCache cache = new ImageCache(CACHE_SIZE);
private int x0, y0, w0, h0;
private Graphics graphics;
@@ -178,7 +178,7 @@
Toolkit.getDefaultToolkit();
// Initialize regionToWidgetTypeMap
- regionToWidgetTypeMap = new HashMap(50);
+ regionToWidgetTypeMap = new HashMap(50);
regionToWidgetTypeMap.put(Region.ARROW_BUTTON, new WidgetType[] {
WidgetType.SPINNER_ARROW_BUTTON,
WidgetType.COMBO_BOX_ARROW_BUTTON,
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/java/swing/plaf/gtk/GTKFileChooserUI.java
--- a/jdk/src/share/classes/com/sun/java/swing/plaf/gtk/GTKFileChooserUI.java Thu Jan 29 21:46:48 2009 -0800
+++ b/jdk/src/share/classes/com/sun/java/swing/plaf/gtk/GTKFileChooserUI.java Tue Feb 03 22:02:55 2009 -0800
@@ -148,7 +148,7 @@
directoryList : fileList;
Object[] files = list.getSelectedValues();
int len = files.length;
- Vector result = new Vector(len + 1);
+ Vector result = new Vector(len + 1);
// we return all selected file names
for (int i = 0; i < len; i++) {
@@ -263,13 +263,13 @@
ListSelectionModel sm = directoryList.getSelectionModel();
if (sm instanceof DefaultListSelectionModel) {
((DefaultListSelectionModel)sm).moveLeadSelectionIndex(0);
- ((DefaultListSelectionModel)sm).setAnchorSelectionIndex(0);
+ sm.setAnchorSelectionIndex(0);
}
fileList.clearSelection();
sm = fileList.getSelectionModel();
if (sm instanceof DefaultListSelectionModel) {
((DefaultListSelectionModel)sm).moveLeadSelectionIndex(0);
- ((DefaultListSelectionModel)sm).setAnchorSelectionIndex(0);
+ sm.setAnchorSelectionIndex(0);
}
File currentDirectory = getFileChooser().getCurrentDirectory();
@@ -425,16 +425,16 @@
setDirectorySelected(true);
setDirectory(((File)objects[0]));
} else {
- ArrayList fList = new ArrayList(objects.length);
- for (int i = 0; i < objects.length; i++) {
- File f = (File)objects[i];
+ ArrayList fList = new ArrayList(objects.length);
+ for (Object object : objects) {
+ File f = (File) object;
if ((chooser.isFileSelectionEnabled() && f.isFile())
|| (chooser.isDirectorySelectionEnabled() && f.isDirectory())) {
fList.add(f);
}
}
if (fList.size() > 0) {
- files = (File[])fList.toArray(new File[fList.size()]);
+ files = fList.toArray(new File[fList.size()]);
}
setDirectorySelected(false);
}
@@ -671,9 +671,9 @@
pathFieldLabel.setLabelFor(fileNameTextField);
- Set forwardTraversalKeys = fileNameTextField.getFocusTraversalKeys(
+ Set forwardTraversalKeys = fileNameTextField.getFocusTraversalKeys(
KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
- forwardTraversalKeys = new HashSet(forwardTraversalKeys);
+ forwardTraversalKeys = new HashSet(forwardTraversalKeys);
forwardTraversalKeys.remove(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0));
fileNameTextField.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, forwardTraversalKeys);
@@ -895,10 +895,9 @@
private class GTKDirectoryModel extends BasicDirectoryModel {
FileSystemView fsv;
- private Comparator fileComparator = new Comparator() {
- public int compare(Object o, Object o1) {
- return fsv.getSystemDisplayName((File) o).compareTo
- (fsv.getSystemDisplayName((File) o1));
+ private Comparator fileComparator = new Comparator() {
+ public int compare(File o, File o1) {
+ return fsv.getSystemDisplayName(o).compareTo(fsv.getSystemDisplayName(o1));
}
};
@@ -1074,7 +1073,7 @@
* Data model for a type-face selection combo-box.
*/
protected class DirectoryComboBoxModel extends AbstractListModel implements ComboBoxModel {
- Vector directories = new Vector();
+ Vector directories = new Vector();
File selectedDirectory = null;
JFileChooser chooser = getFileChooser();
FileSystemView fsv = chooser.getFileSystemView();
@@ -1216,7 +1215,7 @@
ListSelectionModel sm = fileList.getSelectionModel();
if (sm instanceof DefaultListSelectionModel) {
((DefaultListSelectionModel)sm).moveLeadSelectionIndex(0);
- ((DefaultListSelectionModel)sm).setAnchorSelectionIndex(0);
+ sm.setAnchorSelectionIndex(0);
}
rescanCurrentDirectory(getFileChooser());
return;
@@ -1352,8 +1351,8 @@
FileFilter currentFilter = getFileChooser().getFileFilter();
boolean found = false;
if (currentFilter != null) {
- for (int i = 0; i < filters.length; i++) {
- if (filters[i] == currentFilter) {
+ for (FileFilter filter : filters) {
+ if (filter == currentFilter) {
found = true;
}
}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java
--- a/jdk/src/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java Thu Jan 29 21:46:48 2009 -0800
+++ b/jdk/src/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java Tue Feb 03 22:02:55 2009 -0800
@@ -1470,7 +1470,7 @@
aaTextInfo = SwingUtilities2.AATextInfo.getAATextInfo(gtkAAFontSettingsCond);
}
- static ReferenceQueue queue = new ReferenceQueue();
+ static ReferenceQueue queue = new ReferenceQueue();
private static void flushUnreferenced() {
WeakPCL pcl;
@@ -1480,12 +1480,12 @@
}
}
- static class WeakPCL extends WeakReference implements
+ static class WeakPCL extends WeakReference implements
PropertyChangeListener {
private Toolkit kit;
private String key;
- WeakPCL(Object target, Toolkit kit, String key) {
+ WeakPCL(GTKLookAndFeel target, Toolkit kit, String key) {
super(target, queue);
this.kit = kit;
this.key = key;
@@ -1494,7 +1494,7 @@
public String getKey() { return key; }
public void propertyChange(final PropertyChangeEvent pce) {
- final GTKLookAndFeel lnf = (GTKLookAndFeel)get();
+ final GTKLookAndFeel lnf = get();
if (lnf == null || UIManager.getLookAndFeel() != lnf) {
// The property was GC'ed, we're no longer interested in
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/java/swing/plaf/gtk/GTKPainter.java
--- a/jdk/src/share/classes/com/sun/java/swing/plaf/gtk/GTKPainter.java Thu Jan 29 21:46:48 2009 -0800
+++ b/jdk/src/share/classes/com/sun/java/swing/plaf/gtk/GTKPainter.java Tue Feb 03 22:02:55 2009 -0800
@@ -299,7 +299,7 @@
// Paint the default indicator
GTKStyle style = (GTKStyle)context.getStyle();
if (defaultCapable && !toolButton) {
- Insets defaultInsets = (Insets)style.getClassSpecificInsetsValue(
+ Insets defaultInsets = style.getClassSpecificInsetsValue(
context, "default-border",
GTKStyle.BUTTON_DEFAULT_BORDER_INSETS);
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/java/swing/plaf/gtk/Metacity.java
--- a/jdk/src/share/classes/com/sun/java/swing/plaf/gtk/Metacity.java Thu Jan 29 21:46:48 2009 -0800
+++ b/jdk/src/share/classes/com/sun/java/swing/plaf/gtk/Metacity.java Tue Feb 03 22:02:55 2009 -0800
@@ -124,7 +124,7 @@
}
// Initialize constants
- variables = new HashMap();
+ variables = new HashMap();
NodeList nodes = xmlDoc.getElementsByTagName("constant");
int n = nodes.getLength();
for (int i = 0; i < n; i++) {
@@ -144,14 +144,14 @@
}
// Cache frame geometries
- frameGeometries = new HashMap();
+ frameGeometries = new HashMap>();
nodes = xmlDoc.getElementsByTagName("frame_geometry");
n = nodes.getLength();
for (int i = 0; i < n; i++) {
Node node = nodes.item(i);
String name = getStringAttr(node, "name");
if (name != null) {
- HashMap gm = new HashMap();
+ HashMap gm = new HashMap();
frameGeometries.put(name, gm);
String parentGM = getStringAttr(node, "parent");
@@ -458,7 +458,7 @@
- private static class Privileged implements PrivilegedAction {
+ private static class Privileged implements PrivilegedAction {
private static int GET_THEME_DIR = 0;
private static int GET_USER_THEME = 1;
private static int GET_IMAGE = 2;
@@ -598,7 +598,7 @@
g2.setComposite(oldComp);
}
- private HashMap images = new HashMap();
+ private HashMap images = new HashMap();
protected Image getImage(String key, Color c) {
Image image = images.get(key+"-"+c.getRGB());
@@ -1530,8 +1530,8 @@
DocumentBuilderFactory.newInstance().newDocumentBuilder();
}
InputStream inputStream =
- (InputStream)AccessController.doPrivileged(new PrivilegedAction() {
- public Object run() {
+ AccessController.doPrivileged(new PrivilegedAction() {
+ public InputStream run() {
try {
return new BufferedInputStream(xmlFile.openStream());
} catch (IOException ex) {
@@ -1551,7 +1551,7 @@
protected Node[] getNodesByName(Node parent, String name) {
NodeList nodes = parent.getChildNodes(); // ElementNode
int n = nodes.getLength();
- ArrayList list = new ArrayList();
+ ArrayList list = new ArrayList();
for (int i=0; i < n; i++) {
Node node = nodes.item(i);
if (name.equals(node.getNodeName())) {
@@ -1603,7 +1603,7 @@
String aValue = attrs[a * 2 + 1];
Node attr = nodeAttrs.getNamedItem(aName);
if (attr == null ||
- aValue != null && !aValue.equals((String)attr.getNodeValue())) {
+ aValue != null && !aValue.equals(attr.getNodeValue())) {
matches = false;
break;
}
@@ -1642,7 +1642,7 @@
protected String getStringAttr(NamedNodeMap attrs, String name) {
Node item = attrs.getNamedItem(name);
- return (item != null) ? (String)item.getNodeValue() : null;
+ return (item != null) ? item.getNodeValue() : null;
}
protected boolean getBooleanAttr(Node node, String name, boolean fallback) {
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsFileChooserUI.java
--- a/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsFileChooserUI.java Thu Jan 29 21:46:48 2009 -0800
+++ b/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsFileChooserUI.java Tue Feb 03 22:02:55 2009 -0800
@@ -70,7 +70,6 @@
private JTextField filenameTextField;
private FilePane filePane;
private WindowsPlacesBar placesBar;
- private boolean useShellFolder;
private JButton approveButton;
private JButton cancelButton;
@@ -210,10 +209,6 @@
public ListSelectionListener createListSelectionListener() {
return WindowsFileChooserUI.this.createListSelectionListener(getFileChooser());
}
-
- public boolean usesShellFolder() {
- return useShellFolder;
- }
}
public void installComponents(JFileChooser fc) {
@@ -625,15 +620,8 @@
// Decide whether to use the ShellFolder class to populate shortcut
// panel and combobox.
JFileChooser fc = getFileChooser();
- Boolean prop =
- (Boolean)fc.getClientProperty("FileChooser.useShellFolder");
- if (prop != null) {
- useShellFolder = prop.booleanValue();
- } else {
- useShellFolder = fc.getFileSystemView().equals(FileSystemView.getFileSystemView());
- }
if (OS_VERSION.compareTo(OSInfo.WINDOWS_ME) >= 0) {
- if (useShellFolder) {
+ if (FilePane.usesShellFolder(fc)) {
if (placesBar == null && !UIManager.getBoolean("FileChooser.noPlacesBar")) {
placesBar = new WindowsPlacesBar(fc, XPStyle.getXP() != null);
fc.add(placesBar, BorderLayout.BEFORE_LINE_BEGINS);
@@ -1149,6 +1137,8 @@
return;
}
+ boolean useShellFolder = FilePane.usesShellFolder(chooser);
+
directories.clear();
File[] baseFolders;
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsLookAndFeel.java
--- a/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsLookAndFeel.java Thu Jan 29 21:46:48 2009 -0800
+++ b/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsLookAndFeel.java Tue Feb 03 22:02:55 2009 -0800
@@ -1554,10 +1554,10 @@
"Tree.selectionBackground", SelectionBackgroundColor,
"Tree.expandedIcon", treeExpandedIcon,
"Tree.collapsedIcon", treeCollapsedIcon,
- "Tree.openIcon", new ActiveWindowsIcon("win.icon.shellIconBPP", "shell32Icon 5",
- (Icon)table.get("Tree.openIcon")),
- "Tree.closedIcon", new ActiveWindowsIcon("win.icon.shellIconBPP", "shell32Icon 4",
- (Icon)table.get("Tree.closedIcon")),
+ "Tree.openIcon", new ActiveWindowsIcon("win.icon.shellIconBPP",
+ "shell32Icon 5", "icons/TreeOpen.gif"),
+ "Tree.closedIcon", new ActiveWindowsIcon("win.icon.shellIconBPP",
+ "shell32Icon 4", "icons/TreeClosed.gif"),
"Tree.focusInputMap",
new UIDefaults.LazyInputMap(new Object[] {
"ADD", "expand",
@@ -2205,21 +2205,21 @@
*/
private class ActiveWindowsIcon implements UIDefaults.ActiveValue {
private Icon icon;
- private Icon fallback;
private String nativeImageName;
+ private String fallbackName;
private DesktopProperty desktopProperty;
ActiveWindowsIcon(String desktopPropertyName,
- String nativeImageName, Icon fallback) {
+ String nativeImageName, String fallbackName) {
this.nativeImageName = nativeImageName;
- this.fallback = fallback;
+ this.fallbackName = fallbackName;
if (OSInfo.getOSType() == OSInfo.OSType.WINDOWS &&
OSInfo.getWindowsVersion().compareTo(OSInfo.WINDOWS_XP) < 0) {
// This desktop property is needed to trigger reloading the icon.
// It is kept in member variable to avoid GC.
this.desktopProperty = new TriggerDesktopProperty(desktopPropertyName) {
- protected void updateUI() {
+ @Override protected void updateUI() {
icon = null;
super.updateUI();
}
@@ -2227,6 +2227,7 @@
}
}
+ @Override
public Object createValue(UIDefaults table) {
if (icon == null) {
Image image = (Image)ShellFolder.get(nativeImageName);
@@ -2234,8 +2235,11 @@
icon = new ImageIconUIResource(image);
}
}
- if (icon == null && fallback != null) {
- icon = fallback;
+ if (icon == null && fallbackName != null) {
+ UIDefaults.LazyValue fallback = (UIDefaults.LazyValue)
+ SwingUtilities2.makeIcon(WindowsLookAndFeel.class,
+ BasicLookAndFeel.class, fallbackName);
+ icon = (Icon) fallback.createValue(table);
}
return icon;
}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/AbstractMidiDevice.java
--- a/jdk/src/share/classes/com/sun/media/sound/AbstractMidiDevice.java Thu Jan 29 21:46:48 2009 -0800
+++ b/jdk/src/share/classes/com/sun/media/sound/AbstractMidiDevice.java Tue Feb 03 22:02:55 2009 -0800
@@ -75,13 +75,6 @@
/**
* This is the device handle returned from native code
*/
- /*
- * $$rratta Solaris 64 bit holds pointer must be long
- *
- * $$mp 2003-08-07:
- * 'id' is a really bad name. The variable should
- * be called nativePointer or something similar.
- */
protected long id = 0;
@@ -586,7 +579,6 @@
private ArrayList transmitters = new ArrayList();
private MidiOutDevice.MidiOutReceiver midiOutReceiver;
- private MixerSynth.SynthReceiver mixerSynthReceiver;
// how many transmitters must be present for optimized
// handling
@@ -621,22 +613,14 @@
if (midiOutReceiver == oldR) {
midiOutReceiver = null;
}
- if (mixerSynthReceiver == oldR) {
- mixerSynthReceiver = null;
- }
if (newR != null) {
if ((newR instanceof MidiOutDevice.MidiOutReceiver)
&& (midiOutReceiver == null)) {
midiOutReceiver = ((MidiOutDevice.MidiOutReceiver) newR);
}
- if ((newR instanceof MixerSynth.SynthReceiver)
- && (mixerSynthReceiver == null)) {
- mixerSynthReceiver = ((MixerSynth.SynthReceiver) newR);
- }
}
optimizedReceiverCount =
- ((midiOutReceiver!=null)?1:0)
- + ((mixerSynthReceiver!=null)?1:0);
+ ((midiOutReceiver!=null)?1:0);
}
// more potential for optimization here
}
@@ -670,10 +654,6 @@
if (TRACE_TRANSMITTER) Printer.println("Sending packed message to MidiOutReceiver");
midiOutReceiver.sendPackedMidiMessage(packedMessage, timeStamp);
}
- if (mixerSynthReceiver != null) {
- if (TRACE_TRANSMITTER) Printer.println("Sending packed message to MixerSynthReceiver");
- mixerSynthReceiver.sendPackedMidiMessage(packedMessage, timeStamp);
- }
} else {
if (TRACE_TRANSMITTER) Printer.println("Sending packed message to "+size+" transmitter's receivers");
for (int i = 0; i < size; i++) {
@@ -682,9 +662,6 @@
if (optimizedReceiverCount > 0) {
if (receiver instanceof MidiOutDevice.MidiOutReceiver) {
((MidiOutDevice.MidiOutReceiver) receiver).sendPackedMidiMessage(packedMessage, timeStamp);
- }
- else if (receiver instanceof MixerSynth.SynthReceiver) {
- ((MixerSynth.SynthReceiver) receiver).sendPackedMidiMessage(packedMessage, timeStamp);
} else {
receiver.send(new FastShortMessage(packedMessage), timeStamp);
}
@@ -739,10 +716,6 @@
if (TRACE_TRANSMITTER) Printer.println("Sending MIDI message to MidiOutReceiver");
midiOutReceiver.send(message, timeStamp);
}
- if (mixerSynthReceiver != null) {
- if (TRACE_TRANSMITTER) Printer.println("Sending MIDI message to MixerSynthReceiver");
- mixerSynthReceiver.send(message, timeStamp);
- }
} else {
if (TRACE_TRANSMITTER) Printer.println("Sending MIDI message to "+size+" transmitter's receivers");
for (int i = 0; i < size; i++) {
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/AudioFileSoundbankReader.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/AudioFileSoundbankReader.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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 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 {
+ try {
+ byte[] buffer;
+ if (ais.getFrameLength() == -1) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ byte[] buff = new byte[1024
+ - (1024 % ais.getFormat().getFrameSize())];
+ int ret;
+ while ((ret = ais.read(buff)) != -1) {
+ baos.write(buff, 0, ret);
+ }
+ ais.close();
+ buffer = baos.toByteArray();
+ } else {
+ buffer = new byte[(int) (ais.getFrameLength()
+ * ais.getFormat().getFrameSize())];
+ 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;
+ }
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/AudioFloatConverter.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/AudioFloatConverter.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,1058 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.media.sound;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.DoubleBuffer;
+import java.nio.FloatBuffer;
+
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.AudioFormat.Encoding;
+
+/**
+ * This class is used to convert between 8,16,24,32,32+ bit signed/unsigned
+ * big/litle endian fixed/floating point byte buffers and float buffers.
+ *
+ * @author Karl Helgason
+ */
+public abstract class AudioFloatConverter {
+
+ public static final Encoding PCM_FLOAT = new Encoding("PCM_FLOAT");
+
+ /***************************************************************************
+ *
+ * LSB Filter, used filter least significant byte in samples arrays.
+ *
+ * Is used filter out data in lsb byte when SampleSizeInBits is not
+ * dividable by 8.
+ *
+ **************************************************************************/
+
+ private static class AudioFloatLSBFilter extends AudioFloatConverter {
+
+ private AudioFloatConverter converter;
+
+ final private int offset;
+
+ final private int stepsize;
+
+ final private byte mask;
+
+ private byte[] mask_buffer;
+
+ public AudioFloatLSBFilter(AudioFloatConverter converter,
+ AudioFormat format) {
+ int bits = format.getSampleSizeInBits();
+ boolean bigEndian = format.isBigEndian();
+ this.converter = converter;
+ stepsize = (bits + 7) / 8;
+ offset = bigEndian ? (stepsize - 1) : 0;
+ int lsb_bits = bits % 8;
+ if (lsb_bits == 0)
+ mask = (byte) 0x00;
+ else if (lsb_bits == 1)
+ mask = (byte) 0x80;
+ else if (lsb_bits == 2)
+ mask = (byte) 0xC0;
+ else if (lsb_bits == 3)
+ mask = (byte) 0xE0;
+ else if (lsb_bits == 4)
+ mask = (byte) 0xF0;
+ else if (lsb_bits == 5)
+ mask = (byte) 0xF8;
+ else if (lsb_bits == 6)
+ mask = (byte) 0xFC;
+ else if (lsb_bits == 7)
+ mask = (byte) 0xFE;
+ else
+ mask = (byte) 0xFF;
+ }
+
+ public byte[] toByteArray(float[] in_buff, int in_offset, int in_len,
+ byte[] out_buff, int out_offset) {
+ byte[] ret = converter.toByteArray(in_buff, in_offset, in_len,
+ out_buff, out_offset);
+
+ int out_offset_end = in_len * stepsize;
+ for (int i = out_offset + offset; i < out_offset_end; i += stepsize) {
+ out_buff[i] = (byte) (out_buff[i] & mask);
+ }
+
+ return ret;
+ }
+
+ public float[] toFloatArray(byte[] in_buff, int in_offset,
+ float[] out_buff, int out_offset, int out_len) {
+ if (mask_buffer == null || mask_buffer.length < in_buff.length)
+ mask_buffer = new byte[in_buff.length];
+ System.arraycopy(in_buff, 0, mask_buffer, 0, in_buff.length);
+ int in_offset_end = out_len * stepsize;
+ for (int i = in_offset + offset; i < in_offset_end; i += stepsize) {
+ mask_buffer[i] = (byte) (mask_buffer[i] & mask);
+ }
+ float[] ret = converter.toFloatArray(mask_buffer, in_offset,
+ out_buff, out_offset, out_len);
+ return ret;
+ }
+
+ }
+
+ /***************************************************************************
+ *
+ * 64 bit float, little/big-endian
+ *
+ **************************************************************************/
+
+ // PCM 64 bit float, little-endian
+ private static class AudioFloatConversion64L extends AudioFloatConverter {
+ ByteBuffer bytebuffer = null;
+
+ DoubleBuffer floatbuffer = null;
+
+ double[] double_buff = null;
+
+ public float[] toFloatArray(byte[] in_buff, int in_offset,
+ float[] out_buff, int out_offset, int out_len) {
+ int in_len = out_len * 8;
+ if (bytebuffer == null || bytebuffer.capacity() < in_len) {
+ bytebuffer = ByteBuffer.allocate(in_len).order(
+ ByteOrder.LITTLE_ENDIAN);
+ floatbuffer = bytebuffer.asDoubleBuffer();
+ }
+ bytebuffer.position(0);
+ floatbuffer.position(0);
+ bytebuffer.put(in_buff, in_offset, in_len);
+ if (double_buff == null
+ || double_buff.length < out_len + out_offset)
+ double_buff = new double[out_len + out_offset];
+ floatbuffer.get(double_buff, out_offset, out_len);
+ int out_offset_end = out_offset + out_len;
+ for (int i = out_offset; i < out_offset_end; i++) {
+ out_buff[i] = (float) double_buff[i];
+ }
+ return out_buff;
+ }
+
+ public byte[] toByteArray(float[] in_buff, int in_offset, int in_len,
+ byte[] out_buff, int out_offset) {
+ int out_len = in_len * 8;
+ if (bytebuffer == null || bytebuffer.capacity() < out_len) {
+ bytebuffer = ByteBuffer.allocate(out_len).order(
+ ByteOrder.LITTLE_ENDIAN);
+ floatbuffer = bytebuffer.asDoubleBuffer();
+ }
+ floatbuffer.position(0);
+ bytebuffer.position(0);
+ if (double_buff == null || double_buff.length < in_offset + in_len)
+ double_buff = new double[in_offset + in_len];
+ int in_offset_end = in_offset + in_len;
+ for (int i = in_offset; i < in_offset_end; i++) {
+ double_buff[i] = in_buff[i];
+ }
+ floatbuffer.put(double_buff, in_offset, in_len);
+ bytebuffer.get(out_buff, out_offset, out_len);
+ return out_buff;
+ }
+ }
+
+ // PCM 64 bit float, big-endian
+ private static class AudioFloatConversion64B extends AudioFloatConverter {
+ ByteBuffer bytebuffer = null;
+
+ DoubleBuffer floatbuffer = null;
+
+ double[] double_buff = null;
+
+ public float[] toFloatArray(byte[] in_buff, int in_offset,
+ float[] out_buff, int out_offset, int out_len) {
+ int in_len = out_len * 8;
+ if (bytebuffer == null || bytebuffer.capacity() < in_len) {
+ bytebuffer = ByteBuffer.allocate(in_len).order(
+ ByteOrder.BIG_ENDIAN);
+ floatbuffer = bytebuffer.asDoubleBuffer();
+ }
+ bytebuffer.position(0);
+ floatbuffer.position(0);
+ bytebuffer.put(in_buff, in_offset, in_len);
+ if (double_buff == null
+ || double_buff.length < out_len + out_offset)
+ double_buff = new double[out_len + out_offset];
+ floatbuffer.get(double_buff, out_offset, out_len);
+ int out_offset_end = out_offset + out_len;
+ for (int i = out_offset; i < out_offset_end; i++) {
+ out_buff[i] = (float) double_buff[i];
+ }
+ return out_buff;
+ }
+
+ public byte[] toByteArray(float[] in_buff, int in_offset, int in_len,
+ byte[] out_buff, int out_offset) {
+ int out_len = in_len * 8;
+ if (bytebuffer == null || bytebuffer.capacity() < out_len) {
+ bytebuffer = ByteBuffer.allocate(out_len).order(
+ ByteOrder.BIG_ENDIAN);
+ floatbuffer = bytebuffer.asDoubleBuffer();
+ }
+ floatbuffer.position(0);
+ bytebuffer.position(0);
+ if (double_buff == null || double_buff.length < in_offset + in_len)
+ double_buff = new double[in_offset + in_len];
+ int in_offset_end = in_offset + in_len;
+ for (int i = in_offset; i < in_offset_end; i++) {
+ double_buff[i] = in_buff[i];
+ }
+ floatbuffer.put(double_buff, in_offset, in_len);
+ bytebuffer.get(out_buff, out_offset, out_len);
+ return out_buff;
+ }
+ }
+
+ /***************************************************************************
+ *
+ * 32 bit float, little/big-endian
+ *
+ **************************************************************************/
+
+ // PCM 32 bit float, little-endian
+ private static class AudioFloatConversion32L extends AudioFloatConverter {
+ ByteBuffer bytebuffer = null;
+
+ FloatBuffer floatbuffer = null;
+
+ public float[] toFloatArray(byte[] in_buff, int in_offset,
+ float[] out_buff, int out_offset, int out_len) {
+ int in_len = out_len * 4;
+ if (bytebuffer == null || bytebuffer.capacity() < in_len) {
+ bytebuffer = ByteBuffer.allocate(in_len).order(
+ ByteOrder.LITTLE_ENDIAN);
+ floatbuffer = bytebuffer.asFloatBuffer();
+ }
+ bytebuffer.position(0);
+ floatbuffer.position(0);
+ bytebuffer.put(in_buff, in_offset, in_len);
+ floatbuffer.get(out_buff, out_offset, out_len);
+ return out_buff;
+ }
+
+ public byte[] toByteArray(float[] in_buff, int in_offset, int in_len,
+ byte[] out_buff, int out_offset) {
+ int out_len = in_len * 4;
+ if (bytebuffer == null || bytebuffer.capacity() < out_len) {
+ bytebuffer = ByteBuffer.allocate(out_len).order(
+ ByteOrder.LITTLE_ENDIAN);
+ floatbuffer = bytebuffer.asFloatBuffer();
+ }
+ floatbuffer.position(0);
+ bytebuffer.position(0);
+ floatbuffer.put(in_buff, in_offset, in_len);
+ bytebuffer.get(out_buff, out_offset, out_len);
+ return out_buff;
+ }
+ }
+
+ // PCM 32 bit float, big-endian
+ private static class AudioFloatConversion32B extends AudioFloatConverter {
+ ByteBuffer bytebuffer = null;
+
+ FloatBuffer floatbuffer = null;
+
+ public float[] toFloatArray(byte[] in_buff, int in_offset,
+ float[] out_buff, int out_offset, int out_len) {
+ int in_len = out_len * 4;
+ if (bytebuffer == null || bytebuffer.capacity() < in_len) {
+ bytebuffer = ByteBuffer.allocate(in_len).order(
+ ByteOrder.BIG_ENDIAN);
+ floatbuffer = bytebuffer.asFloatBuffer();
+ }
+ bytebuffer.position(0);
+ floatbuffer.position(0);
+ bytebuffer.put(in_buff, in_offset, in_len);
+ floatbuffer.get(out_buff, out_offset, out_len);
+ return out_buff;
+ }
+
+ public byte[] toByteArray(float[] in_buff, int in_offset, int in_len,
+ byte[] out_buff, int out_offset) {
+ int out_len = in_len * 4;
+ if (bytebuffer == null || bytebuffer.capacity() < out_len) {
+ bytebuffer = ByteBuffer.allocate(out_len).order(
+ ByteOrder.BIG_ENDIAN);
+ floatbuffer = bytebuffer.asFloatBuffer();
+ }
+ floatbuffer.position(0);
+ bytebuffer.position(0);
+ floatbuffer.put(in_buff, in_offset, in_len);
+ bytebuffer.get(out_buff, out_offset, out_len);
+ return out_buff;
+ }
+ }
+
+ /***************************************************************************
+ *
+ * 8 bit signed/unsigned
+ *
+ **************************************************************************/
+
+ // PCM 8 bit, signed
+ private static class AudioFloatConversion8S extends AudioFloatConverter {
+ public float[] toFloatArray(byte[] in_buff, int in_offset,
+ float[] out_buff, int out_offset, int out_len) {
+ int ix = in_offset;
+ int ox = out_offset;
+ for (int i = 0; i < out_len; i++)
+ out_buff[ox++] = in_buff[ix++] * (1.0f / 127.0f);
+ return out_buff;
+ }
+
+ public byte[] toByteArray(float[] in_buff, int in_offset, int in_len,
+ byte[] out_buff, int out_offset) {
+ int ix = in_offset;
+ int ox = out_offset;
+ for (int i = 0; i < in_len; i++)
+ out_buff[ox++] = (byte) (in_buff[ix++] * 127.0f);
+ return out_buff;
+ }
+ }
+
+ // PCM 8 bit, unsigned
+ private static class AudioFloatConversion8U extends AudioFloatConverter {
+ public float[] toFloatArray(byte[] in_buff, int in_offset,
+ float[] out_buff, int out_offset, int out_len) {
+ int ix = in_offset;
+ int ox = out_offset;
+ for (int i = 0; i < out_len; i++)
+ out_buff[ox++] = ((in_buff[ix++] & 0xFF) - 127)
+ * (1.0f / 127.0f);
+ return out_buff;
+ }
+
+ public byte[] toByteArray(float[] in_buff, int in_offset, int in_len,
+ byte[] out_buff, int out_offset) {
+ int ix = in_offset;
+ int ox = out_offset;
+ for (int i = 0; i < in_len; i++)
+ out_buff[ox++] = (byte) (127 + in_buff[ix++] * 127.0f);
+ return out_buff;
+ }
+ }
+
+ /***************************************************************************
+ *
+ * 16 bit signed/unsigned, little/big-endian
+ *
+ **************************************************************************/
+
+ // PCM 16 bit, signed, little-endian
+ private static class AudioFloatConversion16SL extends AudioFloatConverter {
+ public float[] toFloatArray(byte[] in_buff, int in_offset,
+ float[] out_buff, int out_offset, int out_len) {
+ int ix = in_offset;
+ int len = out_offset + out_len;
+ for (int ox = out_offset; ox < len; ox++) {
+ out_buff[ox] = ((short) ((in_buff[ix++] & 0xFF) |
+ (in_buff[ix++] << 8))) * (1.0f / 32767.0f);
+ }
+
+ return out_buff;
+ }
+
+ public byte[] toByteArray(float[] in_buff, int in_offset, int in_len,
+ byte[] out_buff, int out_offset) {
+ int ox = out_offset;
+ int len = in_offset + in_len;
+ for (int ix = in_offset; ix < len; ix++) {
+ int x = (int) (in_buff[ix] * 32767.0);
+ out_buff[ox++] = (byte) x;
+ out_buff[ox++] = (byte) (x >>> 8);
+ }
+ return out_buff;
+ }
+ }
+
+ // PCM 16 bit, signed, big-endian
+ private static class AudioFloatConversion16SB extends AudioFloatConverter {
+ public float[] toFloatArray(byte[] in_buff, int in_offset,
+ float[] out_buff, int out_offset, int out_len) {
+ int ix = in_offset;
+ int ox = out_offset;
+ for (int i = 0; i < out_len; i++) {
+ out_buff[ox++] = ((short) ((in_buff[ix++] << 8) |
+ (in_buff[ix++] & 0xFF))) * (1.0f / 32767.0f);
+ }
+ return out_buff;
+ }
+
+ public byte[] toByteArray(float[] in_buff, int in_offset, int in_len,
+ byte[] out_buff, int out_offset) {
+ int ix = in_offset;
+ int ox = out_offset;
+ for (int i = 0; i < in_len; i++) {
+ int x = (int) (in_buff[ix++] * 32767.0);
+ out_buff[ox++] = (byte) (x >>> 8);
+ out_buff[ox++] = (byte) x;
+ }
+ return out_buff;
+ }
+ }
+
+ // PCM 16 bit, unsigned, little-endian
+ private static class AudioFloatConversion16UL extends AudioFloatConverter {
+ public float[] toFloatArray(byte[] in_buff, int in_offset,
+ float[] out_buff, int out_offset, int out_len) {
+ int ix = in_offset;
+ int ox = out_offset;
+ for (int i = 0; i < out_len; i++) {
+ int x = (in_buff[ix++] & 0xFF) | ((in_buff[ix++] & 0xFF) << 8);
+ out_buff[ox++] = (x - 32767) * (1.0f / 32767.0f);
+ }
+ return out_buff;
+ }
+
+ public byte[] toByteArray(float[] in_buff, int in_offset, int in_len,
+ byte[] out_buff, int out_offset) {
+ int ix = in_offset;
+ int ox = out_offset;
+ for (int i = 0; i < in_len; i++) {
+ int x = 32767 + (int) (in_buff[ix++] * 32767.0);
+ out_buff[ox++] = (byte) x;
+ out_buff[ox++] = (byte) (x >>> 8);
+ }
+ return out_buff;
+ }
+ }
+
+ // PCM 16 bit, unsigned, big-endian
+ private static class AudioFloatConversion16UB extends AudioFloatConverter {
+ public float[] toFloatArray(byte[] in_buff, int in_offset,
+ float[] out_buff, int out_offset, int out_len) {
+ int ix = in_offset;
+ int ox = out_offset;
+ for (int i = 0; i < out_len; i++) {
+ int x = ((in_buff[ix++] & 0xFF) << 8) | (in_buff[ix++] & 0xFF);
+ out_buff[ox++] = (x - 32767) * (1.0f / 32767.0f);
+ }
+ return out_buff;
+ }
+
+ public byte[] toByteArray(float[] in_buff, int in_offset, int in_len,
+ byte[] out_buff, int out_offset) {
+ int ix = in_offset;
+ int ox = out_offset;
+ for (int i = 0; i < in_len; i++) {
+ int x = 32767 + (int) (in_buff[ix++] * 32767.0);
+ out_buff[ox++] = (byte) (x >>> 8);
+ out_buff[ox++] = (byte) x;
+ }
+ return out_buff;
+ }
+ }
+
+ /***************************************************************************
+ *
+ * 24 bit signed/unsigned, little/big-endian
+ *
+ **************************************************************************/
+
+ // PCM 24 bit, signed, little-endian
+ private static class AudioFloatConversion24SL extends AudioFloatConverter {
+ public float[] toFloatArray(byte[] in_buff, int in_offset,
+ float[] out_buff, int out_offset, int out_len) {
+ int ix = in_offset;
+ int ox = out_offset;
+ for (int i = 0; i < out_len; i++) {
+ int x = (in_buff[ix++] & 0xFF) | ((in_buff[ix++] & 0xFF) << 8)
+ | ((in_buff[ix++] & 0xFF) << 16);
+ if (x > 0x7FFFFF)
+ x -= 0x1000000;
+ out_buff[ox++] = x * (1.0f / (float)0x7FFFFF);
+ }
+ return out_buff;
+ }
+
+ public byte[] toByteArray(float[] in_buff, int in_offset, int in_len,
+ byte[] out_buff, int out_offset) {
+ int ix = in_offset;
+ int ox = out_offset;
+ for (int i = 0; i < in_len; i++) {
+ int x = (int) (in_buff[ix++] * (float)0x7FFFFF);
+ if (x < 0)
+ x += 0x1000000;
+ out_buff[ox++] = (byte) x;
+ out_buff[ox++] = (byte) (x >>> 8);
+ out_buff[ox++] = (byte) (x >>> 16);
+ }
+ return out_buff;
+ }
+ }
+
+ // PCM 24 bit, signed, big-endian
+ private static class AudioFloatConversion24SB extends AudioFloatConverter {
+ public float[] toFloatArray(byte[] in_buff, int in_offset,
+ float[] out_buff, int out_offset, int out_len) {
+ int ix = in_offset;
+ int ox = out_offset;
+ for (int i = 0; i < out_len; i++) {
+ int x = ((in_buff[ix++] & 0xFF) << 16)
+ | ((in_buff[ix++] & 0xFF) << 8) | (in_buff[ix++] & 0xFF);
+ if (x > 0x7FFFFF)
+ x -= 0x1000000;
+ out_buff[ox++] = x * (1.0f / (float)0x7FFFFF);
+ }
+ return out_buff;
+ }
+
+ public byte[] toByteArray(float[] in_buff, int in_offset, int in_len,
+ byte[] out_buff, int out_offset) {
+ int ix = in_offset;
+ int ox = out_offset;
+ for (int i = 0; i < in_len; i++) {
+ int x = (int) (in_buff[ix++] * (float)0x7FFFFF);
+ if (x < 0)
+ x += 0x1000000;
+ out_buff[ox++] = (byte) (x >>> 16);
+ out_buff[ox++] = (byte) (x >>> 8);
+ out_buff[ox++] = (byte) x;
+ }
+ return out_buff;
+ }
+ }
+
+ // PCM 24 bit, unsigned, little-endian
+ private static class AudioFloatConversion24UL extends AudioFloatConverter {
+ public float[] toFloatArray(byte[] in_buff, int in_offset,
+ float[] out_buff, int out_offset, int out_len) {
+ int ix = in_offset;
+ int ox = out_offset;
+ for (int i = 0; i < out_len; i++) {
+ int x = (in_buff[ix++] & 0xFF) | ((in_buff[ix++] & 0xFF) << 8)
+ | ((in_buff[ix++] & 0xFF) << 16);
+ x -= 0x7FFFFF;
+ out_buff[ox++] = x * (1.0f / (float)0x7FFFFF);
+ }
+ return out_buff;
+ }
+
+ public byte[] toByteArray(float[] in_buff, int in_offset, int in_len,
+ byte[] out_buff, int out_offset) {
+ int ix = in_offset;
+ int ox = out_offset;
+ for (int i = 0; i < in_len; i++) {
+ int x = (int) (in_buff[ix++] * (float)0x7FFFFF);
+ x += 0x7FFFFF;
+ out_buff[ox++] = (byte) x;
+ out_buff[ox++] = (byte) (x >>> 8);
+ out_buff[ox++] = (byte) (x >>> 16);
+ }
+ return out_buff;
+ }
+ }
+
+ // PCM 24 bit, unsigned, big-endian
+ private static class AudioFloatConversion24UB extends AudioFloatConverter {
+ public float[] toFloatArray(byte[] in_buff, int in_offset,
+ float[] out_buff, int out_offset, int out_len) {
+ int ix = in_offset;
+ int ox = out_offset;
+ for (int i = 0; i < out_len; i++) {
+ int x = ((in_buff[ix++] & 0xFF) << 16)
+ | ((in_buff[ix++] & 0xFF) << 8) | (in_buff[ix++] & 0xFF);
+ x -= 0x7FFFFF;
+ out_buff[ox++] = x * (1.0f / (float)0x7FFFFF);
+ }
+ return out_buff;
+ }
+
+ public byte[] toByteArray(float[] in_buff, int in_offset, int in_len,
+ byte[] out_buff, int out_offset) {
+ int ix = in_offset;
+ int ox = out_offset;
+ for (int i = 0; i < in_len; i++) {
+ int x = (int) (in_buff[ix++] * (float)0x7FFFFF);
+ x += 0x7FFFFF;
+ out_buff[ox++] = (byte) (x >>> 16);
+ out_buff[ox++] = (byte) (x >>> 8);
+ out_buff[ox++] = (byte) x;
+ }
+ return out_buff;
+ }
+ }
+
+ /***************************************************************************
+ *
+ * 32 bit signed/unsigned, little/big-endian
+ *
+ **************************************************************************/
+
+ // PCM 32 bit, signed, little-endian
+ private static class AudioFloatConversion32SL extends AudioFloatConverter {
+ public float[] toFloatArray(byte[] in_buff, int in_offset,
+ float[] out_buff, int out_offset, int out_len) {
+ int ix = in_offset;
+ int ox = out_offset;
+ for (int i = 0; i < out_len; i++) {
+ int x = (in_buff[ix++] & 0xFF) | ((in_buff[ix++] & 0xFF) << 8) |
+ ((in_buff[ix++] & 0xFF) << 16) |
+ ((in_buff[ix++] & 0xFF) << 24);
+ out_buff[ox++] = x * (1.0f / (float)0x7FFFFFFF);
+ }
+ return out_buff;
+ }
+
+ public byte[] toByteArray(float[] in_buff, int in_offset, int in_len,
+ byte[] out_buff, int out_offset) {
+ int ix = in_offset;
+ int ox = out_offset;
+ for (int i = 0; i < in_len; i++) {
+ int x = (int) (in_buff[ix++] * (float)0x7FFFFFFF);
+ out_buff[ox++] = (byte) x;
+ out_buff[ox++] = (byte) (x >>> 8);
+ out_buff[ox++] = (byte) (x >>> 16);
+ out_buff[ox++] = (byte) (x >>> 24);
+ }
+ return out_buff;
+ }
+ }
+
+ // PCM 32 bit, signed, big-endian
+ private static class AudioFloatConversion32SB extends AudioFloatConverter {
+ public float[] toFloatArray(byte[] in_buff, int in_offset,
+ float[] out_buff, int out_offset, int out_len) {
+ int ix = in_offset;
+ int ox = out_offset;
+ for (int i = 0; i < out_len; i++) {
+ int x = ((in_buff[ix++] & 0xFF) << 24) |
+ ((in_buff[ix++] & 0xFF) << 16) |
+ ((in_buff[ix++] & 0xFF) << 8) | (in_buff[ix++] & 0xFF);
+ out_buff[ox++] = x * (1.0f / (float)0x7FFFFFFF);
+ }
+ return out_buff;
+ }
+
+ public byte[] toByteArray(float[] in_buff, int in_offset, int in_len,
+ byte[] out_buff, int out_offset) {
+ int ix = in_offset;
+ int ox = out_offset;
+ for (int i = 0; i < in_len; i++) {
+ int x = (int) (in_buff[ix++] * (float)0x7FFFFFFF);
+ out_buff[ox++] = (byte) (x >>> 24);
+ out_buff[ox++] = (byte) (x >>> 16);
+ out_buff[ox++] = (byte) (x >>> 8);
+ out_buff[ox++] = (byte) x;
+ }
+ return out_buff;
+ }
+ }
+
+ // PCM 32 bit, unsigned, little-endian
+ private static class AudioFloatConversion32UL extends AudioFloatConverter {
+ public float[] toFloatArray(byte[] in_buff, int in_offset,
+ float[] out_buff, int out_offset, int out_len) {
+ int ix = in_offset;
+ int ox = out_offset;
+ for (int i = 0; i < out_len; i++) {
+ int x = (in_buff[ix++] & 0xFF) | ((in_buff[ix++] & 0xFF) << 8) |
+ ((in_buff[ix++] & 0xFF) << 16) |
+ ((in_buff[ix++] & 0xFF) << 24);
+ x -= 0x7FFFFFFF;
+ out_buff[ox++] = x * (1.0f / (float)0x7FFFFFFF);
+ }
+ return out_buff;
+ }
+
+ public byte[] toByteArray(float[] in_buff, int in_offset, int in_len,
+ byte[] out_buff, int out_offset) {
+ int ix = in_offset;
+ int ox = out_offset;
+ for (int i = 0; i < in_len; i++) {
+ int x = (int) (in_buff[ix++] * (float)0x7FFFFFFF);
+ x += 0x7FFFFFFF;
+ out_buff[ox++] = (byte) x;
+ out_buff[ox++] = (byte) (x >>> 8);
+ out_buff[ox++] = (byte) (x >>> 16);
+ out_buff[ox++] = (byte) (x >>> 24);
+ }
+ return out_buff;
+ }
+ }
+
+ // PCM 32 bit, unsigned, big-endian
+ private static class AudioFloatConversion32UB extends AudioFloatConverter {
+
+ public float[] toFloatArray(byte[] in_buff, int in_offset,
+ float[] out_buff, int out_offset, int out_len) {
+ int ix = in_offset;
+ int ox = out_offset;
+ for (int i = 0; i < out_len; i++) {
+ int x = ((in_buff[ix++] & 0xFF) << 24) |
+ ((in_buff[ix++] & 0xFF) << 16) |
+ ((in_buff[ix++] & 0xFF) << 8) | (in_buff[ix++] & 0xFF);
+ x -= 0x7FFFFFFF;
+ out_buff[ox++] = x * (1.0f / (float)0x7FFFFFFF);
+ }
+ return out_buff;
+ }
+
+ public byte[] toByteArray(float[] in_buff, int in_offset, int in_len,
+ byte[] out_buff, int out_offset) {
+ int ix = in_offset;
+ int ox = out_offset;
+ for (int i = 0; i < in_len; i++) {
+ int x = (int) (in_buff[ix++] * (float)0x7FFFFFFF);
+ x += 0x7FFFFFFF;
+ out_buff[ox++] = (byte) (x >>> 24);
+ out_buff[ox++] = (byte) (x >>> 16);
+ out_buff[ox++] = (byte) (x >>> 8);
+ out_buff[ox++] = (byte) x;
+ }
+ return out_buff;
+ }
+ }
+
+ /***************************************************************************
+ *
+ * 32+ bit signed/unsigned, little/big-endian
+ *
+ **************************************************************************/
+
+ // PCM 32+ bit, signed, little-endian
+ private static class AudioFloatConversion32xSL extends AudioFloatConverter {
+
+ final int xbytes;
+
+ public AudioFloatConversion32xSL(int xbytes) {
+ this.xbytes = xbytes;
+ }
+
+ public float[] toFloatArray(byte[] in_buff, int in_offset,
+ float[] out_buff, int out_offset, int out_len) {
+ int ix = in_offset;
+ int ox = out_offset;
+ for (int i = 0; i < out_len; i++) {
+ ix += xbytes;
+ int x = (in_buff[ix++] & 0xFF) | ((in_buff[ix++] & 0xFF) << 8)
+ | ((in_buff[ix++] & 0xFF) << 16)
+ | ((in_buff[ix++] & 0xFF) << 24);
+ out_buff[ox++] = x * (1.0f / (float)0x7FFFFFFF);
+ }
+ return out_buff;
+ }
+
+ public byte[] toByteArray(float[] in_buff, int in_offset, int in_len,
+ byte[] out_buff, int out_offset) {
+ int ix = in_offset;
+ int ox = out_offset;
+ for (int i = 0; i < in_len; i++) {
+ int x = (int) (in_buff[ix++] * (float)0x7FFFFFFF);
+ for (int j = 0; j < xbytes; j++) {
+ out_buff[ox++] = 0;
+ }
+ out_buff[ox++] = (byte) x;
+ out_buff[ox++] = (byte) (x >>> 8);
+ out_buff[ox++] = (byte) (x >>> 16);
+ out_buff[ox++] = (byte) (x >>> 24);
+ }
+ return out_buff;
+ }
+ }
+
+ // PCM 32+ bit, signed, big-endian
+ private static class AudioFloatConversion32xSB extends AudioFloatConverter {
+
+ final int xbytes;
+
+ public AudioFloatConversion32xSB(int xbytes) {
+ this.xbytes = xbytes;
+ }
+
+ public float[] toFloatArray(byte[] in_buff, int in_offset,
+ float[] out_buff, int out_offset, int out_len) {
+ int ix = in_offset;
+ int ox = out_offset;
+ for (int i = 0; i < out_len; i++) {
+ int x = ((in_buff[ix++] & 0xFF) << 24)
+ | ((in_buff[ix++] & 0xFF) << 16)
+ | ((in_buff[ix++] & 0xFF) << 8)
+ | (in_buff[ix++] & 0xFF);
+ ix += xbytes;
+ out_buff[ox++] = x * (1.0f / (float)0x7FFFFFFF);
+ }
+ return out_buff;
+ }
+
+ public byte[] toByteArray(float[] in_buff, int in_offset, int in_len,
+ byte[] out_buff, int out_offset) {
+ int ix = in_offset;
+ int ox = out_offset;
+ for (int i = 0; i < in_len; i++) {
+ int x = (int) (in_buff[ix++] * (float)0x7FFFFFFF);
+ out_buff[ox++] = (byte) (x >>> 24);
+ out_buff[ox++] = (byte) (x >>> 16);
+ out_buff[ox++] = (byte) (x >>> 8);
+ out_buff[ox++] = (byte) x;
+ for (int j = 0; j < xbytes; j++) {
+ out_buff[ox++] = 0;
+ }
+ }
+ return out_buff;
+ }
+ }
+
+ // PCM 32+ bit, unsigned, little-endian
+ private static class AudioFloatConversion32xUL extends AudioFloatConverter {
+
+ final int xbytes;
+
+ public AudioFloatConversion32xUL(int xbytes) {
+ this.xbytes = xbytes;
+ }
+
+ public float[] toFloatArray(byte[] in_buff, int in_offset,
+ float[] out_buff, int out_offset, int out_len) {
+ int ix = in_offset;
+ int ox = out_offset;
+ for (int i = 0; i < out_len; i++) {
+ ix += xbytes;
+ int x = (in_buff[ix++] & 0xFF) | ((in_buff[ix++] & 0xFF) << 8)
+ | ((in_buff[ix++] & 0xFF) << 16)
+ | ((in_buff[ix++] & 0xFF) << 24);
+ x -= 0x7FFFFFFF;
+ out_buff[ox++] = x * (1.0f / (float)0x7FFFFFFF);
+ }
+ return out_buff;
+ }
+
+ public byte[] toByteArray(float[] in_buff, int in_offset, int in_len,
+ byte[] out_buff, int out_offset) {
+ int ix = in_offset;
+ int ox = out_offset;
+ for (int i = 0; i < in_len; i++) {
+ int x = (int) (in_buff[ix++] * (float)0x7FFFFFFF);
+ x += 0x7FFFFFFF;
+ for (int j = 0; j < xbytes; j++) {
+ out_buff[ox++] = 0;
+ }
+ out_buff[ox++] = (byte) x;
+ out_buff[ox++] = (byte) (x >>> 8);
+ out_buff[ox++] = (byte) (x >>> 16);
+ out_buff[ox++] = (byte) (x >>> 24);
+ }
+ return out_buff;
+ }
+ }
+
+ // PCM 32+ bit, unsigned, big-endian
+ private static class AudioFloatConversion32xUB extends AudioFloatConverter {
+
+ final int xbytes;
+
+ public AudioFloatConversion32xUB(int xbytes) {
+ this.xbytes = xbytes;
+ }
+
+ public float[] toFloatArray(byte[] in_buff, int in_offset,
+ float[] out_buff, int out_offset, int out_len) {
+ int ix = in_offset;
+ int ox = out_offset;
+ for (int i = 0; i < out_len; i++) {
+ int x = ((in_buff[ix++] & 0xFF) << 24) |
+ ((in_buff[ix++] & 0xFF) << 16) |
+ ((in_buff[ix++] & 0xFF) << 8) | (in_buff[ix++] & 0xFF);
+ ix += xbytes;
+ x -= 2147483647;
+ out_buff[ox++] = x * (1.0f / 2147483647.0f);
+ }
+ return out_buff;
+ }
+
+ public byte[] toByteArray(float[] in_buff, int in_offset, int in_len,
+ byte[] out_buff, int out_offset) {
+ int ix = in_offset;
+ int ox = out_offset;
+ for (int i = 0; i < in_len; i++) {
+ int x = (int) (in_buff[ix++] * 2147483647.0);
+ x += 2147483647;
+ out_buff[ox++] = (byte) (x >>> 24);
+ out_buff[ox++] = (byte) (x >>> 16);
+ out_buff[ox++] = (byte) (x >>> 8);
+ out_buff[ox++] = (byte) x;
+ for (int j = 0; j < xbytes; j++) {
+ out_buff[ox++] = 0;
+ }
+ }
+ return out_buff;
+ }
+ }
+
+ public static AudioFloatConverter getConverter(AudioFormat format) {
+ AudioFloatConverter conv = null;
+ if (format.getFrameSize() == 0)
+ return null;
+ if (format.getFrameSize() !=
+ ((format.getSampleSizeInBits() + 7) / 8) * format.getChannels()) {
+ return null;
+ }
+ if (format.getEncoding().equals(Encoding.PCM_SIGNED)) {
+ if (format.isBigEndian()) {
+ if (format.getSampleSizeInBits() <= 8) {
+ conv = new AudioFloatConversion8S();
+ } else if (format.getSampleSizeInBits() > 8 &&
+ format.getSampleSizeInBits() <= 16) {
+ conv = new AudioFloatConversion16SB();
+ } else if (format.getSampleSizeInBits() > 16 &&
+ format.getSampleSizeInBits() <= 24) {
+ conv = new AudioFloatConversion24SB();
+ } else if (format.getSampleSizeInBits() > 24 &&
+ format.getSampleSizeInBits() <= 32) {
+ conv = new AudioFloatConversion32SB();
+ } else if (format.getSampleSizeInBits() > 32) {
+ conv = new AudioFloatConversion32xSB(((format
+ .getSampleSizeInBits() + 7) / 8) - 4);
+ }
+ } else {
+ if (format.getSampleSizeInBits() <= 8) {
+ conv = new AudioFloatConversion8S();
+ } else if (format.getSampleSizeInBits() > 8 &&
+ format.getSampleSizeInBits() <= 16) {
+ conv = new AudioFloatConversion16SL();
+ } else if (format.getSampleSizeInBits() > 16 &&
+ format.getSampleSizeInBits() <= 24) {
+ conv = new AudioFloatConversion24SL();
+ } else if (format.getSampleSizeInBits() > 24 &&
+ format.getSampleSizeInBits() <= 32) {
+ conv = new AudioFloatConversion32SL();
+ } else if (format.getSampleSizeInBits() > 32) {
+ conv = new AudioFloatConversion32xSL(((format
+ .getSampleSizeInBits() + 7) / 8) - 4);
+ }
+ }
+ } else if (format.getEncoding().equals(Encoding.PCM_UNSIGNED)) {
+ if (format.isBigEndian()) {
+ if (format.getSampleSizeInBits() <= 8) {
+ conv = new AudioFloatConversion8U();
+ } else if (format.getSampleSizeInBits() > 8 &&
+ format.getSampleSizeInBits() <= 16) {
+ conv = new AudioFloatConversion16UB();
+ } else if (format.getSampleSizeInBits() > 16 &&
+ format.getSampleSizeInBits() <= 24) {
+ conv = new AudioFloatConversion24UB();
+ } else if (format.getSampleSizeInBits() > 24 &&
+ format.getSampleSizeInBits() <= 32) {
+ conv = new AudioFloatConversion32UB();
+ } else if (format.getSampleSizeInBits() > 32) {
+ conv = new AudioFloatConversion32xUB(((
+ format.getSampleSizeInBits() + 7) / 8) - 4);
+ }
+ } else {
+ if (format.getSampleSizeInBits() <= 8) {
+ conv = new AudioFloatConversion8U();
+ } else if (format.getSampleSizeInBits() > 8 &&
+ format.getSampleSizeInBits() <= 16) {
+ conv = new AudioFloatConversion16UL();
+ } else if (format.getSampleSizeInBits() > 16 &&
+ format.getSampleSizeInBits() <= 24) {
+ conv = new AudioFloatConversion24UL();
+ } else if (format.getSampleSizeInBits() > 24 &&
+ format.getSampleSizeInBits() <= 32) {
+ conv = new AudioFloatConversion32UL();
+ } else if (format.getSampleSizeInBits() > 32) {
+ conv = new AudioFloatConversion32xUL(((
+ format.getSampleSizeInBits() + 7) / 8) - 4);
+ }
+ }
+ } else if (format.getEncoding().equals(PCM_FLOAT)) {
+ if (format.getSampleSizeInBits() == 32) {
+ if (format.isBigEndian())
+ conv = new AudioFloatConversion32B();
+ else
+ conv = new AudioFloatConversion32L();
+ } else if (format.getSampleSizeInBits() == 64) {
+ if (format.isBigEndian())
+ conv = new AudioFloatConversion64B();
+ else
+ conv = new AudioFloatConversion64L();
+ }
+
+ }
+
+ if ((format.getEncoding().equals(Encoding.PCM_SIGNED) ||
+ format.getEncoding().equals(Encoding.PCM_UNSIGNED)) &&
+ (format.getSampleSizeInBits() % 8 != 0)) {
+ conv = new AudioFloatLSBFilter(conv, format);
+ }
+
+ if (conv != null)
+ conv.format = format;
+ return conv;
+ }
+
+ private AudioFormat format;
+
+ public AudioFormat getFormat() {
+ return format;
+ }
+
+ public abstract float[] toFloatArray(byte[] in_buff, int in_offset,
+ float[] out_buff, int out_offset, int out_len);
+
+ public float[] toFloatArray(byte[] in_buff, float[] out_buff,
+ int out_offset, int out_len) {
+ return toFloatArray(in_buff, 0, out_buff, out_offset, out_len);
+ }
+
+ public float[] toFloatArray(byte[] in_buff, int in_offset,
+ float[] out_buff, int out_len) {
+ return toFloatArray(in_buff, in_offset, out_buff, 0, out_len);
+ }
+
+ public float[] toFloatArray(byte[] in_buff, float[] out_buff, int out_len) {
+ return toFloatArray(in_buff, 0, out_buff, 0, out_len);
+ }
+
+ public float[] toFloatArray(byte[] in_buff, float[] out_buff) {
+ return toFloatArray(in_buff, 0, out_buff, 0, out_buff.length);
+ }
+
+ public abstract byte[] toByteArray(float[] in_buff, int in_offset,
+ int in_len, byte[] out_buff, int out_offset);
+
+ public byte[] toByteArray(float[] in_buff, int in_len, byte[] out_buff,
+ int out_offset) {
+ return toByteArray(in_buff, 0, in_len, out_buff, out_offset);
+ }
+
+ public byte[] toByteArray(float[] in_buff, int in_offset, int in_len,
+ byte[] out_buff) {
+ return toByteArray(in_buff, in_offset, in_len, out_buff, 0);
+ }
+
+ public byte[] toByteArray(float[] in_buff, int in_len, byte[] out_buff) {
+ return toByteArray(in_buff, 0, in_len, out_buff, 0);
+ }
+
+ public byte[] toByteArray(float[] in_buff, byte[] out_buff) {
+ return toByteArray(in_buff, 0, in_buff.length, out_buff, 0);
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/AudioFloatFormatConverter.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/AudioFloatFormatConverter.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,617 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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 class AudioFloatFormatConverter extends FormatConversionProvider {
+
+ private static class AudioFloatFormatConverterInputStream extends
+ InputStream {
+ private AudioFloatConverter converter;
+
+ private AudioFloatInputStream stream;
+
+ private float[] readfloatbuffer;
+
+ private int fsize = 0;
+
+ public 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 int targetChannels;
+
+ private int sourceChannels;
+
+ private AudioFloatInputStream ais;
+
+ private AudioFormat targetFormat;
+
+ private float[] conversion_buffer;
+
+ public 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 AudioFloatInputStream ais;
+
+ private AudioFormat targetFormat;
+
+ private float[] skipbuffer;
+
+ private SoftAbstractResampler resampler;
+
+ private float[] pitch = new float[1];
+
+ private float[] ibuffer2;
+
+ private float[][] ibuffer;
+
+ private float ibuffer_index = 0;
+
+ private int ibuffer_len = 0;
+
+ private int nrofchannels = 0;
+
+ private float[][] cbuffer;
+
+ private int buffer_len = 512;
+
+ private int pad;
+
+ private int pad2;
+
+ private float[] ix = new float[1];
+
+ private int[] ox = new int[1];
+
+ private float[][] mark_ibuffer = null;
+
+ private float mark_ibuffer_index = 0;
+
+ private int mark_ibuffer_len = 0;
+
+ public 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 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; i < b.length; 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 Encoding[] formats = { Encoding.PCM_SIGNED, Encoding.PCM_UNSIGNED,
+ AudioFloatConverter.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(AudioFloatConverter.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,
+ AudioFloatConverter.PCM_FLOAT };
+ }
+
+ public Encoding[] getTargetEncodings() {
+ return new Encoding[] { Encoding.PCM_SIGNED, Encoding.PCM_UNSIGNED,
+ AudioFloatConverter.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,
+ AudioFloatConverter.PCM_FLOAT };
+ }
+
+ public AudioFormat[] getTargetFormats(Encoding targetEncoding,
+ AudioFormat sourceFormat) {
+ if (AudioFloatConverter.getConverter(sourceFormat) == null)
+ return new AudioFormat[0];
+ int channels = sourceFormat.getChannels();
+
+ ArrayList formats = new ArrayList();
+
+ 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(AudioFloatConverter.PCM_FLOAT)) {
+ formats.add(new AudioFormat(AudioFloatConverter.PCM_FLOAT,
+ AudioSystem.NOT_SPECIFIED, 32, channels, channels * 4,
+ AudioSystem.NOT_SPECIFIED, false));
+ formats.add(new AudioFormat(AudioFloatConverter.PCM_FLOAT,
+ AudioSystem.NOT_SPECIFIED, 32, channels, channels * 4,
+ AudioSystem.NOT_SPECIFIED, true));
+ formats.add(new AudioFormat(AudioFloatConverter.PCM_FLOAT,
+ AudioSystem.NOT_SPECIFIED, 64, channels, channels * 8,
+ AudioSystem.NOT_SPECIFIED, false));
+ formats.add(new AudioFormat(AudioFloatConverter.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;
+ }
+
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/AudioFloatInputStream.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/AudioFloatInputStream.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,281 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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 AudioFloatConverter converter;
+ private AudioFormat format;
+ private byte[] buffer;
+ private int buffer_offset;
+ private int buffer_len;
+ private int framesize_pc;
+
+ public 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 AudioInputStream stream;
+ private AudioFloatConverter converter;
+ private int framesize_pc; // framesize / channels
+ private byte[] buffer;
+
+ public 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 int read(float[] b) throws IOException {
+ return read(b, 0, b.length);
+ }
+
+ public 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;
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/AudioSynthesizer.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/AudioSynthesizer.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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;
+
+/**
+ * AudioSynthesizer
is a Synthesizer
+ * which renders it's output audio into SourceDataLine
+ * or AudioInputStream
.
+ *
+ * @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.
+ *
+ * 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 AudioSynthesizerPropertyInfo
objects
+ * describing possible properties. This array may be an empty array if
+ * no properties are required.
+ */
+ public AudioSynthesizerPropertyInfo[] getPropertyInfo(
+ Map info);
+
+ /**
+ * Opens the synthesizer and starts rendering audio into
+ * SourceDataLine
.
+ *
+ * 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.
+ *
+ *
Note that some synthesizers, once closed, cannot be reopened.
+ * Attempts to reopen such a synthesizer will always result in
+ * a MidiUnavailableException
.
+ *
+ * @param line which AudioSynthesizer
writes output audio into.
+ * If line
is null, then line from system default mixer is used.
+ * @param info a Map
object containing
+ * properties for additional configuration supported by synthesizer.
+ * If info
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 info)
+ throws MidiUnavailableException;
+
+ /**
+ * Opens the synthesizer and renders audio into returned
+ * AudioInputStream
.
+ *
+ * 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.
+ *
+ *
Note that some synthesizers, once closed, cannot be reopened.
+ * Attempts to reopen such a synthesizer will always result in
+ * a MidiUnavailableException.
+ *
+ * @param targetFormat specifies the AudioFormat
+ * used in returned AudioInputStream
.
+ * @param info a Map
object containing
+ * properties for additional configuration supported by synthesizer.
+ * If info
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 info) throws MidiUnavailableException;
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/AudioSynthesizerPropertyInfo.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/AudioSynthesizerPropertyInfo.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.media.sound;
+
+/**
+ * Information about property used in opening AudioSynthesizer
.
+ *
+ * @author Karl Helgason
+ */
+public class AudioSynthesizerPropertyInfo {
+
+ /**
+ * Constructs a AudioSynthesizerPropertyInfo
object with a given
+ * name and value. The description
and choices
+ * are intialized by null
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;
+ this.value = value;
+ if (value instanceof Class)
+ valueClass = (Class)value;
+ else 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 value
field specifies the current value of
+ * the property.
+ */
+ public Object value = null;
+ /**
+ * The valueClass
field specifies class
+ * used in value
field.
+ */
+ public Class valueClass = null;
+ /**
+ * An array of possible values if the value for the field
+ * AudioSynthesizerPropertyInfo.value
may be selected
+ * from a particular set of values; otherwise null.
+ */
+ public Object[] choices = null;
+
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/DLSInfo.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/DLSInfo.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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 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;
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/DLSInstrument.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/DLSInstrument.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,448 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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;
+
+/**
+ * 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 class DLSInstrument extends ModelInstrument {
+
+ protected int preset = 0;
+ protected int bank = 0;
+ protected boolean druminstrument = false;
+ protected byte[] guid = null;
+ protected DLSInfo info = new DLSInfo();
+ protected List regions = new ArrayList();
+ protected List modulators = new ArrayList();
+
+ 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 getRegions() {
+ return regions;
+ }
+
+ public List 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 performers = new ArrayList();
+
+ Map modmap = new HashMap();
+ for (DLSModulator mod: getModulators()) {
+ modmap.put(mod.getSource() + "x" + mod.getControl() + "=" +
+ mod.getDestination(), mod);
+ }
+
+ Map insmodmap =
+ new HashMap();
+
+ 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 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;
+ }
+
+ public void setGuid(byte[] guid) {
+ this.guid = guid;
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/DLSModulator.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/DLSModulator.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,351 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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 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;
+ protected int source;
+ protected int control;
+ protected int destination;
+ protected int transform;
+ protected int scale;
+ protected 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;
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/DLSRegion.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/DLSRegion.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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 class DLSRegion {
+
+ public final static int OPTION_SELFNONEXCLUSIVE = 0x0001;
+ protected List modulators = new ArrayList();
+ protected int keyfrom;
+ protected int keyto;
+ protected int velfrom;
+ protected int velto;
+ protected int options;
+ protected int exclusiveClass;
+ protected int fusoptions;
+ protected int phasegroup;
+ protected long channel;
+ protected DLSSample sample = null;
+ protected DLSSampleOptions sampleoptions;
+
+ public List 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 modulators) {
+ this.modulators = modulators;
+ }
+
+ public DLSSampleOptions getSampleoptions() {
+ return sampleoptions;
+ }
+
+ public void setSampleoptions(DLSSampleOptions sampleOptions) {
+ this.sampleoptions = sampleOptions;
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/DLSSample.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/DLSSample.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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;
+
+/**
+ * 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 class DLSSample extends SoundbankResource {
+
+ protected byte[] guid = null;
+ protected DLSInfo info = new DLSInfo();
+ protected DLSSampleOptions sampleoptions;
+ protected ModelByteBuffer data;
+ protected 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;
+ }
+
+ public void setGuid(byte[] guid) {
+ this.guid = guid;
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/DLSSampleLoop.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/DLSSampleLoop.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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 class DLSSampleLoop {
+
+ public final static int LOOP_TYPE_FORWARD = 0;
+ public final static int LOOP_TYPE_RELEASE = 1;
+ protected long type;
+ protected long start;
+ protected 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;
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/DLSSampleOptions.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/DLSSampleOptions.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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 class DLSSampleOptions {
+
+ protected int unitynote;
+ protected short finetune;
+ protected int attenuation;
+ protected long options;
+ protected List loops = new ArrayList();
+
+ 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 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;
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/DLSSoundbank.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/DLSSoundbank.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,1287 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+
+import javax.sound.midi.Instrument;
+import javax.sound.midi.Patch;
+import javax.sound.midi.Soundbank;
+import javax.sound.midi.SoundbankResource;
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.AudioInputStream;
+import javax.sound.sampled.AudioSystem;
+import javax.sound.sampled.AudioFormat.Encoding;
+
+/**
+ * A DLS Level 1 and Level 2 soundbank reader (from files/url/streams).
+ *
+ * @author Karl Helgason
+ */
+public class DLSSoundbank implements Soundbank {
+
+ static private class DLSID {
+ long i1;
+ int s1;
+ int s2;
+ int x1;
+ int x2;
+ int x3;
+ int x4;
+ int x5;
+ int x6;
+ int x7;
+ int x8;
+
+ private DLSID() {
+ }
+
+ public DLSID(long i1, int s1, int s2, int x1, int x2, int x3, int x4,
+ int x5, int x6, int x7, int x8) {
+ this.i1 = i1;
+ this.s1 = s1;
+ this.s2 = s2;
+ this.x1 = x1;
+ this.x2 = x2;
+ this.x3 = x3;
+ this.x4 = x4;
+ this.x5 = x5;
+ this.x6 = x6;
+ this.x7 = x7;
+ this.x8 = x8;
+ }
+
+ public static DLSID read(RIFFReader riff) throws IOException {
+ DLSID d = new DLSID();
+ d.i1 = riff.readUnsignedInt();
+ d.s1 = riff.readUnsignedShort();
+ d.s2 = riff.readUnsignedShort();
+ d.x1 = riff.readUnsignedByte();
+ d.x2 = riff.readUnsignedByte();
+ d.x3 = riff.readUnsignedByte();
+ d.x4 = riff.readUnsignedByte();
+ d.x5 = riff.readUnsignedByte();
+ d.x6 = riff.readUnsignedByte();
+ d.x7 = riff.readUnsignedByte();
+ d.x8 = riff.readUnsignedByte();
+ return d;
+ }
+
+ public int hashCode() {
+ return (int)i1;
+ }
+
+ public boolean equals(Object obj) {
+ if (!(obj instanceof DLSID)) {
+ return false;
+ }
+ DLSID t = (DLSID) obj;
+ return i1 == t.i1 && s1 == t.s1 && s2 == t.s2
+ && x1 == t.x1 && x2 == t.x2 && x3 == t.x3 && x4 == t.x4
+ && x5 == t.x5 && x6 == t.x6 && x7 == t.x7 && x8 == t.x8;
+ }
+ }
+
+ /** X = X & Y */
+ private static final int DLS_CDL_AND = 0x0001;
+ /** X = X | Y */
+ private static final int DLS_CDL_OR = 0x0002;
+ /** X = X ^ Y */
+ private static final int DLS_CDL_XOR = 0x0003;
+ /** X = X + Y */
+ private static final int DLS_CDL_ADD = 0x0004;
+ /** X = X - Y */
+ private static final int DLS_CDL_SUBTRACT = 0x0005;
+ /** X = X * Y */
+ private static final int DLS_CDL_MULTIPLY = 0x0006;
+ /** X = X / Y */
+ private static final int DLS_CDL_DIVIDE = 0x0007;
+ /** X = X && Y */
+ private static final int DLS_CDL_LOGICAL_AND = 0x0008;
+ /** X = X || Y */
+ private static final int DLS_CDL_LOGICAL_OR = 0x0009;
+ /** X = (X < Y) */
+ private static final int DLS_CDL_LT = 0x000A;
+ /** X = (X <= Y) */
+ private static final int DLS_CDL_LE = 0x000B;
+ /** X = (X > Y) */
+ private static final int DLS_CDL_GT = 0x000C;
+ /** X = (X >= Y) */
+ private static final int DLS_CDL_GE = 0x000D;
+ /** X = (X == Y) */
+ private static final int DLS_CDL_EQ = 0x000E;
+ /** X = !X */
+ private static final int DLS_CDL_NOT = 0x000F;
+ /** 32-bit constant */
+ private static final int DLS_CDL_CONST = 0x0010;
+ /** 32-bit value returned from query */
+ private static final int DLS_CDL_QUERY = 0x0011;
+ /** 32-bit value returned from query */
+ private static final int DLS_CDL_QUERYSUPPORTED = 0x0012;
+
+ private static final DLSID DLSID_GMInHardware = new DLSID(0x178f2f24,
+ 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12);
+ private static final DLSID DLSID_GSInHardware = new DLSID(0x178f2f25,
+ 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12);
+ private static final DLSID DLSID_XGInHardware = new DLSID(0x178f2f26,
+ 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12);
+ private static final DLSID DLSID_SupportsDLS1 = new DLSID(0x178f2f27,
+ 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12);
+ private static final DLSID DLSID_SupportsDLS2 = new DLSID(0xf14599e5,
+ 0x4689, 0x11d2, 0xaf, 0xa6, 0x0, 0xaa, 0x0, 0x24, 0xd8, 0xb6);
+ private static final DLSID DLSID_SampleMemorySize = new DLSID(0x178f2f28,
+ 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12);
+ private static final DLSID DLSID_ManufacturersID = new DLSID(0xb03e1181,
+ 0x8095, 0x11d2, 0xa1, 0xef, 0x0, 0x60, 0x8, 0x33, 0xdb, 0xd8);
+ private static final DLSID DLSID_ProductID = new DLSID(0xb03e1182,
+ 0x8095, 0x11d2, 0xa1, 0xef, 0x0, 0x60, 0x8, 0x33, 0xdb, 0xd8);
+ private static final DLSID DLSID_SamplePlaybackRate = new DLSID(0x2a91f713,
+ 0xa4bf, 0x11d2, 0xbb, 0xdf, 0x0, 0x60, 0x8, 0x33, 0xdb, 0xd8);
+
+ private long major = -1;
+ private long minor = -1;
+
+ private DLSInfo info = new DLSInfo();
+
+ private List instruments = new ArrayList();
+ private List samples = new ArrayList();
+
+ private boolean largeFormat = false;
+ private File sampleFile;
+
+ public DLSSoundbank() {
+ }
+
+ public DLSSoundbank(URL url) throws IOException {
+ InputStream is = url.openStream();
+ try {
+ readSoundbank(is);
+ } finally {
+ is.close();
+ }
+ }
+
+ public DLSSoundbank(File file) throws IOException {
+ largeFormat = true;
+ sampleFile = file;
+ InputStream is = new FileInputStream(file);
+ try {
+ readSoundbank(is);
+ } finally {
+ is.close();
+ }
+ }
+
+ public DLSSoundbank(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("DLS ")) {
+ throw new RIFFInvalidFormatException(
+ "Input stream is not a valid DLS soundbank!");
+ }
+ while (riff.hasNextChunk()) {
+ RIFFReader chunk = riff.nextChunk();
+ if (chunk.getFormat().equals("LIST")) {
+ if (chunk.getType().equals("INFO"))
+ readInfoChunk(chunk);
+ if (chunk.getType().equals("lins"))
+ readLinsChunk(chunk);
+ if (chunk.getType().equals("wvpl"))
+ readWvplChunk(chunk);
+ } else {
+ if (chunk.getFormat().equals("cdl ")) {
+ if (!readCdlChunk(chunk)) {
+ throw new RIFFInvalidFormatException(
+ "DLS file isn't supported!");
+ }
+ }
+ if (chunk.getFormat().equals("colh")) {
+ // skipped because we will load the entire bank into memory
+ // long instrumentcount = chunk.readUnsignedInt();
+ // System.out.println("instrumentcount = "+ instrumentcount);
+ }
+ if (chunk.getFormat().equals("ptbl")) {
+ // Pool Table Chunk
+ // skipped because we will load the entire bank into memory
+ }
+ if (chunk.getFormat().equals("vers")) {
+ major = chunk.readUnsignedInt();
+ minor = chunk.readUnsignedInt();
+ }
+ }
+ }
+
+ for (Map.Entry entry : temp_rgnassign.entrySet()) {
+ entry.getKey().sample = samples.get((int)entry.getValue().longValue());
+ }
+
+ temp_rgnassign = null;
+ }
+
+ private boolean cdlIsQuerySupported(DLSID uuid) {
+ return uuid.equals(DLSID_GMInHardware)
+ || uuid.equals(DLSID_GSInHardware)
+ || uuid.equals(DLSID_XGInHardware)
+ || uuid.equals(DLSID_SupportsDLS1)
+ || uuid.equals(DLSID_SupportsDLS2)
+ || uuid.equals(DLSID_SampleMemorySize)
+ || uuid.equals(DLSID_ManufacturersID)
+ || uuid.equals(DLSID_ProductID)
+ || uuid.equals(DLSID_SamplePlaybackRate);
+ }
+
+ private long cdlQuery(DLSID uuid) {
+ if (uuid.equals(DLSID_GMInHardware))
+ return 1;
+ if (uuid.equals(DLSID_GSInHardware))
+ return 0;
+ if (uuid.equals(DLSID_XGInHardware))
+ return 0;
+ if (uuid.equals(DLSID_SupportsDLS1))
+ return 1;
+ if (uuid.equals(DLSID_SupportsDLS2))
+ return 1;
+ if (uuid.equals(DLSID_SampleMemorySize))
+ return Runtime.getRuntime().totalMemory();
+ if (uuid.equals(DLSID_ManufacturersID))
+ return 0;
+ if (uuid.equals(DLSID_ProductID))
+ return 0;
+ if (uuid.equals(DLSID_SamplePlaybackRate))
+ return 44100;
+ return 0;
+ }
+
+
+ // Reading cdl-ck Chunk
+ // "cdl " chunk can only appear inside : DLS,lart,lar2,rgn,rgn2
+ private boolean readCdlChunk(RIFFReader riff) throws IOException {
+
+ DLSID uuid;
+ long x;
+ long y;
+ Stack stack = new Stack();
+
+ while (riff.available() != 0) {
+ int opcode = riff.readUnsignedShort();
+ switch (opcode) {
+ case DLS_CDL_AND:
+ x = stack.pop();
+ y = stack.pop();
+ stack.push(Long.valueOf(((x != 0) && (y != 0)) ? 1 : 0));
+ break;
+ case DLS_CDL_OR:
+ x = stack.pop();
+ y = stack.pop();
+ stack.push(Long.valueOf(((x != 0) || (y != 0)) ? 1 : 0));
+ break;
+ case DLS_CDL_XOR:
+ x = stack.pop();
+ y = stack.pop();
+ stack.push(Long.valueOf(((x != 0) ^ (y != 0)) ? 1 : 0));
+ break;
+ case DLS_CDL_ADD:
+ x = stack.pop();
+ y = stack.pop();
+ stack.push(Long.valueOf(x + y));
+ break;
+ case DLS_CDL_SUBTRACT:
+ x = stack.pop();
+ y = stack.pop();
+ stack.push(Long.valueOf(x - y));
+ break;
+ case DLS_CDL_MULTIPLY:
+ x = stack.pop();
+ y = stack.pop();
+ stack.push(Long.valueOf(x * y));
+ break;
+ case DLS_CDL_DIVIDE:
+ x = stack.pop();
+ y = stack.pop();
+ stack.push(Long.valueOf(x / y));
+ break;
+ case DLS_CDL_LOGICAL_AND:
+ x = stack.pop();
+ y = stack.pop();
+ stack.push(Long.valueOf(((x != 0) && (y != 0)) ? 1 : 0));
+ break;
+ case DLS_CDL_LOGICAL_OR:
+ x = stack.pop();
+ y = stack.pop();
+ stack.push(Long.valueOf(((x != 0) || (y != 0)) ? 1 : 0));
+ break;
+ case DLS_CDL_LT:
+ x = stack.pop();
+ y = stack.pop();
+ stack.push(Long.valueOf((x < y) ? 1 : 0));
+ break;
+ case DLS_CDL_LE:
+ x = stack.pop();
+ y = stack.pop();
+ stack.push(Long.valueOf((x <= y) ? 1 : 0));
+ break;
+ case DLS_CDL_GT:
+ x = stack.pop();
+ y = stack.pop();
+ stack.push(Long.valueOf((x > y) ? 1 : 0));
+ break;
+ case DLS_CDL_GE:
+ x = stack.pop();
+ y = stack.pop();
+ stack.push(Long.valueOf((x >= y) ? 1 : 0));
+ break;
+ case DLS_CDL_EQ:
+ x = stack.pop();
+ y = stack.pop();
+ stack.push(Long.valueOf((x == y) ? 1 : 0));
+ break;
+ case DLS_CDL_NOT:
+ x = stack.pop();
+ y = stack.pop();
+ stack.push(Long.valueOf((x == 0) ? 1 : 0));
+ break;
+ case DLS_CDL_CONST:
+ stack.push(Long.valueOf(riff.readUnsignedInt()));
+ break;
+ case DLS_CDL_QUERY:
+ uuid = DLSID.read(riff);
+ stack.push(cdlQuery(uuid));
+ break;
+ case DLS_CDL_QUERYSUPPORTED:
+ uuid = DLSID.read(riff);
+ stack.push(Long.valueOf(cdlIsQuerySupported(uuid) ? 1 : 0));
+ break;
+ default:
+ break;
+ }
+ }
+ if (stack.isEmpty())
+ return false;
+
+ return stack.pop() == 1;
+ }
+
+ private void readInfoChunk(RIFFReader riff) throws IOException {
+ info.name = null;
+ while (riff.hasNextChunk()) {
+ RIFFReader chunk = riff.nextChunk();
+ String format = chunk.getFormat();
+ if (format.equals("INAM"))
+ info.name = chunk.readString(chunk.available());
+ else if (format.equals("ICRD"))
+ info.creationDate = chunk.readString(chunk.available());
+ else if (format.equals("IENG"))
+ info.engineers = chunk.readString(chunk.available());
+ else if (format.equals("IPRD"))
+ info.product = chunk.readString(chunk.available());
+ else if (format.equals("ICOP"))
+ info.copyright = chunk.readString(chunk.available());
+ else if (format.equals("ICMT"))
+ info.comments = chunk.readString(chunk.available());
+ else if (format.equals("ISFT"))
+ info.tools = chunk.readString(chunk.available());
+ else if (format.equals("IARL"))
+ info.archival_location = chunk.readString(chunk.available());
+ else if (format.equals("IART"))
+ info.artist = chunk.readString(chunk.available());
+ else if (format.equals("ICMS"))
+ info.commissioned = chunk.readString(chunk.available());
+ else if (format.equals("IGNR"))
+ info.genre = chunk.readString(chunk.available());
+ else if (format.equals("IKEY"))
+ info.keywords = chunk.readString(chunk.available());
+ else if (format.equals("IMED"))
+ info.medium = chunk.readString(chunk.available());
+ else if (format.equals("ISBJ"))
+ info.subject = chunk.readString(chunk.available());
+ else if (format.equals("ISRC"))
+ info.source = chunk.readString(chunk.available());
+ else if (format.equals("ISRF"))
+ info.source_form = chunk.readString(chunk.available());
+ else if (format.equals("ITCH"))
+ info.technician = chunk.readString(chunk.available());
+ }
+ }
+
+ private void readLinsChunk(RIFFReader riff) throws IOException {
+ while (riff.hasNextChunk()) {
+ RIFFReader chunk = riff.nextChunk();
+ if (chunk.getFormat().equals("LIST")) {
+ if (chunk.getType().equals("ins "))
+ readInsChunk(chunk);
+ }
+ }
+ }
+
+ private void readInsChunk(RIFFReader riff) throws IOException {
+ DLSInstrument instrument = new DLSInstrument(this);
+
+ while (riff.hasNextChunk()) {
+ RIFFReader chunk = riff.nextChunk();
+ String format = chunk.getFormat();
+ if (format.equals("LIST")) {
+ if (chunk.getType().equals("INFO")) {
+ readInsInfoChunk(instrument, chunk);
+ }
+ if (chunk.getType().equals("lrgn")) {
+ while (chunk.hasNextChunk()) {
+ RIFFReader subchunk = chunk.nextChunk();
+ if (subchunk.getFormat().equals("LIST")) {
+ if (subchunk.getType().equals("rgn ")) {
+ DLSRegion split = new DLSRegion();
+ if (readRgnChunk(split, subchunk))
+ instrument.getRegions().add(split);
+ }
+ if (subchunk.getType().equals("rgn2")) {
+ // support for DLS level 2 regions
+ DLSRegion split = new DLSRegion();
+ if (readRgnChunk(split, subchunk))
+ instrument.getRegions().add(split);
+ }
+ }
+ }
+ }
+ if (chunk.getType().equals("lart")) {
+ List modlist = new ArrayList();
+ while (chunk.hasNextChunk()) {
+ RIFFReader subchunk = chunk.nextChunk();
+ if (chunk.getFormat().equals("cdl ")) {
+ if (!readCdlChunk(chunk)) {
+ modlist.clear();
+ break;
+ }
+ }
+ if (subchunk.getFormat().equals("art1"))
+ readArt1Chunk(modlist, subchunk);
+ }
+ instrument.getModulators().addAll(modlist);
+ }
+ if (chunk.getType().equals("lar2")) {
+ // support for DLS level 2 ART
+ List modlist = new ArrayList();
+ while (chunk.hasNextChunk()) {
+ RIFFReader subchunk = chunk.nextChunk();
+ if (chunk.getFormat().equals("cdl ")) {
+ if (!readCdlChunk(chunk)) {
+ modlist.clear();
+ break;
+ }
+ }
+ if (subchunk.getFormat().equals("art2"))
+ readArt2Chunk(modlist, subchunk);
+ }
+ instrument.getModulators().addAll(modlist);
+ }
+ } else {
+ if (format.equals("dlid")) {
+ instrument.guid = new byte[16];
+ chunk.readFully(instrument.guid);
+ }
+ if (format.equals("insh")) {
+ chunk.readUnsignedInt(); // Read Region Count - ignored
+
+ int bank = chunk.read(); // LSB
+ bank += (chunk.read() & 127) << 7; // MSB
+ chunk.read(); // Read Reserved byte
+ int drumins = chunk.read(); // Drum Instrument
+
+ int id = chunk.read() & 127; // Read only first 7 bits
+ chunk.read(); // Read Reserved byte
+ chunk.read(); // Read Reserved byte
+ chunk.read(); // Read Reserved byte
+
+ instrument.bank = bank;
+ instrument.preset = (int) id;
+ instrument.druminstrument = (drumins & 128) > 0;
+ //System.out.println("bank="+bank+" drumkit="+drumkit
+ // +" id="+id);
+ }
+
+ }
+ }
+ instruments.add(instrument);
+ }
+
+ private void readArt1Chunk(List modulators, RIFFReader riff)
+ throws IOException {
+ long size = riff.readUnsignedInt();
+ long count = riff.readUnsignedInt();
+
+ if (size - 8 != 0)
+ riff.skipBytes(size - 8);
+
+ for (int i = 0; i < count; i++) {
+ DLSModulator modulator = new DLSModulator();
+ modulator.version = 1;
+ modulator.source = riff.readUnsignedShort();
+ modulator.control = riff.readUnsignedShort();
+ modulator.destination = riff.readUnsignedShort();
+ modulator.transform = riff.readUnsignedShort();
+ modulator.scale = riff.readInt();
+ modulators.add(modulator);
+ }
+ }
+
+ private void readArt2Chunk(List modulators, RIFFReader riff)
+ throws IOException {
+ long size = riff.readUnsignedInt();
+ long count = riff.readUnsignedInt();
+
+ if (size - 8 != 0)
+ riff.skipBytes(size - 8);
+
+ for (int i = 0; i < count; i++) {
+ DLSModulator modulator = new DLSModulator();
+ modulator.version = 2;
+ modulator.source = riff.readUnsignedShort();
+ modulator.control = riff.readUnsignedShort();
+ modulator.destination = riff.readUnsignedShort();
+ modulator.transform = riff.readUnsignedShort();
+ modulator.scale = riff.readInt();
+ modulators.add(modulator);
+ }
+ }
+
+ private Map temp_rgnassign = new HashMap();
+
+ private boolean readRgnChunk(DLSRegion split, RIFFReader riff)
+ throws IOException {
+ while (riff.hasNextChunk()) {
+ RIFFReader chunk = riff.nextChunk();
+ String format = chunk.getFormat();
+ if (format.equals("LIST")) {
+ if (chunk.getType().equals("lart")) {
+ List modlist = new ArrayList();
+ while (chunk.hasNextChunk()) {
+ RIFFReader subchunk = chunk.nextChunk();
+ if (chunk.getFormat().equals("cdl ")) {
+ if (!readCdlChunk(chunk)) {
+ modlist.clear();
+ break;
+ }
+ }
+ if (subchunk.getFormat().equals("art1"))
+ readArt1Chunk(modlist, subchunk);
+ }
+ split.getModulators().addAll(modlist);
+ }
+ if (chunk.getType().equals("lar2")) {
+ // support for DLS level 2 ART
+ List modlist = new ArrayList();
+ while (chunk.hasNextChunk()) {
+ RIFFReader subchunk = chunk.nextChunk();
+ if (chunk.getFormat().equals("cdl ")) {
+ if (!readCdlChunk(chunk)) {
+ modlist.clear();
+ break;
+ }
+ }
+ if (subchunk.getFormat().equals("art2"))
+ readArt2Chunk(modlist, subchunk);
+ }
+ split.getModulators().addAll(modlist);
+ }
+ } else {
+
+ if (format.equals("cdl ")) {
+ if (!readCdlChunk(chunk))
+ return false;
+ }
+ if (format.equals("rgnh")) {
+ split.keyfrom = chunk.readUnsignedShort();
+ split.keyto = chunk.readUnsignedShort();
+ split.velfrom = chunk.readUnsignedShort();
+ split.velto = chunk.readUnsignedShort();
+ split.options = chunk.readUnsignedShort();
+ split.exclusiveClass = chunk.readUnsignedShort();
+ }
+ if (format.equals("wlnk")) {
+ split.fusoptions = chunk.readUnsignedShort();
+ split.phasegroup = chunk.readUnsignedShort();
+ split.channel = chunk.readUnsignedInt();
+ long sampleid = chunk.readUnsignedInt();
+ temp_rgnassign.put(split, sampleid);
+ }
+ if (format.equals("wsmp")) {
+ split.sampleoptions = new DLSSampleOptions();
+ readWsmpChunk(split.sampleoptions, chunk);
+ }
+ }
+ }
+ return true;
+ }
+
+ private void readWsmpChunk(DLSSampleOptions sampleOptions, RIFFReader riff)
+ throws IOException {
+ long size = riff.readUnsignedInt();
+ sampleOptions.unitynote = riff.readUnsignedShort();
+ sampleOptions.finetune = riff.readShort();
+ sampleOptions.attenuation = riff.readInt();
+ sampleOptions.options = riff.readUnsignedInt();
+ long loops = riff.readInt();
+
+ if (size > 20)
+ riff.skipBytes(size - 20);
+
+ for (int i = 0; i < loops; i++) {
+ DLSSampleLoop loop = new DLSSampleLoop();
+ long size2 = riff.readUnsignedInt();
+ loop.type = riff.readUnsignedInt();
+ loop.start = riff.readUnsignedInt();
+ loop.length = riff.readUnsignedInt();
+ sampleOptions.loops.add(loop);
+ if (size2 > 16)
+ riff.skipBytes(size2 - 16);
+ }
+ }
+
+ private void readInsInfoChunk(DLSInstrument dlsinstrument, RIFFReader riff)
+ throws IOException {
+ dlsinstrument.info.name = null;
+ while (riff.hasNextChunk()) {
+ RIFFReader chunk = riff.nextChunk();
+ String format = chunk.getFormat();
+ if (format.equals("INAM")) {
+ dlsinstrument.info.name = chunk.readString(chunk.available());
+ } else if (format.equals("ICRD")) {
+ dlsinstrument.info.creationDate =
+ chunk.readString(chunk.available());
+ } else if (format.equals("IENG")) {
+ dlsinstrument.info.engineers =
+ chunk.readString(chunk.available());
+ } else if (format.equals("IPRD")) {
+ dlsinstrument.info.product = chunk.readString(chunk.available());
+ } else if (format.equals("ICOP")) {
+ dlsinstrument.info.copyright =
+ chunk.readString(chunk.available());
+ } else if (format.equals("ICMT")) {
+ dlsinstrument.info.comments =
+ chunk.readString(chunk.available());
+ } else if (format.equals("ISFT")) {
+ dlsinstrument.info.tools = chunk.readString(chunk.available());
+ } else if (format.equals("IARL")) {
+ dlsinstrument.info.archival_location =
+ chunk.readString(chunk.available());
+ } else if (format.equals("IART")) {
+ dlsinstrument.info.artist = chunk.readString(chunk.available());
+ } else if (format.equals("ICMS")) {
+ dlsinstrument.info.commissioned =
+ chunk.readString(chunk.available());
+ } else if (format.equals("IGNR")) {
+ dlsinstrument.info.genre = chunk.readString(chunk.available());
+ } else if (format.equals("IKEY")) {
+ dlsinstrument.info.keywords =
+ chunk.readString(chunk.available());
+ } else if (format.equals("IMED")) {
+ dlsinstrument.info.medium = chunk.readString(chunk.available());
+ } else if (format.equals("ISBJ")) {
+ dlsinstrument.info.subject = chunk.readString(chunk.available());
+ } else if (format.equals("ISRC")) {
+ dlsinstrument.info.source = chunk.readString(chunk.available());
+ } else if (format.equals("ISRF")) {
+ dlsinstrument.info.source_form =
+ chunk.readString(chunk.available());
+ } else if (format.equals("ITCH")) {
+ dlsinstrument.info.technician =
+ chunk.readString(chunk.available());
+ }
+ }
+ }
+
+ private void readWvplChunk(RIFFReader riff) throws IOException {
+ while (riff.hasNextChunk()) {
+ RIFFReader chunk = riff.nextChunk();
+ if (chunk.getFormat().equals("LIST")) {
+ if (chunk.getType().equals("wave"))
+ readWaveChunk(chunk);
+ }
+ }
+ }
+
+ private void readWaveChunk(RIFFReader riff) throws IOException {
+ DLSSample sample = new DLSSample(this);
+
+ while (riff.hasNextChunk()) {
+ RIFFReader chunk = riff.nextChunk();
+ String format = chunk.getFormat();
+ if (format.equals("LIST")) {
+ if (chunk.getType().equals("INFO")) {
+ readWaveInfoChunk(sample, chunk);
+ }
+ } else {
+ if (format.equals("dlid")) {
+ sample.guid = new byte[16];
+ chunk.readFully(sample.guid);
+ }
+
+ if (format.equals("fmt ")) {
+ int sampleformat = chunk.readUnsignedShort();
+ if (sampleformat != 1 && sampleformat != 3) {
+ throw new RIFFInvalidDataException(
+ "Only PCM samples are supported!");
+ }
+ int channels = chunk.readUnsignedShort();
+ long samplerate = chunk.readUnsignedInt();
+ // bytes per sec
+ /* long framerate = */ chunk.readUnsignedInt();
+ // block align, framesize
+ int framesize = chunk.readUnsignedShort();
+ int bits = chunk.readUnsignedShort();
+ AudioFormat audioformat = null;
+ if (sampleformat == 1) {
+ if (bits == 8) {
+ audioformat = new AudioFormat(
+ Encoding.PCM_UNSIGNED, samplerate, bits,
+ channels, framesize, samplerate, false);
+ } else {
+ audioformat = new AudioFormat(
+ Encoding.PCM_SIGNED, samplerate, bits,
+ channels, framesize, samplerate, false);
+ }
+ }
+ if (sampleformat == 3) {
+ audioformat = new AudioFormat(
+ AudioFloatConverter.PCM_FLOAT, samplerate, bits,
+ channels, framesize, samplerate, false);
+ }
+
+ sample.format = audioformat;
+ }
+
+ if (format.equals("data")) {
+ if (largeFormat) {
+ sample.setData(new ModelByteBuffer(sampleFile,
+ chunk.getFilePointer(), chunk.available()));
+ } else {
+ byte[] buffer = new byte[chunk.available()];
+ // chunk.read(buffer);
+ sample.setData(buffer);
+
+ int read = 0;
+ int avail = chunk.available();
+ while (read != avail) {
+ if (avail - read > 65536) {
+ chunk.readFully(buffer, read, 65536);
+ read += 65536;
+ } else {
+ chunk.readFully(buffer, read, avail - read);
+ read = avail;
+ }
+ }
+ }
+ }
+
+ if (format.equals("wsmp")) {
+ sample.sampleoptions = new DLSSampleOptions();
+ readWsmpChunk(sample.sampleoptions, chunk);
+ }
+ }
+ }
+
+ samples.add(sample);
+
+ }
+
+ private void readWaveInfoChunk(DLSSample dlssample, RIFFReader riff)
+ throws IOException {
+ dlssample.info.name = null;
+ while (riff.hasNextChunk()) {
+ RIFFReader chunk = riff.nextChunk();
+ String format = chunk.getFormat();
+ if (format.equals("INAM")) {
+ dlssample.info.name = chunk.readString(chunk.available());
+ } else if (format.equals("ICRD")) {
+ dlssample.info.creationDate =
+ chunk.readString(chunk.available());
+ } else if (format.equals("IENG")) {
+ dlssample.info.engineers = chunk.readString(chunk.available());
+ } else if (format.equals("IPRD")) {
+ dlssample.info.product = chunk.readString(chunk.available());
+ } else if (format.equals("ICOP")) {
+ dlssample.info.copyright = chunk.readString(chunk.available());
+ } else if (format.equals("ICMT")) {
+ dlssample.info.comments = chunk.readString(chunk.available());
+ } else if (format.equals("ISFT")) {
+ dlssample.info.tools = chunk.readString(chunk.available());
+ } else if (format.equals("IARL")) {
+ dlssample.info.archival_location =
+ chunk.readString(chunk.available());
+ } else if (format.equals("IART")) {
+ dlssample.info.artist = chunk.readString(chunk.available());
+ } else if (format.equals("ICMS")) {
+ dlssample.info.commissioned =
+ chunk.readString(chunk.available());
+ } else if (format.equals("IGNR")) {
+ dlssample.info.genre = chunk.readString(chunk.available());
+ } else if (format.equals("IKEY")) {
+ dlssample.info.keywords = chunk.readString(chunk.available());
+ } else if (format.equals("IMED")) {
+ dlssample.info.medium = chunk.readString(chunk.available());
+ } else if (format.equals("ISBJ")) {
+ dlssample.info.subject = chunk.readString(chunk.available());
+ } else if (format.equals("ISRC")) {
+ dlssample.info.source = chunk.readString(chunk.available());
+ } else if (format.equals("ISRF")) {
+ dlssample.info.source_form = chunk.readString(chunk.available());
+ } else if (format.equals("ITCH")) {
+ dlssample.info.technician = chunk.readString(chunk.available());
+ }
+ }
+ }
+
+ public void save(String name) throws IOException {
+ writeSoundbank(new RIFFWriter(name, "DLS "));
+ }
+
+ public void save(File file) throws IOException {
+ writeSoundbank(new RIFFWriter(file, "DLS "));
+ }
+
+ public void save(OutputStream out) throws IOException {
+ writeSoundbank(new RIFFWriter(out, "DLS "));
+ }
+
+ private void writeSoundbank(RIFFWriter writer) throws IOException {
+ RIFFWriter colh_chunk = writer.writeChunk("colh");
+ colh_chunk.writeUnsignedInt(instruments.size());
+
+ if (major != -1 && minor != -1) {
+ RIFFWriter vers_chunk = writer.writeChunk("vers");
+ vers_chunk.writeUnsignedInt(major);
+ vers_chunk.writeUnsignedInt(minor);
+ }
+
+ writeInstruments(writer.writeList("lins"));
+
+ RIFFWriter ptbl = writer.writeChunk("ptbl");
+ ptbl.writeUnsignedInt(8);
+ ptbl.writeUnsignedInt(samples.size());
+ long ptbl_offset = writer.getFilePointer();
+ for (int i = 0; i < samples.size(); i++)
+ ptbl.writeUnsignedInt(0);
+
+ RIFFWriter wvpl = writer.writeList("wvpl");
+ long off = wvpl.getFilePointer();
+ List offsettable = new ArrayList();
+ for (DLSSample sample : samples) {
+ offsettable.add(Long.valueOf(wvpl.getFilePointer() - off));
+ writeSample(wvpl.writeList("wave"), sample);
+ }
+
+ // small cheat, we are going to rewrite data back in wvpl
+ long bak = writer.getFilePointer();
+ writer.seek(ptbl_offset);
+ writer.setWriteOverride(true);
+ for (Long offset : offsettable)
+ writer.writeUnsignedInt(offset.longValue());
+ writer.setWriteOverride(false);
+ writer.seek(bak);
+
+ writeInfo(writer.writeList("INFO"), info);
+
+ writer.close();
+ }
+
+ private void writeSample(RIFFWriter writer, DLSSample sample)
+ throws IOException {
+
+ AudioFormat audioformat = sample.getFormat();
+
+ Encoding encoding = audioformat.getEncoding();
+ float sampleRate = audioformat.getSampleRate();
+ int sampleSizeInBits = audioformat.getSampleSizeInBits();
+ int channels = audioformat.getChannels();
+ int frameSize = audioformat.getFrameSize();
+ float frameRate = audioformat.getFrameRate();
+ boolean bigEndian = audioformat.isBigEndian();
+
+ boolean convert_needed = false;
+
+ if (audioformat.getSampleSizeInBits() == 8) {
+ if (!encoding.equals(Encoding.PCM_UNSIGNED)) {
+ encoding = Encoding.PCM_UNSIGNED;
+ convert_needed = true;
+ }
+ } else {
+ if (!encoding.equals(Encoding.PCM_SIGNED)) {
+ encoding = Encoding.PCM_SIGNED;
+ convert_needed = true;
+ }
+ if (bigEndian) {
+ bigEndian = false;
+ convert_needed = true;
+ }
+ }
+
+ if (convert_needed) {
+ audioformat = new AudioFormat(encoding, sampleRate,
+ sampleSizeInBits, channels, frameSize, frameRate, bigEndian);
+ }
+
+ // fmt
+ RIFFWriter fmt_chunk = writer.writeChunk("fmt ");
+ int sampleformat = 0;
+ if (audioformat.getEncoding().equals(Encoding.PCM_UNSIGNED))
+ sampleformat = 1;
+ else if (audioformat.getEncoding().equals(Encoding.PCM_SIGNED))
+ sampleformat = 1;
+ else if (audioformat.getEncoding().equals(AudioFloatConverter.PCM_FLOAT))
+ sampleformat = 3;
+
+ fmt_chunk.writeUnsignedShort(sampleformat);
+ fmt_chunk.writeUnsignedShort(audioformat.getChannels());
+ fmt_chunk.writeUnsignedInt((long) audioformat.getSampleRate());
+ long srate = ((long)audioformat.getFrameRate())*audioformat.getFrameSize();
+ fmt_chunk.writeUnsignedInt(srate);
+ fmt_chunk.writeUnsignedShort(audioformat.getFrameSize());
+ fmt_chunk.writeUnsignedShort(audioformat.getSampleSizeInBits());
+ fmt_chunk.write(0);
+ fmt_chunk.write(0);
+
+ writeSampleOptions(writer.writeChunk("wsmp"), sample.sampleoptions);
+
+ if (convert_needed) {
+ RIFFWriter data_chunk = writer.writeChunk("data");
+ AudioInputStream stream = AudioSystem.getAudioInputStream(
+ audioformat, (AudioInputStream)sample.getData());
+ byte[] buff = new byte[1024];
+ int ret;
+ while ((ret = stream.read(buff)) != -1) {
+ data_chunk.write(buff, 0, ret);
+ }
+ } else {
+ RIFFWriter data_chunk = writer.writeChunk("data");
+ ModelByteBuffer databuff = sample.getDataBuffer();
+ databuff.writeTo(data_chunk);
+ /*
+ data_chunk.write(databuff.array(),
+ databuff.arrayOffset(),
+ databuff.capacity());
+ */
+ }
+
+ writeInfo(writer.writeList("INFO"), sample.info);
+ }
+
+ private void writeInstruments(RIFFWriter writer) throws IOException {
+ for (DLSInstrument instrument : instruments) {
+ writeInstrument(writer.writeList("ins "), instrument);
+ }
+ }
+
+ private void writeInstrument(RIFFWriter writer, DLSInstrument instrument)
+ throws IOException {
+
+ int art1_count = 0;
+ int art2_count = 0;
+ for (DLSModulator modulator : instrument.getModulators()) {
+ if (modulator.version == 1)
+ art1_count++;
+ if (modulator.version == 2)
+ art2_count++;
+ }
+ for (DLSRegion region : instrument.regions) {
+ for (DLSModulator modulator : region.getModulators()) {
+ if (modulator.version == 1)
+ art1_count++;
+ if (modulator.version == 2)
+ art2_count++;
+ }
+ }
+
+ int version = 1;
+ if (art2_count > 0)
+ version = 2;
+
+ RIFFWriter insh_chunk = writer.writeChunk("insh");
+ insh_chunk.writeUnsignedInt(instrument.getRegions().size());
+ insh_chunk.writeUnsignedInt(instrument.bank +
+ (instrument.druminstrument ? 2147483648L : 0));
+ insh_chunk.writeUnsignedInt(instrument.preset);
+
+ RIFFWriter lrgn = writer.writeList("lrgn");
+ for (DLSRegion region: instrument.regions)
+ writeRegion(lrgn, region, version);
+
+ writeArticulators(writer, instrument.getModulators());
+
+ writeInfo(writer.writeList("INFO"), instrument.info);
+
+ }
+
+ private void writeArticulators(RIFFWriter writer,
+ List modulators) throws IOException {
+ int art1_count = 0;
+ int art2_count = 0;
+ for (DLSModulator modulator : modulators) {
+ if (modulator.version == 1)
+ art1_count++;
+ if (modulator.version == 2)
+ art2_count++;
+ }
+ if (art1_count > 0) {
+ RIFFWriter lar1 = writer.writeList("lart");
+ RIFFWriter art1 = lar1.writeChunk("art1");
+ art1.writeUnsignedInt(8);
+ art1.writeUnsignedInt(art1_count);
+ for (DLSModulator modulator : modulators) {
+ if (modulator.version == 1) {
+ art1.writeUnsignedShort(modulator.source);
+ art1.writeUnsignedShort(modulator.control);
+ art1.writeUnsignedShort(modulator.destination);
+ art1.writeUnsignedShort(modulator.transform);
+ art1.writeInt(modulator.scale);
+ }
+ }
+ }
+ if (art2_count > 0) {
+ RIFFWriter lar2 = writer.writeList("lar2");
+ RIFFWriter art2 = lar2.writeChunk("art2");
+ art2.writeUnsignedInt(8);
+ art2.writeUnsignedInt(art2_count);
+ for (DLSModulator modulator : modulators) {
+ if (modulator.version == 2) {
+ art2.writeUnsignedShort(modulator.source);
+ art2.writeUnsignedShort(modulator.control);
+ art2.writeUnsignedShort(modulator.destination);
+ art2.writeUnsignedShort(modulator.transform);
+ art2.writeInt(modulator.scale);
+ }
+ }
+ }
+ }
+
+ private void writeRegion(RIFFWriter writer, DLSRegion region, int version)
+ throws IOException {
+ RIFFWriter rgns = null;
+ if (version == 1)
+ rgns = writer.writeList("rgn ");
+ if (version == 2)
+ rgns = writer.writeList("rgn2");
+ if (rgns == null)
+ return;
+
+ RIFFWriter rgnh = rgns.writeChunk("rgnh");
+ rgnh.writeUnsignedShort(region.keyfrom);
+ rgnh.writeUnsignedShort(region.keyto);
+ rgnh.writeUnsignedShort(region.velfrom);
+ rgnh.writeUnsignedShort(region.velto);
+ rgnh.writeUnsignedShort(region.options);
+ rgnh.writeUnsignedShort(region.exclusiveClass);
+
+ if (region.sampleoptions != null)
+ writeSampleOptions(rgns.writeChunk("wsmp"), region.sampleoptions);
+
+ if (region.sample != null) {
+ if (samples.indexOf(region.sample) != -1) {
+ RIFFWriter wlnk = rgns.writeChunk("wlnk");
+ wlnk.writeUnsignedShort(region.fusoptions);
+ wlnk.writeUnsignedShort(region.phasegroup);
+ wlnk.writeUnsignedInt(region.channel);
+ wlnk.writeUnsignedInt(samples.indexOf(region.sample));
+ }
+ }
+ writeArticulators(rgns, region.getModulators());
+ rgns.close();
+ }
+
+ private void writeSampleOptions(RIFFWriter wsmp,
+ DLSSampleOptions sampleoptions) throws IOException {
+ wsmp.writeUnsignedInt(20);
+ wsmp.writeUnsignedShort(sampleoptions.unitynote);
+ wsmp.writeShort(sampleoptions.finetune);
+ wsmp.writeInt(sampleoptions.attenuation);
+ wsmp.writeUnsignedInt(sampleoptions.options);
+ wsmp.writeInt(sampleoptions.loops.size());
+
+ for (DLSSampleLoop loop : sampleoptions.loops) {
+ wsmp.writeUnsignedInt(16);
+ wsmp.writeUnsignedInt(loop.type);
+ wsmp.writeUnsignedInt(loop.start);
+ wsmp.writeUnsignedInt(loop.length);
+ }
+ }
+
+ 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, DLSInfo info) throws IOException {
+ writeInfoStringChunk(writer, "INAM", info.name);
+ writeInfoStringChunk(writer, "ICRD", info.creationDate);
+ writeInfoStringChunk(writer, "IENG", info.engineers);
+ writeInfoStringChunk(writer, "IPRD", info.product);
+ writeInfoStringChunk(writer, "ICOP", info.copyright);
+ writeInfoStringChunk(writer, "ICMT", info.comments);
+ writeInfoStringChunk(writer, "ISFT", info.tools);
+ writeInfoStringChunk(writer, "IARL", info.archival_location);
+ writeInfoStringChunk(writer, "IART", info.artist);
+ writeInfoStringChunk(writer, "ICMS", info.commissioned);
+ writeInfoStringChunk(writer, "IGNR", info.genre);
+ writeInfoStringChunk(writer, "IKEY", info.keywords);
+ writeInfoStringChunk(writer, "IMED", info.medium);
+ writeInfoStringChunk(writer, "ISBJ", info.subject);
+ writeInfoStringChunk(writer, "ISRC", info.source);
+ writeInfoStringChunk(writer, "ISRF", info.source_form);
+ writeInfoStringChunk(writer, "ITCH", info.technician);
+ }
+
+ public DLSInfo getInfo() {
+ return info;
+ }
+
+ public String getName() {
+ return info.name;
+ }
+
+ public String getVersion() {
+ return major + "." + minor;
+ }
+
+ public String getVendor() {
+ return info.engineers;
+ }
+
+ public String getDescription() {
+ return info.comments;
+ }
+
+ public void setName(String s) {
+ info.name = s;
+ }
+
+ public void setVendor(String s) {
+ info.engineers = s;
+ }
+
+ public void setDescription(String s) {
+ info.comments = s;
+ }
+
+ public SoundbankResource[] getResources() {
+ SoundbankResource[] resources = new SoundbankResource[samples.size()];
+ int j = 0;
+ for (int i = 0; i < samples.size(); i++)
+ resources[j++] = samples.get(i);
+ return resources;
+ }
+
+ public DLSInstrument[] getInstruments() {
+ DLSInstrument[] inslist_array =
+ instruments.toArray(new DLSInstrument[instruments.size()]);
+ Arrays.sort(inslist_array, new ModelInstrumentComparator());
+ return inslist_array;
+ }
+
+ public DLSSample[] getSamples() {
+ return samples.toArray(new DLSSample[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 void addResource(SoundbankResource resource) {
+ if (resource instanceof DLSInstrument)
+ instruments.add((DLSInstrument) resource);
+ if (resource instanceof DLSSample)
+ samples.add((DLSSample) resource);
+ }
+
+ public void removeResource(SoundbankResource resource) {
+ if (resource instanceof DLSInstrument)
+ instruments.remove((DLSInstrument) resource);
+ if (resource instanceof DLSSample)
+ samples.remove((DLSSample) resource);
+ }
+
+ public void addInstrument(DLSInstrument resource) {
+ instruments.add(resource);
+ }
+
+ public void removeInstrument(DLSInstrument resource) {
+ instruments.remove(resource);
+ }
+
+ public long getMajor() {
+ return major;
+ }
+
+ public void setMajor(long major) {
+ this.major = major;
+ }
+
+ public long getMinor() {
+ return minor;
+ }
+
+ public void setMinor(long minor) {
+ this.minor = minor;
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/DLSSoundbankReader.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/DLSSoundbankReader.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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 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;
+ }
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/DirectAudioDevice.java
--- a/jdk/src/share/classes/com/sun/media/sound/DirectAudioDevice.java Thu Jan 29 21:46:48 2009 -0800
+++ b/jdk/src/share/classes/com/sun/media/sound/DirectAudioDevice.java Tue Feb 03 22:02:55 2009 -0800
@@ -394,7 +394,12 @@
private float leftGain, rightGain;
protected volatile boolean noService = false; // do not run the nService method
+ // Guards all native calls.
protected Object lockNative = new Object();
+ // Guards the lastOpened static variable in implOpen and implClose.
+ protected static Object lockLast = new Object();
+ // Keeps track of last opened line, see implOpen "trick".
+ protected static DirectDL lastOpened;
// CONSTRUCTOR
protected DirectDL(DataLine.Info info,
@@ -496,20 +501,50 @@
// align buffer to full frames
bufferSize = ((int) bufferSize / format.getFrameSize()) * format.getFrameSize();
- id = nOpen(mixerIndex, deviceID, isSource,
- encoding,
- hardwareFormat.getSampleRate(),
- hardwareFormat.getSampleSizeInBits(),
- hardwareFormat.getFrameSize(),
- hardwareFormat.getChannels(),
- hardwareFormat.getEncoding().equals(AudioFormat.Encoding.PCM_SIGNED),
- hardwareFormat.isBigEndian(),
- bufferSize);
+ synchronized(lockLast) {
+ id = nOpen(mixerIndex, deviceID, isSource,
+ encoding,
+ hardwareFormat.getSampleRate(),
+ hardwareFormat.getSampleSizeInBits(),
+ hardwareFormat.getFrameSize(),
+ hardwareFormat.getChannels(),
+ hardwareFormat.getEncoding().equals(
+ AudioFormat.Encoding.PCM_SIGNED),
+ hardwareFormat.isBigEndian(),
+ bufferSize);
- if (id == 0) {
- // TODO: nicer error messages...
- throw new LineUnavailableException("line with format "+format+" not supported.");
+ if (id == 0) {
+ // Bah... Dirty trick. The most likely cause is an application
+ // already having a line open for this particular hardware
+ // format and forgetting about it. If so, silently close that
+ // implementation and try again. Unfortuantely we can only
+ // open one line per hardware format currently.
+ if (lastOpened != null
+ && hardwareFormat.matches(lastOpened.hardwareFormat)) {
+ lastOpened.implClose();
+ lastOpened = null;
+
+ id = nOpen(mixerIndex, deviceID, isSource,
+ encoding,
+ hardwareFormat.getSampleRate(),
+ hardwareFormat.getSampleSizeInBits(),
+ hardwareFormat.getFrameSize(),
+ hardwareFormat.getChannels(),
+ hardwareFormat.getEncoding().equals(
+ AudioFormat.Encoding.PCM_SIGNED),
+ hardwareFormat.isBigEndian(),
+ bufferSize);
+ }
+
+ if (id == 0) {
+ // TODO: nicer error messages...
+ throw new LineUnavailableException(
+ "line with format "+format+" not supported.");
+ }
+ }
+ lastOpened = this;
}
+
this.bufferSize = nGetBufferSize(id, isSource);
if (this.bufferSize < 1) {
// this is an error!
@@ -580,12 +615,12 @@
}
synchronized (lockNative) {
nStop(id, isSource);
+
+ // need to set doIO to false before notifying the
+ // read/write thread, that's why isStartedRunning()
+ // cannot be used
+ doIO = false;
}
-
- // need to set doIO to false before notifying the
- // read/write thread, that's why isStartedRunning()
- // cannot be used
- doIO = false;
// wake up any waiting threads
synchronized(lock) {
lock.notifyAll();
@@ -614,8 +649,12 @@
doIO = false;
long oldID = id;
id = 0;
- synchronized (lockNative) {
- nClose(oldID, isSource);
+ synchronized (lockLast) {
+ synchronized (lockNative) {
+ nClose(oldID, isSource);
+ if (lastOpened == this)
+ lastOpened = null;
+ }
}
bytePosition = 0;
softwareConversionSize = 0;
@@ -630,7 +669,8 @@
}
int a = 0;
synchronized (lockNative) {
- a = nAvailable(id, isSource);
+ if (doIO)
+ a = nAvailable(id, isSource);
}
return a;
}
@@ -644,9 +684,9 @@
int counter = 0;
long startPos = getLongFramePosition();
boolean posChanged = false;
- while (!drained && doIO) {
+ while (!drained) {
synchronized (lockNative) {
- if ((id == 0) || !nIsStillDraining(id, isSource))
+ if ((id == 0) || (!doIO) || !nIsStillDraining(id, isSource))
break;
}
// check every now and then for a new position
@@ -686,7 +726,7 @@
lock.notifyAll();
}
synchronized (lockNative) {
- if (id != 0) {
+ if (id != 0 && doIO) {
// then flush native buffers
nFlush(id, isSource);
}
@@ -697,9 +737,10 @@
// replacement for getFramePosition (see AbstractDataLine)
public long getLongFramePosition() {
- long pos;
+ long pos = 0;
synchronized (lockNative) {
- pos = nGetBytePosition(id, isSource, bytePosition);
+ if (doIO)
+ pos = nGetBytePosition(id, isSource, bytePosition);
}
// hack because ALSA sometimes reports wrong framepos
if (pos < 0) {
@@ -745,11 +786,12 @@
}
int written = 0;
while (!flushing) {
- int thisWritten;
+ int thisWritten = 0;
synchronized (lockNative) {
- thisWritten = nWrite(id, b, off, len,
- softwareConversionSize,
- leftGain, rightGain);
+ if (doIO)
+ thisWritten = nWrite(id, b, off, len,
+ softwareConversionSize,
+ leftGain, rightGain);
if (thisWritten < 0) {
// error in native layer
break;
@@ -972,9 +1014,10 @@
}
int read = 0;
while (doIO && !flushing) {
- int thisRead;
+ int thisRead = 0;
synchronized (lockNative) {
- thisRead = nRead(id, b, off, len, softwareConversionSize);
+ if (doIO)
+ thisRead = nRead(id, b, off, len, softwareConversionSize);
if (thisRead < 0) {
// error in native layer
break;
@@ -1209,7 +1252,8 @@
// set new native position (if necessary)
// this must come after the flush!
synchronized (lockNative) {
- nSetBytePosition(id, isSource, frames * frameSize);
+ if (doIO)
+ nSetBytePosition(id, isSource, frames * frameSize);
}
if (Printer.debug) Printer.debug(" DirectClip.setFramePosition: "
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/EmergencySoundbank.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/EmergencySoundbank.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,2695 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.media.sound;
+
+import java.util.Random;
+
+import javax.sound.midi.Patch;
+import javax.sound.sampled.AudioFormat;
+
+/**
+ * Emergency Soundbank generator.
+ * Used when no other default soundbank can be found.
+ *
+ * @author Karl Helgason
+ */
+public class EmergencySoundbank {
+
+ private final static String[] general_midi_instruments = {
+ "Acoustic Grand Piano",
+ "Bright Acoustic Piano",
+ "Electric Grand Piano",
+ "Honky-tonk Piano",
+ "Electric Piano 1",
+ "Electric Piano 2",
+ "Harpsichord",
+ "Clavi",
+ "Celesta",
+ "Glockenspiel",
+ "Music Box",
+ "Vibraphone",
+ "Marimba",
+ "Xylophone",
+ "Tubular Bells",
+ "Dulcimer",
+ "Drawbar Organ",
+ "Percussive Organ",
+ "Rock Organ",
+ "Church Organ",
+ "Reed Organ",
+ "Accordion",
+ "Harmonica",
+ "Tango Accordion",
+ "Acoustic Guitar (nylon)",
+ "Acoustic Guitar (steel)",
+ "Electric Guitar (jazz)",
+ "Electric Guitar (clean)",
+ "Electric Guitar (muted)",
+ "Overdriven Guitar",
+ "Distortion Guitar",
+ "Guitar harmonics",
+ "Acoustic Bass",
+ "Electric Bass (finger)",
+ "Electric Bass (pick)",
+ "Fretless Bass",
+ "Slap Bass 1",
+ "Slap Bass 2",
+ "Synth Bass 1",
+ "Synth Bass 2",
+ "Violin",
+ "Viola",
+ "Cello",
+ "Contrabass",
+ "Tremolo Strings",
+ "Pizzicato Strings",
+ "Orchestral Harp",
+ "Timpani",
+ "String Ensemble 1",
+ "String Ensemble 2",
+ "SynthStrings 1",
+ "SynthStrings 2",
+ "Choir Aahs",
+ "Voice Oohs",
+ "Synth Voice",
+ "Orchestra Hit",
+ "Trumpet",
+ "Trombone",
+ "Tuba",
+ "Muted Trumpet",
+ "French Horn",
+ "Brass Section",
+ "SynthBrass 1",
+ "SynthBrass 2",
+ "Soprano Sax",
+ "Alto Sax",
+ "Tenor Sax",
+ "Baritone Sax",
+ "Oboe",
+ "English Horn",
+ "Bassoon",
+ "Clarinet",
+ "Piccolo",
+ "Flute",
+ "Recorder",
+ "Pan Flute",
+ "Blown Bottle",
+ "Shakuhachi",
+ "Whistle",
+ "Ocarina",
+ "Lead 1 (square)",
+ "Lead 2 (sawtooth)",
+ "Lead 3 (calliope)",
+ "Lead 4 (chiff)",
+ "Lead 5 (charang)",
+ "Lead 6 (voice)",
+ "Lead 7 (fifths)",
+ "Lead 8 (bass + lead)",
+ "Pad 1 (new age)",
+ "Pad 2 (warm)",
+ "Pad 3 (polysynth)",
+ "Pad 4 (choir)",
+ "Pad 5 (bowed)",
+ "Pad 6 (metallic)",
+ "Pad 7 (halo)",
+ "Pad 8 (sweep)",
+ "FX 1 (rain)",
+ "FX 2 (soundtrack)",
+ "FX 3 (crystal)",
+ "FX 4 (atmosphere)",
+ "FX 5 (brightness)",
+ "FX 6 (goblins)",
+ "FX 7 (echoes)",
+ "FX 8 (sci-fi)",
+ "Sitar",
+ "Banjo",
+ "Shamisen",
+ "Koto",
+ "Kalimba",
+ "Bag pipe",
+ "Fiddle",
+ "Shanai",
+ "Tinkle Bell",
+ "Agogo",
+ "Steel Drums",
+ "Woodblock",
+ "Taiko Drum",
+ "Melodic Tom",
+ "Synth Drum",
+ "Reverse Cymbal",
+ "Guitar Fret Noise",
+ "Breath Noise",
+ "Seashore",
+ "Bird Tweet",
+ "Telephone Ring",
+ "Helicopter",
+ "Applause",
+ "Gunshot"
+ };
+
+ public static SF2Soundbank createSoundbank() throws Exception {
+ SF2Soundbank sf2 = new SF2Soundbank();
+ sf2.setName("Emergency GM sound set");
+ sf2.setVendor("Generated");
+ sf2.setDescription("Emergency generated soundbank");
+
+ /*
+ * percussion instruments
+ */
+
+ SF2Layer bass_drum = new_bass_drum(sf2);
+ SF2Layer snare_drum = new_snare_drum(sf2);
+ SF2Layer tom = new_tom(sf2);
+ SF2Layer open_hihat = new_open_hihat(sf2);
+ SF2Layer closed_hihat = new_closed_hihat(sf2);
+ SF2Layer crash_cymbal = new_crash_cymbal(sf2);
+ SF2Layer side_stick = new_side_stick(sf2);
+
+ SF2Layer[] drums = new SF2Layer[128];
+ drums[35] = bass_drum;
+ drums[36] = bass_drum;
+ drums[38] = snare_drum;
+ drums[40] = snare_drum;
+ drums[41] = tom;
+ drums[43] = tom;
+ drums[45] = tom;
+ drums[47] = tom;
+ drums[48] = tom;
+ drums[50] = tom;
+ drums[42] = closed_hihat;
+ drums[44] = closed_hihat;
+ drums[46] = open_hihat;
+ drums[49] = crash_cymbal;
+ drums[51] = crash_cymbal;
+ drums[52] = crash_cymbal;
+ drums[55] = crash_cymbal;
+ drums[57] = crash_cymbal;
+ drums[59] = crash_cymbal;
+
+ // Use side_stick for missing drums:
+ drums[37] = side_stick;
+ drums[39] = side_stick;
+ drums[53] = side_stick;
+ drums[54] = side_stick;
+ drums[56] = side_stick;
+ drums[58] = side_stick;
+ drums[69] = side_stick;
+ drums[70] = side_stick;
+ drums[75] = side_stick;
+ drums[60] = side_stick;
+ drums[61] = side_stick;
+ drums[62] = side_stick;
+ drums[63] = side_stick;
+ drums[64] = side_stick;
+ drums[65] = side_stick;
+ drums[66] = side_stick;
+ drums[67] = side_stick;
+ drums[68] = side_stick;
+ drums[71] = side_stick;
+ drums[72] = side_stick;
+ drums[73] = side_stick;
+ drums[74] = side_stick;
+ drums[76] = side_stick;
+ drums[77] = side_stick;
+ drums[78] = side_stick;
+ drums[79] = side_stick;
+ drums[80] = side_stick;
+ drums[81] = side_stick;
+
+
+ SF2Instrument drum_instrument = new SF2Instrument(sf2);
+ drum_instrument.setName("Standard Kit");
+ drum_instrument.setPatch(new ModelPatch(0, 0, true));
+ sf2.addInstrument(drum_instrument);
+ for (int i = 0; i < drums.length; i++) {
+ if (drums[i] != null) {
+ SF2InstrumentRegion region = new SF2InstrumentRegion();
+ region.setLayer(drums[i]);
+ region.putBytes(SF2InstrumentRegion.GENERATOR_KEYRANGE,
+ new byte[]{(byte) i, (byte) i});
+ drum_instrument.getRegions().add(region);
+ }
+ }
+
+
+ /*
+ * melodic instruments
+ */
+
+ SF2Layer gpiano = new_gpiano(sf2);
+ SF2Layer gpiano2 = new_gpiano2(sf2);
+ SF2Layer gpiano_hammer = new_piano_hammer(sf2);
+ SF2Layer piano1 = new_piano1(sf2);
+ SF2Layer epiano1 = new_epiano1(sf2);
+ SF2Layer epiano2 = new_epiano2(sf2);
+
+ SF2Layer guitar = new_guitar1(sf2);
+ SF2Layer guitar_pick = new_guitar_pick(sf2);
+ SF2Layer guitar_dist = new_guitar_dist(sf2);
+ SF2Layer bass1 = new_bass1(sf2);
+ SF2Layer bass2 = new_bass2(sf2);
+ SF2Layer synthbass = new_synthbass(sf2);
+ SF2Layer string2 = new_string2(sf2);
+ SF2Layer orchhit = new_orchhit(sf2);
+ SF2Layer choir = new_choir(sf2);
+ SF2Layer solostring = new_solostring(sf2);
+ SF2Layer organ = new_organ(sf2);
+ SF2Layer ch_organ = new_ch_organ(sf2);
+ SF2Layer bell = new_bell(sf2);
+ SF2Layer flute = new_flute(sf2);
+
+ SF2Layer timpani = new_timpani(sf2);
+ SF2Layer melodic_toms = new_melodic_toms(sf2);
+ SF2Layer trumpet = new_trumpet(sf2);
+ SF2Layer trombone = new_trombone(sf2);
+ SF2Layer brass_section = new_brass_section(sf2);
+ SF2Layer horn = new_horn(sf2);
+ SF2Layer sax = new_sax(sf2);
+ SF2Layer oboe = new_oboe(sf2);
+ SF2Layer bassoon = new_bassoon(sf2);
+ SF2Layer clarinet = new_clarinet(sf2);
+ SF2Layer reverse_cymbal = new_reverse_cymbal(sf2);
+
+ SF2Layer defaultsound = piano1;
+
+ newInstrument(sf2, "Piano", new Patch(0, 0), gpiano, gpiano_hammer);
+ newInstrument(sf2, "Piano", new Patch(0, 1), gpiano2, gpiano_hammer);
+ newInstrument(sf2, "Piano", new Patch(0, 2), piano1);
+ {
+ SF2Instrument ins = newInstrument(sf2, "Honky-tonk Piano",
+ new Patch(0, 3), piano1, piano1);
+ SF2InstrumentRegion region = ins.getRegions().get(0);
+ region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 80);
+ region.putInteger(SF2Region.GENERATOR_FINETUNE, 30);
+ region = ins.getRegions().get(1);
+ region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 30);
+ }
+ newInstrument(sf2, "Rhodes", new Patch(0, 4), epiano2);
+ newInstrument(sf2, "Rhodes", new Patch(0, 5), epiano2);
+ newInstrument(sf2, "Clavinet", new Patch(0, 6), epiano1);
+ newInstrument(sf2, "Clavinet", new Patch(0, 7), epiano1);
+ newInstrument(sf2, "Rhodes", new Patch(0, 8), epiano2);
+ newInstrument(sf2, "Bell", new Patch(0, 9), bell);
+ newInstrument(sf2, "Bell", new Patch(0, 10), bell);
+ newInstrument(sf2, "Vibraphone", new Patch(0, 11), bell);
+ newInstrument(sf2, "Marimba", new Patch(0, 12), bell);
+ newInstrument(sf2, "Marimba", new Patch(0, 13), bell);
+ newInstrument(sf2, "Bell", new Patch(0, 14), bell);
+ newInstrument(sf2, "Rock Organ", new Patch(0, 15), organ);
+ newInstrument(sf2, "Rock Organ", new Patch(0, 16), organ);
+ newInstrument(sf2, "Perc Organ", new Patch(0, 17), organ);
+ newInstrument(sf2, "Rock Organ", new Patch(0, 18), organ);
+ newInstrument(sf2, "Church Organ", new Patch(0, 19), ch_organ);
+ newInstrument(sf2, "Accordion", new Patch(0, 20), organ);
+ newInstrument(sf2, "Accordion", new Patch(0, 21), organ);
+ newInstrument(sf2, "Accordion", new Patch(0, 22), organ);
+ newInstrument(sf2, "Accordion", new Patch(0, 23), organ);
+ newInstrument(sf2, "Guitar", new Patch(0, 24), guitar, guitar_pick);
+ newInstrument(sf2, "Guitar", new Patch(0, 25), guitar, guitar_pick);
+ newInstrument(sf2, "Guitar", new Patch(0, 26), guitar, guitar_pick);
+ newInstrument(sf2, "Guitar", new Patch(0, 27), guitar, guitar_pick);
+ newInstrument(sf2, "Guitar", new Patch(0, 28), guitar, guitar_pick);
+ newInstrument(sf2, "Distorted Guitar", new Patch(0, 29), guitar_dist);
+ newInstrument(sf2, "Distorted Guitar", new Patch(0, 30), guitar_dist);
+ newInstrument(sf2, "Guitar", new Patch(0, 31), guitar, guitar_pick);
+ newInstrument(sf2, "Finger Bass", new Patch(0, 32), bass1);
+ newInstrument(sf2, "Finger Bass", new Patch(0, 33), bass1);
+ newInstrument(sf2, "Finger Bass", new Patch(0, 34), bass1);
+ newInstrument(sf2, "Frettless Bass", new Patch(0, 35), bass2);
+ newInstrument(sf2, "Frettless Bass", new Patch(0, 36), bass2);
+ newInstrument(sf2, "Frettless Bass", new Patch(0, 37), bass2);
+ newInstrument(sf2, "Synth Bass1", new Patch(0, 38), synthbass);
+ newInstrument(sf2, "Synth Bass2", new Patch(0, 39), synthbass);
+ newInstrument(sf2, "Solo String", new Patch(0, 40), string2, solostring);
+ newInstrument(sf2, "Solo String", new Patch(0, 41), string2, solostring);
+ newInstrument(sf2, "Solo String", new Patch(0, 42), string2, solostring);
+ newInstrument(sf2, "Solo String", new Patch(0, 43), string2, solostring);
+ newInstrument(sf2, "Solo String", new Patch(0, 44), string2, solostring);
+ newInstrument(sf2, "Def", new Patch(0, 45), defaultsound);
+ newInstrument(sf2, "Harp", new Patch(0, 46), bell);
+ newInstrument(sf2, "Timpani", new Patch(0, 47), timpani);
+ newInstrument(sf2, "Strings", new Patch(0, 48), string2);
+ SF2Instrument slow_strings =
+ newInstrument(sf2, "Slow Strings", new Patch(0, 49), string2);
+ SF2InstrumentRegion region = slow_strings.getRegions().get(0);
+ region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, 2500);
+ region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 2000);
+ newInstrument(sf2, "Synth Strings", new Patch(0, 50), string2);
+ newInstrument(sf2, "Synth Strings", new Patch(0, 51), string2);
+
+
+ newInstrument(sf2, "Choir", new Patch(0, 52), choir);
+ newInstrument(sf2, "Choir", new Patch(0, 53), choir);
+ newInstrument(sf2, "Choir", new Patch(0, 54), choir);
+ {
+ SF2Instrument ins = newInstrument(sf2, "Orch Hit",
+ new Patch(0, 55), orchhit, orchhit, timpani);
+ region = ins.getRegions().get(0);
+ region.putInteger(SF2Region.GENERATOR_COARSETUNE, -12);
+ region.putInteger(SF2Region.GENERATOR_INITIALATTENUATION, -100);
+ }
+ newInstrument(sf2, "Trumpet", new Patch(0, 56), trumpet);
+ newInstrument(sf2, "Trombone", new Patch(0, 57), trombone);
+ newInstrument(sf2, "Trombone", new Patch(0, 58), trombone);
+ newInstrument(sf2, "Trumpet", new Patch(0, 59), trumpet);
+ newInstrument(sf2, "Horn", new Patch(0, 60), horn);
+ newInstrument(sf2, "Brass Section", new Patch(0, 61), brass_section);
+ newInstrument(sf2, "Brass Section", new Patch(0, 62), brass_section);
+ newInstrument(sf2, "Brass Section", new Patch(0, 63), brass_section);
+ newInstrument(sf2, "Sax", new Patch(0, 64), sax);
+ newInstrument(sf2, "Sax", new Patch(0, 65), sax);
+ newInstrument(sf2, "Sax", new Patch(0, 66), sax);
+ newInstrument(sf2, "Sax", new Patch(0, 67), sax);
+ newInstrument(sf2, "Oboe", new Patch(0, 68), oboe);
+ newInstrument(sf2, "Horn", new Patch(0, 69), horn);
+ newInstrument(sf2, "Bassoon", new Patch(0, 70), bassoon);
+ newInstrument(sf2, "Clarinet", new Patch(0, 71), clarinet);
+ newInstrument(sf2, "Flute", new Patch(0, 72), flute);
+ newInstrument(sf2, "Flute", new Patch(0, 73), flute);
+ newInstrument(sf2, "Flute", new Patch(0, 74), flute);
+ newInstrument(sf2, "Flute", new Patch(0, 75), flute);
+ newInstrument(sf2, "Flute", new Patch(0, 76), flute);
+ newInstrument(sf2, "Flute", new Patch(0, 77), flute);
+ newInstrument(sf2, "Flute", new Patch(0, 78), flute);
+ newInstrument(sf2, "Flute", new Patch(0, 79), flute);
+ newInstrument(sf2, "Organ", new Patch(0, 80), organ);
+ newInstrument(sf2, "Organ", new Patch(0, 81), organ);
+ newInstrument(sf2, "Flute", new Patch(0, 82), flute);
+ newInstrument(sf2, "Organ", new Patch(0, 83), organ);
+ newInstrument(sf2, "Organ", new Patch(0, 84), organ);
+ newInstrument(sf2, "Choir", new Patch(0, 85), choir);
+ newInstrument(sf2, "Organ", new Patch(0, 86), organ);
+ newInstrument(sf2, "Organ", new Patch(0, 87), organ);
+ newInstrument(sf2, "Synth Strings", new Patch(0, 88), string2);
+ newInstrument(sf2, "Organ", new Patch(0, 89), organ);
+ newInstrument(sf2, "Def", new Patch(0, 90), defaultsound);
+ newInstrument(sf2, "Choir", new Patch(0, 91), choir);
+ newInstrument(sf2, "Organ", new Patch(0, 92), organ);
+ newInstrument(sf2, "Organ", new Patch(0, 93), organ);
+ newInstrument(sf2, "Organ", new Patch(0, 94), organ);
+ newInstrument(sf2, "Organ", new Patch(0, 95), organ);
+ newInstrument(sf2, "Organ", new Patch(0, 96), organ);
+ newInstrument(sf2, "Organ", new Patch(0, 97), organ);
+ newInstrument(sf2, "Bell", new Patch(0, 98), bell);
+ newInstrument(sf2, "Organ", new Patch(0, 99), organ);
+ newInstrument(sf2, "Organ", new Patch(0, 100), organ);
+ newInstrument(sf2, "Organ", new Patch(0, 101), organ);
+ newInstrument(sf2, "Def", new Patch(0, 102), defaultsound);
+ newInstrument(sf2, "Synth Strings", new Patch(0, 103), string2);
+ newInstrument(sf2, "Def", new Patch(0, 104), defaultsound);
+ newInstrument(sf2, "Def", new Patch(0, 105), defaultsound);
+ newInstrument(sf2, "Def", new Patch(0, 106), defaultsound);
+ newInstrument(sf2, "Def", new Patch(0, 107), defaultsound);
+ newInstrument(sf2, "Marimba", new Patch(0, 108), bell);
+ newInstrument(sf2, "Sax", new Patch(0, 109), sax);
+ newInstrument(sf2, "Solo String", new Patch(0, 110), string2, solostring);
+ newInstrument(sf2, "Oboe", new Patch(0, 111), oboe);
+ newInstrument(sf2, "Bell", new Patch(0, 112), bell);
+ newInstrument(sf2, "Melodic Toms", new Patch(0, 113), melodic_toms);
+ newInstrument(sf2, "Marimba", new Patch(0, 114), bell);
+ newInstrument(sf2, "Melodic Toms", new Patch(0, 115), melodic_toms);
+ newInstrument(sf2, "Melodic Toms", new Patch(0, 116), melodic_toms);
+ newInstrument(sf2, "Melodic Toms", new Patch(0, 117), melodic_toms);
+ newInstrument(sf2, "Reverse Cymbal", new Patch(0, 118), reverse_cymbal);
+ newInstrument(sf2, "Reverse Cymbal", new Patch(0, 119), reverse_cymbal);
+ newInstrument(sf2, "Guitar", new Patch(0, 120), guitar);
+ newInstrument(sf2, "Def", new Patch(0, 121), defaultsound);
+ {
+ SF2Instrument ins = newInstrument(sf2, "Seashore/Reverse Cymbal",
+ new Patch(0, 122), reverse_cymbal);
+ region = ins.getRegions().get(0);
+ region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, 1000);
+ region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 18500);
+ region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 4500);
+ region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, -4500);
+ }
+ {
+ SF2Instrument ins = newInstrument(sf2, "Bird/Flute",
+ new Patch(0, 123), flute);
+ region = ins.getRegions().get(0);
+ region.putInteger(SF2Region.GENERATOR_COARSETUNE, 24);
+ region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, -3000);
+ region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, 1000);
+ }
+ newInstrument(sf2, "Def", new Patch(0, 124), side_stick);
+ {
+ SF2Instrument ins = newInstrument(sf2, "Seashore/Reverse Cymbal",
+ new Patch(0, 125), reverse_cymbal);
+ region = ins.getRegions().get(0);
+ region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, 1000);
+ region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 18500);
+ region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 4500);
+ region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, -4500);
+ }
+ newInstrument(sf2, "Applause/crash_cymbal",
+ new Patch(0, 126), crash_cymbal);
+ newInstrument(sf2, "Gunshot/side_stick", new Patch(0, 127), side_stick);
+
+ for (SF2Instrument instrument : sf2.getInstruments()) {
+ Patch patch = instrument.getPatch();
+ if (patch instanceof ModelPatch) {
+ if (((ModelPatch) patch).isPercussion())
+ continue;
+ }
+ instrument.setName(general_midi_instruments[patch.getProgram()]);
+ }
+
+ return sf2;
+
+ }
+
+ public static SF2Layer new_bell(SF2Soundbank sf2) {
+ Random random = new Random(102030201);
+ int x = 8;
+ int fftsize = 4096 * x;
+ double[] data = new double[fftsize * 2];
+ double base = x * 25;
+ double start_w = 0.01;
+ double end_w = 0.05;
+ double start_a = 0.2;
+ double end_a = 0.00001;
+ double a = start_a;
+ double a_step = Math.pow(end_a / start_a, 1.0 / 40.0);
+ for (int i = 0; i < 40; i++) {
+ double detune = 1 + (random.nextDouble() * 2 - 1) * 0.01;
+ double w = start_w + (end_w - start_w) * (i / 40.0);
+ complexGaussianDist(data, base * (i + 1) * detune, w, a);
+ a *= a_step;
+ }
+ SF2Sample sample = newSimpleFFTSample(sf2, "EPiano", data, base);
+ SF2Layer layer = newLayer(sf2, "EPiano", sample);
+ SF2Region region = layer.getRegions().get(0);
+ region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1);
+ region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -12000);
+ region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 0);
+ region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 4000);
+ region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, 1000);
+ region.putInteger(SF2Region.GENERATOR_ATTACKMODENV, 1200);
+ region.putInteger(SF2Region.GENERATOR_RELEASEMODENV, 12000);
+ region.putInteger(SF2Region.GENERATOR_MODENVTOFILTERFC, -9000);
+ region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 16000);
+ return layer;
+ }
+
+ public static SF2Layer new_guitar1(SF2Soundbank sf2) {
+
+ int x = 8;
+ int fftsize = 4096 * x;
+ double[] data = new double[fftsize * 2];
+ double base = x * 25;
+ double start_w = 0.01;
+ double end_w = 0.01;
+ double start_a = 2;
+ double end_a = 0.01;
+ double a = start_a;
+ double a_step = Math.pow(end_a / start_a, 1.0 / 40.0);
+
+ double[] aa = new double[40];
+ for (int i = 0; i < 40; i++) {
+ aa[i] = a;
+ a *= a_step;
+ }
+
+ aa[0] = 2;
+ aa[1] = 0.5;
+ aa[2] = 0.45;
+ aa[3] = 0.2;
+ aa[4] = 1;
+ aa[5] = 0.5;
+ aa[6] = 2;
+ aa[7] = 1;
+ aa[8] = 0.5;
+ aa[9] = 1;
+ aa[9] = 0.5;
+ aa[10] = 0.2;
+ aa[11] = 1;
+ aa[12] = 0.7;
+ aa[13] = 0.5;
+ aa[14] = 1;
+
+ for (int i = 0; i < 40; i++) {
+ double w = start_w + (end_w - start_w) * (i / 40.0);
+ complexGaussianDist(data, base * (i + 1), w, aa[i]);
+ }
+
+ SF2Sample sample = newSimpleFFTSample(sf2, "Guitar", data, base);
+ SF2Layer layer = newLayer(sf2, "Guitar", sample);
+ SF2Region region = layer.getRegions().get(0);
+ region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1);
+ region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -12000);
+ region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 0);
+ region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 2400);
+ region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, 1000);
+
+ region.putInteger(SF2Region.GENERATOR_ATTACKMODENV, -100);
+ region.putInteger(SF2Region.GENERATOR_RELEASEMODENV, 12000);
+ region.putInteger(SF2Region.GENERATOR_MODENVTOFILTERFC, -6000);
+ region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 16000);
+ region.putInteger(SF2Region.GENERATOR_INITIALATTENUATION, -20);
+ return layer;
+ }
+
+ public static SF2Layer new_guitar_dist(SF2Soundbank sf2) {
+
+ int x = 8;
+ int fftsize = 4096 * x;
+ double[] data = new double[fftsize * 2];
+ double base = x * 25;
+ double start_w = 0.01;
+ double end_w = 0.01;
+ double start_a = 2;
+ double end_a = 0.01;
+ double a = start_a;
+ double a_step = Math.pow(end_a / start_a, 1.0 / 40.0);
+
+ double[] aa = new double[40];
+ for (int i = 0; i < 40; i++) {
+ aa[i] = a;
+ a *= a_step;
+ }
+
+ aa[0] = 5;
+ aa[1] = 2;
+ aa[2] = 0.45;
+ aa[3] = 0.2;
+ aa[4] = 1;
+ aa[5] = 0.5;
+ aa[6] = 2;
+ aa[7] = 1;
+ aa[8] = 0.5;
+ aa[9] = 1;
+ aa[9] = 0.5;
+ aa[10] = 0.2;
+ aa[11] = 1;
+ aa[12] = 0.7;
+ aa[13] = 0.5;
+ aa[14] = 1;
+
+ for (int i = 0; i < 40; i++) {
+ double w = start_w + (end_w - start_w) * (i / 40.0);
+ complexGaussianDist(data, base * (i + 1), w, aa[i]);
+ }
+
+
+ SF2Sample sample = newSimpleFFTSample_dist(sf2, "Distorted Guitar",
+ data, base, 10000.0);
+
+
+ SF2Layer layer = newLayer(sf2, "Distorted Guitar", sample);
+ SF2Region region = layer.getRegions().get(0);
+ region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1);
+ region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -12000);
+ region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 0);
+ //region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 2400);
+ //region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, 200);
+
+ //region.putInteger(SF2Region.GENERATOR_ATTACKMODENV, -100);
+ //region.putInteger(SF2Region.GENERATOR_RELEASEMODENV, 12000);
+ //region.putInteger(SF2Region.GENERATOR_MODENVTOFILTERFC, -1000);
+ region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 8000);
+ //region.putInteger(SF2Region.GENERATOR_INITIALATTENUATION, -20);
+ return layer;
+ }
+
+ public static SF2Layer new_guitar_pick(SF2Soundbank sf2) {
+
+ double datab[];
+
+ // Make treble part
+ {
+ int m = 2;
+ int fftlen = 4096 * m;
+ double[] data = new double[2 * fftlen];
+ Random random = new Random(3049912);
+ for (int i = 0; i < data.length; i += 2)
+ data[i] = (2.0 * (random.nextDouble() - 0.5));
+ fft(data);
+ // Remove all negative frequency
+ for (int i = fftlen / 2; i < data.length; i++)
+ data[i] = 0;
+ for (int i = 0; i < 2048 * m; i++) {
+ data[i] *= Math.exp(-Math.abs((i - 23) / ((double) m)) * 1.2)
+ + Math.exp(-Math.abs((i - 40) / ((double) m)) * 0.9);
+ }
+ randomPhase(data, new Random(3049912));
+ ifft(data);
+ normalize(data, 0.8);
+ data = realPart(data);
+ double gain = 1.0;
+ for (int i = 0; i < data.length; i++) {
+ data[i] *= gain;
+ gain *= 0.9994;
+ }
+ datab = data;
+
+ fadeUp(data, 80);
+ }
+
+ SF2Sample sample = newSimpleDrumSample(sf2, "Guitar Noise", datab);
+
+ SF2Layer layer = new SF2Layer(sf2);
+ layer.setName("Guitar Noise");
+
+ SF2GlobalRegion global = new SF2GlobalRegion();
+ layer.setGlobalZone(global);
+ sf2.addResource(layer);
+
+ SF2LayerRegion region = new SF2LayerRegion();
+ region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 12000);
+ //region.putInteger(SF2Region.GENERATOR_SCALETUNING, 0);
+// region.putInteger(SF2Region.GENERATOR_INITIALATTENUATION, -100);
+/*
+ region.putInteger(SF2Region.GENERATOR_ATTACKMODENV, 0);
+ region.putInteger(SF2Region.GENERATOR_SUSTAINMODENV, 1000);
+ region.putInteger(SF2Region.GENERATOR_RELEASEMODENV, 12000);
+ region.putInteger(SF2Region.GENERATOR_MODENVTOFILTERFC, -11000);
+ region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 12000);
+ */
+
+ region.setSample(sample);
+ layer.getRegions().add(region);
+
+ return layer;
+ }
+
+ public static SF2Layer new_gpiano(SF2Soundbank sf2) {
+ //Random random = new Random(302030201);
+ int x = 8;
+ int fftsize = 4096 * x;
+ double[] data = new double[fftsize * 2];
+ double base = x * 25;
+ double start_a = 0.2;
+ double end_a = 0.001;
+ double a = start_a;
+ double a_step = Math.pow(end_a / start_a, 1.0 / 15.0);
+
+ double[] aa = new double[30];
+ for (int i = 0; i < 30; i++) {
+ aa[i] = a;
+ a *= a_step;
+ }
+
+ aa[0] *= 2;
+ //aa[2] *= 0.1;
+ aa[4] *= 2;
+
+
+ aa[12] *= 0.9;
+ aa[13] *= 0.7;
+ for (int i = 14; i < 30; i++) {
+ aa[i] *= 0.5;
+ }
+
+
+ for (int i = 0; i < 30; i++) {
+ //double detune = 1 + (random.nextDouble()*2 - 1)*0.0001;
+ double w = 0.2;
+ double ai = aa[i];
+ if (i > 10) {
+ w = 5;
+ ai *= 10;
+ }
+ int adjust = 0;
+ if (i > 5) {
+ adjust = (i - 5) * 7;
+ }
+ complexGaussianDist(data, base * (i + 1) + adjust, w, ai);
+ }
+
+ SF2Sample sample = newSimpleFFTSample(sf2, "Grand Piano", data, base, 200);
+ SF2Layer layer = newLayer(sf2, "Grand Piano", sample);
+ SF2Region region = layer.getRegions().get(0);
+ region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1);
+ region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -7000);
+ region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 0);
+ region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 4000);
+ region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, 1000);
+ region.putInteger(SF2Region.GENERATOR_ATTACKMODENV, -6000);
+ region.putInteger(SF2Region.GENERATOR_RELEASEMODENV, 12000);
+ region.putInteger(SF2Region.GENERATOR_MODENVTOFILTERFC, -5500);
+ region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 18000);
+ return layer;
+ }
+
+ public static SF2Layer new_gpiano2(SF2Soundbank sf2) {
+ //Random random = new Random(302030201);
+ int x = 8;
+ int fftsize = 4096 * x;
+ double[] data = new double[fftsize * 2];
+ double base = x * 25;
+ double start_a = 0.2;
+ double end_a = 0.001;
+ double a = start_a;
+ double a_step = Math.pow(end_a / start_a, 1.0 / 20.0);
+
+ double[] aa = new double[30];
+ for (int i = 0; i < 30; i++) {
+ aa[i] = a;
+ a *= a_step;
+ }
+
+ aa[0] *= 1;
+ //aa[2] *= 0.1;
+ aa[4] *= 2;
+
+
+ aa[12] *= 0.9;
+ aa[13] *= 0.7;
+ for (int i = 14; i < 30; i++) {
+ aa[i] *= 0.5;
+ }
+
+
+ for (int i = 0; i < 30; i++) {
+ //double detune = 1 + (random.nextDouble()*2 - 1)*0.0001;
+ double w = 0.2;
+ double ai = aa[i];
+ if (i > 10) {
+ w = 5;
+ ai *= 10;
+ }
+ int adjust = 0;
+ if (i > 5) {
+ adjust = (i - 5) * 7;
+ }
+ complexGaussianDist(data, base * (i + 1) + adjust, w, ai);
+ }
+
+ SF2Sample sample = newSimpleFFTSample(sf2, "Grand Piano", data, base, 200);
+ SF2Layer layer = newLayer(sf2, "Grand Piano", sample);
+ SF2Region region = layer.getRegions().get(0);
+ region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1);
+ region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -7000);
+ region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 0);
+ region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 4000);
+ region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, 1000);
+ region.putInteger(SF2Region.GENERATOR_ATTACKMODENV, -6000);
+ region.putInteger(SF2Region.GENERATOR_RELEASEMODENV, 12000);
+ region.putInteger(SF2Region.GENERATOR_MODENVTOFILTERFC, -5500);
+ region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 18000);
+ return layer;
+ }
+
+ public static SF2Layer new_piano_hammer(SF2Soundbank sf2) {
+
+ double datab[];
+
+ // Make treble part
+ {
+ int m = 2;
+ int fftlen = 4096 * m;
+ double[] data = new double[2 * fftlen];
+ Random random = new Random(3049912);
+ for (int i = 0; i < data.length; i += 2)
+ data[i] = (2.0 * (random.nextDouble() - 0.5));
+ fft(data);
+ // Remove all negative frequency
+ for (int i = fftlen / 2; i < data.length; i++)
+ data[i] = 0;
+ for (int i = 0; i < 2048 * m; i++)
+ data[i] *= Math.exp(-Math.abs((i - 37) / ((double) m)) * 0.05);
+ randomPhase(data, new Random(3049912));
+ ifft(data);
+ normalize(data, 0.6);
+ data = realPart(data);
+ double gain = 1.0;
+ for (int i = 0; i < data.length; i++) {
+ data[i] *= gain;
+ gain *= 0.9997;
+ }
+ datab = data;
+
+ fadeUp(data, 80);
+ }
+
+ SF2Sample sample = newSimpleDrumSample(sf2, "Piano Hammer", datab);
+
+ SF2Layer layer = new SF2Layer(sf2);
+ layer.setName("Piano Hammer");
+
+ SF2GlobalRegion global = new SF2GlobalRegion();
+ layer.setGlobalZone(global);
+ sf2.addResource(layer);
+
+ SF2LayerRegion region = new SF2LayerRegion();
+ region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 12000);
+ //region.putInteger(SF2Region.GENERATOR_SCALETUNING, 0);
+/*
+ region.putInteger(SF2Region.GENERATOR_ATTACKMODENV, 0);
+ region.putInteger(SF2Region.GENERATOR_SUSTAINMODENV, 1000);
+ region.putInteger(SF2Region.GENERATOR_RELEASEMODENV, 12000);
+ region.putInteger(SF2Region.GENERATOR_MODENVTOFILTERFC, -11000);
+ region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 12000);
+ */
+
+ region.setSample(sample);
+ layer.getRegions().add(region);
+
+ return layer;
+ }
+
+ public static SF2Layer new_piano1(SF2Soundbank sf2) {
+ //Random random = new Random(302030201);
+ int x = 8;
+ int fftsize = 4096 * x;
+ double[] data = new double[fftsize * 2];
+ double base = x * 25;
+ double start_a = 0.2;
+ double end_a = 0.0001;
+ double a = start_a;
+ double a_step = Math.pow(end_a / start_a, 1.0 / 40.0);
+
+ double[] aa = new double[30];
+ for (int i = 0; i < 30; i++) {
+ aa[i] = a;
+ a *= a_step;
+ }
+
+ aa[0] *= 5;
+ aa[2] *= 0.1;
+ aa[7] *= 5;
+
+
+ for (int i = 0; i < 30; i++) {
+ //double detune = 1 + (random.nextDouble()*2 - 1)*0.0001;
+ double w = 0.2;
+ double ai = aa[i];
+ if (i > 12) {
+ w = 5;
+ ai *= 10;
+ }
+ int adjust = 0;
+ if (i > 5) {
+ adjust = (i - 5) * 7;
+ }
+ complexGaussianDist(data, base * (i + 1) + adjust, w, ai);
+ }
+
+ complexGaussianDist(data, base * (15.5), 1, 0.1);
+ complexGaussianDist(data, base * (17.5), 1, 0.01);
+
+ SF2Sample sample = newSimpleFFTSample(sf2, "EPiano", data, base, 200);
+ SF2Layer layer = newLayer(sf2, "EPiano", sample);
+ SF2Region region = layer.getRegions().get(0);
+ region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1);
+ region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -12000);
+ region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 0);
+ region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 4000);
+ region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, 1000);
+ region.putInteger(SF2Region.GENERATOR_ATTACKMODENV, -1200);
+ region.putInteger(SF2Region.GENERATOR_RELEASEMODENV, 12000);
+ region.putInteger(SF2Region.GENERATOR_MODENVTOFILTERFC, -5500);
+ region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 16000);
+ return layer;
+ }
+
+ public static SF2Layer new_epiano1(SF2Soundbank sf2) {
+ Random random = new Random(302030201);
+ int x = 8;
+ int fftsize = 4096 * x;
+ double[] data = new double[fftsize * 2];
+ double base = x * 25;
+ double start_w = 0.05;
+ double end_w = 0.05;
+ double start_a = 0.2;
+ double end_a = 0.0001;
+ double a = start_a;
+ double a_step = Math.pow(end_a / start_a, 1.0 / 40.0);
+ for (int i = 0; i < 40; i++) {
+ double detune = 1 + (random.nextDouble() * 2 - 1) * 0.0001;
+ double w = start_w + (end_w - start_w) * (i / 40.0);
+ complexGaussianDist(data, base * (i + 1) * detune, w, a);
+ a *= a_step;
+ }
+
+
+
+ SF2Sample sample = newSimpleFFTSample(sf2, "EPiano", data, base);
+ SF2Layer layer = newLayer(sf2, "EPiano", sample);
+ SF2Region region = layer.getRegions().get(0);
+ region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1);
+ region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -12000);
+ region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 0);
+ region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 4000);
+ region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, 1000);
+ region.putInteger(SF2Region.GENERATOR_ATTACKMODENV, 1200);
+ region.putInteger(SF2Region.GENERATOR_RELEASEMODENV, 12000);
+ region.putInteger(SF2Region.GENERATOR_MODENVTOFILTERFC, -9000);
+ region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 16000);
+ return layer;
+ }
+
+ public static SF2Layer new_epiano2(SF2Soundbank sf2) {
+ Random random = new Random(302030201);
+ int x = 8;
+ int fftsize = 4096 * x;
+ double[] data = new double[fftsize * 2];
+ double base = x * 25;
+ double start_w = 0.01;
+ double end_w = 0.05;
+ double start_a = 0.2;
+ double end_a = 0.00001;
+ double a = start_a;
+ double a_step = Math.pow(end_a / start_a, 1.0 / 40.0);
+ for (int i = 0; i < 40; i++) {
+ double detune = 1 + (random.nextDouble() * 2 - 1) * 0.0001;
+ double w = start_w + (end_w - start_w) * (i / 40.0);
+ complexGaussianDist(data, base * (i + 1) * detune, w, a);
+ a *= a_step;
+ }
+
+ SF2Sample sample = newSimpleFFTSample(sf2, "EPiano", data, base);
+ SF2Layer layer = newLayer(sf2, "EPiano", sample);
+ SF2Region region = layer.getRegions().get(0);
+ region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1);
+ region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -12000);
+ region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 0);
+ region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 8000);
+ region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, 1000);
+ region.putInteger(SF2Region.GENERATOR_ATTACKMODENV, 2400);
+ region.putInteger(SF2Region.GENERATOR_RELEASEMODENV, 12000);
+ region.putInteger(SF2Region.GENERATOR_MODENVTOFILTERFC, -9000);
+ region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 16000);
+ region.putInteger(SF2Region.GENERATOR_INITIALATTENUATION, -100);
+ return layer;
+ }
+
+ public static SF2Layer new_bass1(SF2Soundbank sf2) {
+ int x = 8;
+ int fftsize = 4096 * x;
+ double[] data = new double[fftsize * 2];
+ double base = x * 25;
+ double start_w = 0.05;
+ double end_w = 0.05;
+ double start_a = 0.2;
+ double end_a = 0.02;
+ double a = start_a;
+ double a_step = Math.pow(end_a / start_a, 1.0 / 25.0);
+
+ double[] aa = new double[25];
+ for (int i = 0; i < 25; i++) {
+ aa[i] = a;
+ a *= a_step;
+ }
+
+ aa[0] *= 8;
+ aa[1] *= 4;
+ aa[3] *= 8;
+ aa[5] *= 8;
+
+ for (int i = 0; i < 25; i++) {
+ double w = start_w + (end_w - start_w) * (i / 40.0);
+ complexGaussianDist(data, base * (i + 1), w, aa[i]);
+ }
+
+
+ SF2Sample sample = newSimpleFFTSample(sf2, "Bass", data, base);
+ SF2Layer layer = newLayer(sf2, "Bass", sample);
+ SF2Region region = layer.getRegions().get(0);
+ region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1);
+ region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -12000);
+ region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 0);
+ region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 4000);
+ region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, 1000);
+ region.putInteger(SF2Region.GENERATOR_ATTACKMODENV, -3000);
+ region.putInteger(SF2Region.GENERATOR_RELEASEMODENV, 12000);
+ region.putInteger(SF2Region.GENERATOR_MODENVTOFILTERFC, -5000);
+ region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 11000);
+ region.putInteger(SF2Region.GENERATOR_INITIALATTENUATION, -100);
+ return layer;
+ }
+
+ public static SF2Layer new_synthbass(SF2Soundbank sf2) {
+ int x = 8;
+ int fftsize = 4096 * x;
+ double[] data = new double[fftsize * 2];
+ double base = x * 25;
+ double start_w = 0.05;
+ double end_w = 0.05;
+ double start_a = 0.2;
+ double end_a = 0.02;
+ double a = start_a;
+ double a_step = Math.pow(end_a / start_a, 1.0 / 25.0);
+
+ double[] aa = new double[25];
+ for (int i = 0; i < 25; i++) {
+ aa[i] = a;
+ a *= a_step;
+ }
+
+ aa[0] *= 16;
+ aa[1] *= 4;
+ aa[3] *= 16;
+ aa[5] *= 8;
+
+ for (int i = 0; i < 25; i++) {
+ double w = start_w + (end_w - start_w) * (i / 40.0);
+ complexGaussianDist(data, base * (i + 1), w, aa[i]);
+ }
+
+
+ SF2Sample sample = newSimpleFFTSample(sf2, "Bass", data, base);
+ SF2Layer layer = newLayer(sf2, "Bass", sample);
+ SF2Region region = layer.getRegions().get(0);
+ region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1);
+ region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -12000);
+ region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 0);
+ region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 4000);
+ region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, 1000);
+ region.putInteger(SF2Region.GENERATOR_ATTACKMODENV, -3000);
+ region.putInteger(SF2Region.GENERATOR_RELEASEMODENV, 12000);
+ region.putInteger(SF2Region.GENERATOR_MODENVTOFILTERFC, -3000);
+ region.putInteger(SF2Region.GENERATOR_INITIALFILTERQ, 100);
+ region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 8000);
+ region.putInteger(SF2Region.GENERATOR_INITIALATTENUATION, -100);
+ return layer;
+ }
+
+ public static SF2Layer new_bass2(SF2Soundbank sf2) {
+ int x = 8;
+ int fftsize = 4096 * x;
+ double[] data = new double[fftsize * 2];
+ double base = x * 25;
+ double start_w = 0.05;
+ double end_w = 0.05;
+ double start_a = 0.2;
+ double end_a = 0.002;
+ double a = start_a;
+ double a_step = Math.pow(end_a / start_a, 1.0 / 25.0);
+
+ double[] aa = new double[25];
+ for (int i = 0; i < 25; i++) {
+ aa[i] = a;
+ a *= a_step;
+ }
+
+ aa[0] *= 8;
+ aa[1] *= 4;
+ aa[3] *= 8;
+ aa[5] *= 8;
+
+ for (int i = 0; i < 25; i++) {
+ double w = start_w + (end_w - start_w) * (i / 40.0);
+ complexGaussianDist(data, base * (i + 1), w, aa[i]);
+ }
+
+
+ SF2Sample sample = newSimpleFFTSample(sf2, "Bass2", data, base);
+ SF2Layer layer = newLayer(sf2, "Bass2", sample);
+ SF2Region region = layer.getRegions().get(0);
+ region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1);
+ region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -8000);
+ region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 0);
+ region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 4000);
+ region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, 1000);
+ region.putInteger(SF2Region.GENERATOR_ATTACKMODENV, -6000);
+ region.putInteger(SF2Region.GENERATOR_RELEASEMODENV, 12000);
+ region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 5000);
+ region.putInteger(SF2Region.GENERATOR_INITIALATTENUATION, -100);
+ return layer;
+ }
+
+ public static SF2Layer new_solostring(SF2Soundbank sf2) {
+ int x = 8;
+ int fftsize = 4096 * x;
+ double[] data = new double[fftsize * 2];
+ double base = x * 25;
+ double start_w = 2;
+ double end_w = 2;
+ double start_a = 0.2;
+ double end_a = 0.01;
+
+ double[] aa = new double[18];
+ double a = start_a;
+ double a_step = Math.pow(end_a / start_a, 1.0 / 40.0);
+ for (int i = 0; i < aa.length; i++) {
+ a *= a_step;
+ aa[i] = a;
+ }
+
+ aa[0] *= 5;
+ aa[1] *= 5;
+ aa[2] *= 5;
+ aa[3] *= 4;
+ aa[4] *= 4;
+ aa[5] *= 3;
+ aa[6] *= 3;
+ aa[7] *= 2;
+
+ for (int i = 0; i < aa.length; i++) {
+ double w = start_w + (end_w - start_w) * (i / 40.0);
+ complexGaussianDist(data, base * (i + 1), w, a);
+ }
+ SF2Sample sample = newSimpleFFTSample(sf2, "Strings", data, base);
+ SF2Layer layer = newLayer(sf2, "Strings", sample);
+ SF2Region region = layer.getRegions().get(0);
+ region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1);
+ region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -5000);
+ region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 1000);
+ region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 4000);
+ region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, -100);
+ region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 9500);
+ region.putInteger(SF2Region.GENERATOR_FREQVIBLFO, -1000);
+ region.putInteger(SF2Region.GENERATOR_VIBLFOTOPITCH, 15);
+ return layer;
+
+ }
+
+ public static SF2Layer new_orchhit(SF2Soundbank sf2) {
+ int x = 8;
+ int fftsize = 4096 * x;
+ double[] data = new double[fftsize * 2];
+ double base = x * 25;
+ double start_w = 2;
+ double end_w = 80;
+ double start_a = 0.2;
+ double end_a = 0.001;
+ double a = start_a;
+ double a_step = Math.pow(end_a / start_a, 1.0 / 40.0);
+ for (int i = 0; i < 40; i++) {
+ double w = start_w + (end_w - start_w) * (i / 40.0);
+ complexGaussianDist(data, base * (i + 1), w, a);
+ a *= a_step;
+ }
+ complexGaussianDist(data, base * 4, 300, 1);
+
+
+ SF2Sample sample = newSimpleFFTSample(sf2, "Och Strings", data, base);
+ SF2Layer layer = newLayer(sf2, "Och Strings", sample);
+ SF2Region region = layer.getRegions().get(0);
+ region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1);
+ region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -5000);
+ region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 200);
+ region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 200);
+ region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, 1000);
+ region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 9500);
+ return layer;
+
+ }
+
+ public static SF2Layer new_string2(SF2Soundbank sf2) {
+ int x = 8;
+ int fftsize = 4096 * x;
+ double[] data = new double[fftsize * 2];
+ double base = x * 25;
+ double start_w = 2;
+ double end_w = 80;
+ double start_a = 0.2;
+ double end_a = 0.001;
+ double a = start_a;
+ double a_step = Math.pow(end_a / start_a, 1.0 / 40.0);
+ for (int i = 0; i < 40; i++) {
+ double w = start_w + (end_w - start_w) * (i / 40.0);
+ complexGaussianDist(data, base * (i + 1), w, a);
+ a *= a_step;
+ }
+ SF2Sample sample = newSimpleFFTSample(sf2, "Strings", data, base);
+ SF2Layer layer = newLayer(sf2, "Strings", sample);
+ SF2Region region = layer.getRegions().get(0);
+ region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1);
+ region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -5000);
+ region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 1000);
+ region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 4000);
+ region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, -100);
+ region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 9500);
+ return layer;
+
+ }
+
+ public static SF2Layer new_choir(SF2Soundbank sf2) {
+ int x = 8;
+ int fftsize = 4096 * x;
+ double[] data = new double[fftsize * 2];
+ double base = x * 25;
+ double start_w = 2;
+ double end_w = 80;
+ double start_a = 0.2;
+ double end_a = 0.001;
+ double a = start_a;
+ double a_step = Math.pow(end_a / start_a, 1.0 / 40.0);
+ double[] aa = new double[40];
+ for (int i = 0; i < aa.length; i++) {
+ a *= a_step;
+ aa[i] = a;
+ }
+
+ aa[5] *= 0.1;
+ aa[6] *= 0.01;
+ aa[7] *= 0.1;
+ aa[8] *= 0.1;
+
+ for (int i = 0; i < aa.length; i++) {
+ double w = start_w + (end_w - start_w) * (i / 40.0);
+ complexGaussianDist(data, base * (i + 1), w, aa[i]);
+ }
+ SF2Sample sample = newSimpleFFTSample(sf2, "Strings", data, base);
+ SF2Layer layer = newLayer(sf2, "Strings", sample);
+ SF2Region region = layer.getRegions().get(0);
+ region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1);
+ region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -5000);
+ region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 1000);
+ region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 4000);
+ region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, -100);
+ region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 9500);
+ return layer;
+
+ }
+
+ public static SF2Layer new_organ(SF2Soundbank sf2) {
+ Random random = new Random(102030201);
+ int x = 1;
+ int fftsize = 4096 * x;
+ double[] data = new double[fftsize * 2];
+ double base = x * 15;
+ double start_w = 0.01;
+ double end_w = 0.01;
+ double start_a = 0.2;
+ double end_a = 0.001;
+ double a = start_a;
+ double a_step = Math.pow(end_a / start_a, 1.0 / 40.0);
+
+ for (int i = 0; i < 12; i++) {
+ double w = start_w + (end_w - start_w) * (i / 40.0);
+ complexGaussianDist(data, base * (i + 1), w,
+ a * (0.5 + 3 * (random.nextDouble())));
+ a *= a_step;
+ }
+ SF2Sample sample = newSimpleFFTSample(sf2, "Organ", data, base);
+ SF2Layer layer = newLayer(sf2, "Organ", sample);
+ SF2Region region = layer.getRegions().get(0);
+ region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1);
+ region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -6000);
+ region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, -1000);
+ region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 4000);
+ region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, -100);
+ region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 9500);
+ return layer;
+
+ }
+
+ public static SF2Layer new_ch_organ(SF2Soundbank sf2) {
+ int x = 1;
+ int fftsize = 4096 * x;
+ double[] data = new double[fftsize * 2];
+ double base = x * 15;
+ double start_w = 0.01;
+ double end_w = 0.01;
+ double start_a = 0.2;
+ double end_a = 0.001;
+ double a = start_a;
+ double a_step = Math.pow(end_a / start_a, 1.0 / 60.0);
+
+ double[] aa = new double[60];
+ for (int i = 0; i < aa.length; i++) {
+ a *= a_step;
+ aa[i] = a;
+ }
+
+ aa[0] *= 5;
+ aa[1] *= 2;
+ aa[2] = 0;
+ aa[4] = 0;
+ aa[5] = 0;
+ aa[7] *= 7;
+ aa[9] = 0;
+ aa[10] = 0;
+ aa[12] = 0;
+ aa[15] *= 7;
+ aa[18] = 0;
+ aa[20] = 0;
+ aa[24] = 0;
+ aa[27] *= 5;
+ aa[29] = 0;
+ aa[30] = 0;
+ aa[33] = 0;
+ aa[36] *= 4;
+ aa[37] = 0;
+ aa[39] = 0;
+ aa[42] = 0;
+ aa[43] = 0;
+ aa[47] = 0;
+ aa[50] *= 4;
+ aa[52] = 0;
+ aa[55] = 0;
+ aa[57] = 0;
+
+
+ aa[10] *= 0.1;
+ aa[11] *= 0.1;
+ aa[12] *= 0.1;
+ aa[13] *= 0.1;
+
+ aa[17] *= 0.1;
+ aa[18] *= 0.1;
+ aa[19] *= 0.1;
+ aa[20] *= 0.1;
+
+ for (int i = 0; i < 60; i++) {
+ double w = start_w + (end_w - start_w) * (i / 40.0);
+ complexGaussianDist(data, base * (i + 1), w, aa[i]);
+ a *= a_step;
+ }
+ SF2Sample sample = newSimpleFFTSample(sf2, "Organ", data, base);
+ SF2Layer layer = newLayer(sf2, "Organ", sample);
+ SF2Region region = layer.getRegions().get(0);
+ region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1);
+ region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -10000);
+ region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, -1000);
+ return layer;
+
+ }
+
+ public static SF2Layer new_flute(SF2Soundbank sf2) {
+ int x = 8;
+ int fftsize = 4096 * x;
+ double[] data = new double[fftsize * 2];
+ double base = x * 15;
+
+ complexGaussianDist(data, base * 1, 0.001, 0.5);
+ complexGaussianDist(data, base * 2, 0.001, 0.5);
+ complexGaussianDist(data, base * 3, 0.001, 0.5);
+ complexGaussianDist(data, base * 4, 0.01, 0.5);
+
+ complexGaussianDist(data, base * 4, 100, 120);
+ complexGaussianDist(data, base * 6, 100, 40);
+ complexGaussianDist(data, base * 8, 100, 80);
+
+ complexGaussianDist(data, base * 5, 0.001, 0.05);
+ complexGaussianDist(data, base * 6, 0.001, 0.06);
+ complexGaussianDist(data, base * 7, 0.001, 0.04);
+ complexGaussianDist(data, base * 8, 0.005, 0.06);
+ complexGaussianDist(data, base * 9, 0.005, 0.06);
+ complexGaussianDist(data, base * 10, 0.01, 0.1);
+ complexGaussianDist(data, base * 11, 0.08, 0.7);
+ complexGaussianDist(data, base * 12, 0.08, 0.6);
+ complexGaussianDist(data, base * 13, 0.08, 0.6);
+ complexGaussianDist(data, base * 14, 0.08, 0.6);
+ complexGaussianDist(data, base * 15, 0.08, 0.5);
+ complexGaussianDist(data, base * 16, 0.08, 0.5);
+ complexGaussianDist(data, base * 17, 0.08, 0.2);
+
+
+ complexGaussianDist(data, base * 1, 10, 8);
+ complexGaussianDist(data, base * 2, 10, 8);
+ complexGaussianDist(data, base * 3, 10, 8);
+ complexGaussianDist(data, base * 4, 10, 8);
+ complexGaussianDist(data, base * 5, 10, 8);
+ complexGaussianDist(data, base * 6, 20, 9);
+ complexGaussianDist(data, base * 7, 20, 9);
+ complexGaussianDist(data, base * 8, 20, 9);
+ complexGaussianDist(data, base * 9, 20, 8);
+ complexGaussianDist(data, base * 10, 30, 8);
+ complexGaussianDist(data, base * 11, 30, 9);
+ complexGaussianDist(data, base * 12, 30, 9);
+ complexGaussianDist(data, base * 13, 30, 8);
+ complexGaussianDist(data, base * 14, 30, 8);
+ complexGaussianDist(data, base * 15, 30, 7);
+ complexGaussianDist(data, base * 16, 30, 7);
+ complexGaussianDist(data, base * 17, 30, 6);
+
+ SF2Sample sample = newSimpleFFTSample(sf2, "Flute", data, base);
+ SF2Layer layer = newLayer(sf2, "Flute", sample);
+ SF2Region region = layer.getRegions().get(0);
+ region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1);
+ region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -6000);
+ region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, -1000);
+ region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 4000);
+ region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, -100);
+ region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 9500);
+ return layer;
+
+ }
+
+ public static SF2Layer new_horn(SF2Soundbank sf2) {
+ int x = 8;
+ int fftsize = 4096 * x;
+ double[] data = new double[fftsize * 2];
+ double base = x * 15;
+
+ double start_a = 0.5;
+ double end_a = 0.00000000001;
+ double a = start_a;
+ double a_step = Math.pow(end_a / start_a, 1.0 / 40.0);
+ for (int i = 0; i < 40; i++) {
+ if (i == 0)
+ complexGaussianDist(data, base * (i + 1), 0.1, a * 0.2);
+ else
+ complexGaussianDist(data, base * (i + 1), 0.1, a);
+ a *= a_step;
+ }
+
+ complexGaussianDist(data, base * 2, 100, 1);
+
+
+ SF2Sample sample = newSimpleFFTSample(sf2, "Horn", data, base);
+ SF2Layer layer = newLayer(sf2, "Horn", sample);
+ SF2Region region = layer.getRegions().get(0);
+ region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1);
+ region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -6000);
+ region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, -1000);
+ region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 4000);
+ region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, -100);
+
+ region.putInteger(SF2Region.GENERATOR_ATTACKMODENV, -500);
+ region.putInteger(SF2Region.GENERATOR_RELEASEMODENV, 12000);
+ region.putInteger(SF2Region.GENERATOR_MODENVTOFILTERFC, 5000);
+ region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 4500);
+ return layer;
+
+ }
+
+ public static SF2Layer new_trumpet(SF2Soundbank sf2) {
+ int x = 8;
+ int fftsize = 4096 * x;
+ double[] data = new double[fftsize * 2];
+ double base = x * 15;
+
+ double start_a = 0.5;
+ double end_a = 0.00001;
+ double a = start_a;
+ double a_step = Math.pow(end_a / start_a, 1.0 / 80.0);
+ double[] aa = new double[80];
+ for (int i = 0; i < 80; i++) {
+ aa[i] = a;
+ a *= a_step;
+ }
+
+ aa[0] *= 0.05;
+ aa[1] *= 0.2;
+ aa[2] *= 0.5;
+ aa[3] *= 0.85;
+
+ for (int i = 0; i < 80; i++) {
+ complexGaussianDist(data, base * (i + 1), 0.1, aa[i]);
+ }
+
+ complexGaussianDist(data, base * 5, 300, 3);
+
+
+ SF2Sample sample = newSimpleFFTSample(sf2, "Trumpet", data, base);
+ SF2Layer layer = newLayer(sf2, "Trumpet", sample);
+ SF2Region region = layer.getRegions().get(0);
+ region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1);
+ region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -10000);
+ region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 0);
+ region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 4000);
+ region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, -100);
+
+ region.putInteger(SF2Region.GENERATOR_ATTACKMODENV, -4000);
+ region.putInteger(SF2Region.GENERATOR_RELEASEMODENV, -2500);
+ region.putInteger(SF2Region.GENERATOR_MODENVTOFILTERFC, 5000);
+ region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 4500);
+ region.putInteger(SF2Region.GENERATOR_INITIALFILTERQ, 10);
+ return layer;
+
+ }
+
+ public static SF2Layer new_brass_section(SF2Soundbank sf2) {
+ int x = 8;
+ int fftsize = 4096 * x;
+ double[] data = new double[fftsize * 2];
+ double base = x * 15;
+
+ double start_a = 0.5;
+ double end_a = 0.005;
+ double a = start_a;
+ double a_step = Math.pow(end_a / start_a, 1.0 / 30.0);
+ double[] aa = new double[30];
+ for (int i = 0; i < 30; i++) {
+ aa[i] = a;
+ a *= a_step;
+ }
+
+ aa[0] *= 0.8;
+ aa[1] *= 0.9;
+
+ double w = 5;
+ for (int i = 0; i < 30; i++) {
+ complexGaussianDist(data, base * (i + 1), 0.1 * w, aa[i] * w);
+ w += 6; //*= w_step;
+ }
+
+ complexGaussianDist(data, base * 6, 300, 2);
+
+
+ SF2Sample sample = newSimpleFFTSample(sf2, "Brass Section", data, base);
+ SF2Layer layer = newLayer(sf2, "Brass Section", sample);
+ SF2Region region = layer.getRegions().get(0);
+ region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1);
+ region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -9200);
+ region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, -1000);
+ region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 4000);
+ region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, -100);
+
+ region.putInteger(SF2Region.GENERATOR_ATTACKMODENV, -3000);
+ region.putInteger(SF2Region.GENERATOR_RELEASEMODENV, 12000);
+ region.putInteger(SF2Region.GENERATOR_MODENVTOFILTERFC, 5000);
+ region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 4500);
+ return layer;
+
+ }
+
+ public static SF2Layer new_trombone(SF2Soundbank sf2) {
+ int x = 8;
+ int fftsize = 4096 * x;
+ double[] data = new double[fftsize * 2];
+ double base = x * 15;
+
+ double start_a = 0.5;
+ double end_a = 0.001;
+ double a = start_a;
+ double a_step = Math.pow(end_a / start_a, 1.0 / 80.0);
+ double[] aa = new double[80];
+ for (int i = 0; i < 80; i++) {
+ aa[i] = a;
+ a *= a_step;
+ }
+
+ aa[0] *= 0.3;
+ aa[1] *= 0.7;
+
+ for (int i = 0; i < 80; i++) {
+ complexGaussianDist(data, base * (i + 1), 0.1, aa[i]);
+ }
+
+ complexGaussianDist(data, base * 6, 300, 2);
+
+
+ SF2Sample sample = newSimpleFFTSample(sf2, "Trombone", data, base);
+ SF2Layer layer = newLayer(sf2, "Trombone", sample);
+ SF2Region region = layer.getRegions().get(0);
+ region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1);
+ region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -8000);
+ region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, -1000);
+ region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 4000);
+ region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, -100);
+
+ region.putInteger(SF2Region.GENERATOR_ATTACKMODENV, -2000);
+ region.putInteger(SF2Region.GENERATOR_RELEASEMODENV, 12000);
+ region.putInteger(SF2Region.GENERATOR_MODENVTOFILTERFC, 5000);
+ region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 4500);
+ region.putInteger(SF2Region.GENERATOR_INITIALFILTERQ, 10);
+ return layer;
+
+ }
+
+ public static SF2Layer new_sax(SF2Soundbank sf2) {
+ int x = 8;
+ int fftsize = 4096 * x;
+ double[] data = new double[fftsize * 2];
+ double base = x * 15;
+
+ double start_a = 0.5;
+ double end_a = 0.01;
+ double a = start_a;
+ double a_step = Math.pow(end_a / start_a, 1.0 / 40.0);
+ for (int i = 0; i < 40; i++) {
+ if (i == 0 || i == 2)
+ complexGaussianDist(data, base * (i + 1), 0.1, a * 4);
+ else
+ complexGaussianDist(data, base * (i + 1), 0.1, a);
+ a *= a_step;
+ }
+
+ complexGaussianDist(data, base * 4, 200, 1);
+
+ SF2Sample sample = newSimpleFFTSample(sf2, "Sax", data, base);
+ SF2Layer layer = newLayer(sf2, "Sax", sample);
+ SF2Region region = layer.getRegions().get(0);
+ region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1);
+ region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -6000);
+ region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, -1000);
+ region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 4000);
+ region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, -100);
+
+ region.putInteger(SF2Region.GENERATOR_ATTACKMODENV, -3000);
+ region.putInteger(SF2Region.GENERATOR_RELEASEMODENV, 12000);
+ region.putInteger(SF2Region.GENERATOR_MODENVTOFILTERFC, 5000);
+ region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 4500);
+ return layer;
+
+ }
+
+ public static SF2Layer new_oboe(SF2Soundbank sf2) {
+ int x = 8;
+ int fftsize = 4096 * x;
+ double[] data = new double[fftsize * 2];
+ double base = x * 15;
+
+ complexGaussianDist(data, base * 5, 100, 80);
+
+
+ complexGaussianDist(data, base * 1, 0.01, 0.53);
+ complexGaussianDist(data, base * 2, 0.01, 0.51);
+ complexGaussianDist(data, base * 3, 0.01, 0.48);
+ complexGaussianDist(data, base * 4, 0.01, 0.49);
+ complexGaussianDist(data, base * 5, 0.01, 5);
+ complexGaussianDist(data, base * 6, 0.01, 0.51);
+ complexGaussianDist(data, base * 7, 0.01, 0.50);
+ complexGaussianDist(data, base * 8, 0.01, 0.59);
+ complexGaussianDist(data, base * 9, 0.01, 0.61);
+ complexGaussianDist(data, base * 10, 0.01, 0.52);
+ complexGaussianDist(data, base * 11, 0.01, 0.49);
+ complexGaussianDist(data, base * 12, 0.01, 0.51);
+ complexGaussianDist(data, base * 13, 0.01, 0.48);
+ complexGaussianDist(data, base * 14, 0.01, 0.51);
+ complexGaussianDist(data, base * 15, 0.01, 0.46);
+ complexGaussianDist(data, base * 16, 0.01, 0.35);
+ complexGaussianDist(data, base * 17, 0.01, 0.20);
+ complexGaussianDist(data, base * 18, 0.01, 0.10);
+ complexGaussianDist(data, base * 19, 0.01, 0.5);
+ complexGaussianDist(data, base * 20, 0.01, 0.1);
+
+
+ SF2Sample sample = newSimpleFFTSample(sf2, "Oboe", data, base);
+ SF2Layer layer = newLayer(sf2, "Oboe", sample);
+ SF2Region region = layer.getRegions().get(0);
+ region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1);
+ region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -6000);
+ region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, -1000);
+ region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 4000);
+ region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, -100);
+ region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 9500);
+ return layer;
+
+ }
+
+ public static SF2Layer new_bassoon(SF2Soundbank sf2) {
+ int x = 8;
+ int fftsize = 4096 * x;
+ double[] data = new double[fftsize * 2];
+ double base = x * 15;
+
+ complexGaussianDist(data, base * 2, 100, 40);
+ complexGaussianDist(data, base * 4, 100, 20);
+
+ complexGaussianDist(data, base * 1, 0.01, 0.53);
+ complexGaussianDist(data, base * 2, 0.01, 5);
+ complexGaussianDist(data, base * 3, 0.01, 0.51);
+ complexGaussianDist(data, base * 4, 0.01, 0.48);
+ complexGaussianDist(data, base * 5, 0.01, 1.49);
+ complexGaussianDist(data, base * 6, 0.01, 0.51);
+ complexGaussianDist(data, base * 7, 0.01, 0.50);
+ complexGaussianDist(data, base * 8, 0.01, 0.59);
+ complexGaussianDist(data, base * 9, 0.01, 0.61);
+ complexGaussianDist(data, base * 10, 0.01, 0.52);
+ complexGaussianDist(data, base * 11, 0.01, 0.49);
+ complexGaussianDist(data, base * 12, 0.01, 0.51);
+ complexGaussianDist(data, base * 13, 0.01, 0.48);
+ complexGaussianDist(data, base * 14, 0.01, 0.51);
+ complexGaussianDist(data, base * 15, 0.01, 0.46);
+ complexGaussianDist(data, base * 16, 0.01, 0.35);
+ complexGaussianDist(data, base * 17, 0.01, 0.20);
+ complexGaussianDist(data, base * 18, 0.01, 0.10);
+ complexGaussianDist(data, base * 19, 0.01, 0.5);
+ complexGaussianDist(data, base * 20, 0.01, 0.1);
+
+
+ SF2Sample sample = newSimpleFFTSample(sf2, "Flute", data, base);
+ SF2Layer layer = newLayer(sf2, "Flute", sample);
+ SF2Region region = layer.getRegions().get(0);
+ region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1);
+ region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -6000);
+ region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, -1000);
+ region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 4000);
+ region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, -100);
+ region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 9500);
+ return layer;
+
+ }
+
+ public static SF2Layer new_clarinet(SF2Soundbank sf2) {
+ int x = 8;
+ int fftsize = 4096 * x;
+ double[] data = new double[fftsize * 2];
+ double base = x * 15;
+
+ complexGaussianDist(data, base * 1, 0.001, 0.5);
+ complexGaussianDist(data, base * 2, 0.001, 0.02);
+ complexGaussianDist(data, base * 3, 0.001, 0.2);
+ complexGaussianDist(data, base * 4, 0.01, 0.1);
+
+ complexGaussianDist(data, base * 4, 100, 60);
+ complexGaussianDist(data, base * 6, 100, 20);
+ complexGaussianDist(data, base * 8, 100, 20);
+
+ complexGaussianDist(data, base * 5, 0.001, 0.1);
+ complexGaussianDist(data, base * 6, 0.001, 0.09);
+ complexGaussianDist(data, base * 7, 0.001, 0.02);
+ complexGaussianDist(data, base * 8, 0.005, 0.16);
+ complexGaussianDist(data, base * 9, 0.005, 0.96);
+ complexGaussianDist(data, base * 10, 0.01, 0.9);
+ complexGaussianDist(data, base * 11, 0.08, 1.2);
+ complexGaussianDist(data, base * 12, 0.08, 1.8);
+ complexGaussianDist(data, base * 13, 0.08, 1.6);
+ complexGaussianDist(data, base * 14, 0.08, 1.2);
+ complexGaussianDist(data, base * 15, 0.08, 0.9);
+ complexGaussianDist(data, base * 16, 0.08, 0.5);
+ complexGaussianDist(data, base * 17, 0.08, 0.2);
+
+
+ complexGaussianDist(data, base * 1, 10, 8);
+ complexGaussianDist(data, base * 2, 10, 8);
+ complexGaussianDist(data, base * 3, 10, 8);
+ complexGaussianDist(data, base * 4, 10, 8);
+ complexGaussianDist(data, base * 5, 10, 8);
+ complexGaussianDist(data, base * 6, 20, 9);
+ complexGaussianDist(data, base * 7, 20, 9);
+ complexGaussianDist(data, base * 8, 20, 9);
+ complexGaussianDist(data, base * 9, 20, 8);
+ complexGaussianDist(data, base * 10, 30, 8);
+ complexGaussianDist(data, base * 11, 30, 9);
+ complexGaussianDist(data, base * 12, 30, 9);
+ complexGaussianDist(data, base * 13, 30, 8);
+ complexGaussianDist(data, base * 14, 30, 8);
+ complexGaussianDist(data, base * 15, 30, 7);
+ complexGaussianDist(data, base * 16, 30, 7);
+ complexGaussianDist(data, base * 17, 30, 6);
+
+ SF2Sample sample = newSimpleFFTSample(sf2, "Clarinet", data, base);
+ SF2Layer layer = newLayer(sf2, "Clarinet", sample);
+ SF2Region region = layer.getRegions().get(0);
+ region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1);
+ region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -6000);
+ region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, -1000);
+ region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 4000);
+ region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, -100);
+ region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 9500);
+ return layer;
+
+ }
+
+ public static SF2Layer new_timpani(SF2Soundbank sf2) {
+
+ double datab[];
+ double datah[];
+
+ // Make Bass Part
+ {
+ int fftlen = 4096 * 8;
+ double[] data = new double[2 * fftlen];
+ double base = 48;
+ complexGaussianDist(data, base * 2, 0.2, 1);
+ complexGaussianDist(data, base * 3, 0.2, 0.7);
+ complexGaussianDist(data, base * 5, 10, 1);
+ complexGaussianDist(data, base * 6, 9, 1);
+ complexGaussianDist(data, base * 8, 15, 1);
+ complexGaussianDist(data, base * 9, 18, 0.8);
+ complexGaussianDist(data, base * 11, 21, 0.5);
+ complexGaussianDist(data, base * 13, 28, 0.3);
+ complexGaussianDist(data, base * 14, 22, 0.1);
+ randomPhase(data, new Random(3049912));
+ ifft(data);
+ normalize(data, 0.5);
+ data = realPart(data);
+
+ double d_len = data.length;
+ for (int i = 0; i < data.length; i++) {
+ double g = (1.0 - (i / d_len));
+ data[i] *= g * g;
+ }
+ fadeUp(data, 40);
+ datab = data;
+ }
+
+ // Make treble part
+ {
+ int fftlen = 4096 * 4;
+ double[] data = new double[2 * fftlen];
+ Random random = new Random(3049912);
+ for (int i = 0; i < data.length; i += 2) {
+ data[i] = (2.0 * (random.nextDouble() - 0.5)) * 0.1;
+ }
+ fft(data);
+ // Remove all negative frequency
+ for (int i = fftlen / 2; i < data.length; i++)
+ data[i] = 0;
+ for (int i = 1024 * 4; i < 2048 * 4; i++)
+ data[i] = 1.0 - (i - 4096) / 4096.0;
+ for (int i = 0; i < 300; i++) {
+ double g = (1.0 - (i / 300.0));
+ data[i] *= 1.0 + 20 * g * g;
+ }
+ for (int i = 0; i < 24; i++)
+ data[i] = 0;
+ randomPhase(data, new Random(3049912));
+ ifft(data);
+ normalize(data, 0.9);
+ data = realPart(data);
+ double gain = 1.0;
+ for (int i = 0; i < data.length; i++) {
+ data[i] *= gain;
+ gain *= 0.9998;
+ }
+ datah = data;
+ }
+
+ for (int i = 0; i < datah.length; i++)
+ datab[i] += datah[i] * 0.02;
+
+ normalize(datab, 0.9);
+
+ SF2Sample sample = newSimpleDrumSample(sf2, "Timpani", datab);
+
+ SF2Layer layer = new SF2Layer(sf2);
+ layer.setName("Timpani");
+
+ SF2GlobalRegion global = new SF2GlobalRegion();
+ layer.setGlobalZone(global);
+ sf2.addResource(layer);
+
+ SF2LayerRegion region = new SF2LayerRegion();
+ region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 12000);
+ region.putInteger(SF2Region.GENERATOR_INITIALATTENUATION, -100);
+ region.setSample(sample);
+ layer.getRegions().add(region);
+
+ return layer;
+ }
+
+ public static SF2Layer new_melodic_toms(SF2Soundbank sf2) {
+
+ double datab[];
+ double datah[];
+
+ // Make Bass Part
+ {
+ int fftlen = 4096 * 4;
+ double[] data = new double[2 * fftlen];
+ complexGaussianDist(data, 30, 0.5, 1);
+ randomPhase(data, new Random(3049912));
+ ifft(data);
+ normalize(data, 0.8);
+ data = realPart(data);
+
+ double d_len = data.length;
+ for (int i = 0; i < data.length; i++)
+ data[i] *= (1.0 - (i / d_len));
+ datab = data;
+ }
+
+ // Make treble part
+ {
+ int fftlen = 4096 * 4;
+ double[] data = new double[2 * fftlen];
+ Random random = new Random(3049912);
+ for (int i = 0; i < data.length; i += 2)
+ data[i] = (2.0 * (random.nextDouble() - 0.5)) * 0.1;
+ fft(data);
+ // Remove all negative frequency
+ for (int i = fftlen / 2; i < data.length; i++)
+ data[i] = 0;
+ for (int i = 1024 * 4; i < 2048 * 4; i++)
+ data[i] = 1.0 - (i - 4096) / 4096.0;
+ for (int i = 0; i < 200; i++) {
+ double g = (1.0 - (i / 200.0));
+ data[i] *= 1.0 + 20 * g * g;
+ }
+ for (int i = 0; i < 30; i++)
+ data[i] = 0;
+ randomPhase(data, new Random(3049912));
+ ifft(data);
+ normalize(data, 0.9);
+ data = realPart(data);
+ double gain = 1.0;
+ for (int i = 0; i < data.length; i++) {
+ data[i] *= gain;
+ gain *= 0.9996;
+ }
+ datah = data;
+ }
+
+ for (int i = 0; i < datah.length; i++)
+ datab[i] += datah[i] * 0.5;
+ for (int i = 0; i < 5; i++)
+ datab[i] *= i / 5.0;
+
+ normalize(datab, 0.99);
+
+ SF2Sample sample = newSimpleDrumSample(sf2, "Melodic Toms", datab);
+ sample.setOriginalPitch(63);
+
+ SF2Layer layer = new SF2Layer(sf2);
+ layer.setName("Melodic Toms");
+
+ SF2GlobalRegion global = new SF2GlobalRegion();
+ layer.setGlobalZone(global);
+ sf2.addResource(layer);
+
+ SF2LayerRegion region = new SF2LayerRegion();
+ region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 12000);
+ //region.putInteger(SF2Region.GENERATOR_SCALETUNING, 0);
+ region.putInteger(SF2Region.GENERATOR_INITIALATTENUATION, -100);
+ region.setSample(sample);
+ layer.getRegions().add(region);
+
+ return layer;
+ }
+
+ public static SF2Layer new_reverse_cymbal(SF2Soundbank sf2) {
+ double datah[];
+ {
+ int fftlen = 4096 * 4;
+ double[] data = new double[2 * fftlen];
+ Random random = new Random(3049912);
+ for (int i = 0; i < data.length; i += 2)
+ data[i] = (2.0 * (random.nextDouble() - 0.5));
+ for (int i = fftlen / 2; i < data.length; i++)
+ data[i] = 0;
+ for (int i = 0; i < 100; i++)
+ data[i] = 0;
+
+ for (int i = 0; i < 512 * 2; i++) {
+ double gain = (i / (512.0 * 2.0));
+ data[i] = 1 - gain;
+ }
+ datah = data;
+ }
+
+ SF2Sample sample = newSimpleFFTSample(sf2, "Reverse Cymbal",
+ datah, 100, 20);
+
+ SF2Layer layer = new SF2Layer(sf2);
+ layer.setName("Reverse Cymbal");
+
+ SF2GlobalRegion global = new SF2GlobalRegion();
+ layer.setGlobalZone(global);
+ sf2.addResource(layer);
+
+ SF2LayerRegion region = new SF2LayerRegion();
+ region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -200);
+ region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, -12000);
+ region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1);
+ region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, -1000);
+ region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, 1000);
+ region.setSample(sample);
+ layer.getRegions().add(region);
+
+ return layer;
+ }
+
+ public static SF2Layer new_snare_drum(SF2Soundbank sf2) {
+
+ double datab[];
+ double datah[];
+
+ // Make Bass Part
+ {
+ int fftlen = 4096 * 4;
+ double[] data = new double[2 * fftlen];
+ complexGaussianDist(data, 24, 0.5, 1);
+ randomPhase(data, new Random(3049912));
+ ifft(data);
+ normalize(data, 0.5);
+ data = realPart(data);
+
+ double d_len = data.length;
+ for (int i = 0; i < data.length; i++)
+ data[i] *= (1.0 - (i / d_len));
+ datab = data;
+ }
+
+ // Make treble part
+ {
+ int fftlen = 4096 * 4;
+ double[] data = new double[2 * fftlen];
+ Random random = new Random(3049912);
+ for (int i = 0; i < data.length; i += 2)
+ data[i] = (2.0 * (random.nextDouble() - 0.5)) * 0.1;
+ fft(data);
+ // Remove all negative frequency
+ for (int i = fftlen / 2; i < data.length; i++)
+ data[i] = 0;
+ for (int i = 1024 * 4; i < 2048 * 4; i++)
+ data[i] = 1.0 - (i - 4096) / 4096.0;
+ for (int i = 0; i < 300; i++) {
+ double g = (1.0 - (i / 300.0));
+ data[i] *= 1.0 + 20 * g * g;
+ }
+ for (int i = 0; i < 24; i++)
+ data[i] = 0;
+ randomPhase(data, new Random(3049912));
+ ifft(data);
+ normalize(data, 0.9);
+ data = realPart(data);
+ double gain = 1.0;
+ for (int i = 0; i < data.length; i++) {
+ data[i] *= gain;
+ gain *= 0.9998;
+ }
+ datah = data;
+ }
+
+ for (int i = 0; i < datah.length; i++)
+ datab[i] += datah[i];
+ for (int i = 0; i < 5; i++)
+ datab[i] *= i / 5.0;
+
+ SF2Sample sample = newSimpleDrumSample(sf2, "Snare Drum", datab);
+
+ SF2Layer layer = new SF2Layer(sf2);
+ layer.setName("Snare Drum");
+
+ SF2GlobalRegion global = new SF2GlobalRegion();
+ layer.setGlobalZone(global);
+ sf2.addResource(layer);
+
+ SF2LayerRegion region = new SF2LayerRegion();
+ region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 12000);
+ region.putInteger(SF2Region.GENERATOR_SCALETUNING, 0);
+ region.putInteger(SF2Region.GENERATOR_INITIALATTENUATION, -100);
+ region.setSample(sample);
+ layer.getRegions().add(region);
+
+ return layer;
+ }
+
+ public static SF2Layer new_bass_drum(SF2Soundbank sf2) {
+
+ double datab[];
+ double datah[];
+
+ // Make Bass Part
+ {
+ int fftlen = 4096 * 4;
+ double[] data = new double[2 * fftlen];
+ complexGaussianDist(data, 1.8 * 5 + 1, 2, 1);
+ complexGaussianDist(data, 1.8 * 9 + 1, 2, 1);
+ randomPhase(data, new Random(3049912));
+ ifft(data);
+ normalize(data, 0.9);
+ data = realPart(data);
+ double d_len = data.length;
+ for (int i = 0; i < data.length; i++)
+ data[i] *= (1.0 - (i / d_len));
+ datab = data;
+ }
+
+ // Make treble part
+ {
+ int fftlen = 4096;
+ double[] data = new double[2 * fftlen];
+ Random random = new Random(3049912);
+ for (int i = 0; i < data.length; i += 2)
+ data[i] = (2.0 * (random.nextDouble() - 0.5)) * 0.1;
+ fft(data);
+ // Remove all negative frequency
+ for (int i = fftlen / 2; i < data.length; i++)
+ data[i] = 0;
+ for (int i = 1024; i < 2048; i++)
+ data[i] = 1.0 - (i - 1024) / 1024.0;
+ for (int i = 0; i < 512; i++)
+ data[i] = 10 * i / 512.0;
+ for (int i = 0; i < 10; i++)
+ data[i] = 0;
+ randomPhase(data, new Random(3049912));
+ ifft(data);
+ normalize(data, 0.9);
+ data = realPart(data);
+ double gain = 1.0;
+ for (int i = 0; i < data.length; i++) {
+ data[i] *= gain;
+ gain *= 0.999;
+ }
+ datah = data;
+ }
+
+ for (int i = 0; i < datah.length; i++)
+ datab[i] += datah[i] * 0.5;
+ for (int i = 0; i < 5; i++)
+ datab[i] *= i / 5.0;
+
+ SF2Sample sample = newSimpleDrumSample(sf2, "Bass Drum", datab);
+
+ SF2Layer layer = new SF2Layer(sf2);
+ layer.setName("Bass Drum");
+
+ SF2GlobalRegion global = new SF2GlobalRegion();
+ layer.setGlobalZone(global);
+ sf2.addResource(layer);
+
+ SF2LayerRegion region = new SF2LayerRegion();
+ region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 12000);
+ region.putInteger(SF2Region.GENERATOR_SCALETUNING, 0);
+ region.putInteger(SF2Region.GENERATOR_INITIALATTENUATION, -100);
+ region.setSample(sample);
+ layer.getRegions().add(region);
+
+ return layer;
+ }
+
+ public static SF2Layer new_tom(SF2Soundbank sf2) {
+
+ double datab[];
+ double datah[];
+
+ // Make Bass Part
+ {
+ int fftlen = 4096 * 4;
+ double[] data = new double[2 * fftlen];
+ complexGaussianDist(data, 30, 0.5, 1);
+ randomPhase(data, new Random(3049912));
+ ifft(data);
+ normalize(data, 0.8);
+ data = realPart(data);
+
+ double d_len = data.length;
+ for (int i = 0; i < data.length; i++)
+ data[i] *= (1.0 - (i / d_len));
+ datab = data;
+ }
+
+ // Make treble part
+ {
+ int fftlen = 4096 * 4;
+ double[] data = new double[2 * fftlen];
+ Random random = new Random(3049912);
+ for (int i = 0; i < data.length; i += 2)
+ data[i] = (2.0 * (random.nextDouble() - 0.5)) * 0.1;
+ fft(data);
+ // Remove all negative frequency
+ for (int i = fftlen / 2; i < data.length; i++)
+ data[i] = 0;
+ for (int i = 1024 * 4; i < 2048 * 4; i++)
+ data[i] = 1.0 - (i - 4096) / 4096.0;
+ for (int i = 0; i < 200; i++) {
+ double g = (1.0 - (i / 200.0));
+ data[i] *= 1.0 + 20 * g * g;
+ }
+ for (int i = 0; i < 30; i++)
+ data[i] = 0;
+ randomPhase(data, new Random(3049912));
+ ifft(data);
+ normalize(data, 0.9);
+ data = realPart(data);
+ double gain = 1.0;
+ for (int i = 0; i < data.length; i++) {
+ data[i] *= gain;
+ gain *= 0.9996;
+ }
+ datah = data;
+ }
+
+ for (int i = 0; i < datah.length; i++)
+ datab[i] += datah[i] * 0.5;
+ for (int i = 0; i < 5; i++)
+ datab[i] *= i / 5.0;
+
+ normalize(datab, 0.99);
+
+ SF2Sample sample = newSimpleDrumSample(sf2, "Tom", datab);
+ sample.setOriginalPitch(50);
+
+ SF2Layer layer = new SF2Layer(sf2);
+ layer.setName("Tom");
+
+ SF2GlobalRegion global = new SF2GlobalRegion();
+ layer.setGlobalZone(global);
+ sf2.addResource(layer);
+
+ SF2LayerRegion region = new SF2LayerRegion();
+ region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 12000);
+ //region.putInteger(SF2Region.GENERATOR_SCALETUNING, 0);
+ region.putInteger(SF2Region.GENERATOR_INITIALATTENUATION, -100);
+ region.setSample(sample);
+ layer.getRegions().add(region);
+
+ return layer;
+ }
+
+ public static SF2Layer new_closed_hihat(SF2Soundbank sf2) {
+ double datah[];
+
+ // Make treble part
+ {
+ int fftlen = 4096 * 4;
+ double[] data = new double[2 * fftlen];
+ Random random = new Random(3049912);
+ for (int i = 0; i < data.length; i += 2)
+ data[i] = (2.0 * (random.nextDouble() - 0.5)) * 0.1;
+ fft(data);
+ // Remove all negative frequency
+ for (int i = fftlen / 2; i < data.length; i++)
+ data[i] = 0;
+ for (int i = 1024 * 4; i < 2048 * 4; i++)
+ data[i] = 1.0 - (i - 4096) / 4096.0;
+ for (int i = 0; i < 2048; i++)
+ data[i] = 0.2 + 0.8 * (i / 2048.0);
+ randomPhase(data, new Random(3049912));
+ ifft(data);
+ normalize(data, 0.9);
+ data = realPart(data);
+ double gain = 1.0;
+ for (int i = 0; i < data.length; i++) {
+ data[i] *= gain;
+ gain *= 0.9996;
+ }
+ datah = data;
+ }
+
+ for (int i = 0; i < 5; i++)
+ datah[i] *= i / 5.0;
+ SF2Sample sample = newSimpleDrumSample(sf2, "Closed Hi-Hat", datah);
+
+ SF2Layer layer = new SF2Layer(sf2);
+ layer.setName("Closed Hi-Hat");
+
+ SF2GlobalRegion global = new SF2GlobalRegion();
+ layer.setGlobalZone(global);
+ sf2.addResource(layer);
+
+ SF2LayerRegion region = new SF2LayerRegion();
+ region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 12000);
+ region.putInteger(SF2Region.GENERATOR_SCALETUNING, 0);
+ region.putInteger(SF2Region.GENERATOR_EXCLUSIVECLASS, 1);
+ region.setSample(sample);
+ layer.getRegions().add(region);
+
+ return layer;
+ }
+
+ public static SF2Layer new_open_hihat(SF2Soundbank sf2) {
+ double datah[];
+ {
+ int fftlen = 4096 * 4;
+ double[] data = new double[2 * fftlen];
+ Random random = new Random(3049912);
+ for (int i = 0; i < data.length; i += 2)
+ data[i] = (2.0 * (random.nextDouble() - 0.5));
+ for (int i = fftlen / 2; i < data.length; i++)
+ data[i] = 0;
+ for (int i = 0; i < 200; i++)
+ data[i] = 0;
+ for (int i = 0; i < 2048 * 4; i++) {
+ double gain = (i / (2048.0 * 4.0));
+ data[i] = gain;
+ }
+ datah = data;
+ }
+
+ SF2Sample sample = newSimpleFFTSample(sf2, "Open Hi-Hat", datah, 1000, 5);
+
+ SF2Layer layer = new SF2Layer(sf2);
+ layer.setName("Open Hi-Hat");
+
+ SF2GlobalRegion global = new SF2GlobalRegion();
+ layer.setGlobalZone(global);
+ sf2.addResource(layer);
+
+ SF2LayerRegion region = new SF2LayerRegion();
+ region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 1500);
+ region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1);
+ region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 1500);
+ region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, 1000);
+ region.putInteger(SF2Region.GENERATOR_SCALETUNING, 0);
+ region.putInteger(SF2Region.GENERATOR_EXCLUSIVECLASS, 1);
+ region.setSample(sample);
+ layer.getRegions().add(region);
+
+ return layer;
+ }
+
+ public static SF2Layer new_crash_cymbal(SF2Soundbank sf2) {
+ double datah[];
+ {
+ int fftlen = 4096 * 4;
+ double[] data = new double[2 * fftlen];
+ Random random = new Random(3049912);
+ for (int i = 0; i < data.length; i += 2)
+ data[i] = (2.0 * (random.nextDouble() - 0.5));
+ for (int i = fftlen / 2; i < data.length; i++)
+ data[i] = 0;
+ for (int i = 0; i < 100; i++)
+ data[i] = 0;
+ for (int i = 0; i < 512 * 2; i++) {
+ double gain = (i / (512.0 * 2.0));
+ data[i] = gain;
+ }
+ datah = data;
+ }
+
+ SF2Sample sample = newSimpleFFTSample(sf2, "Crash Cymbal", datah, 1000, 5);
+
+ SF2Layer layer = new SF2Layer(sf2);
+ layer.setName("Crash Cymbal");
+
+ SF2GlobalRegion global = new SF2GlobalRegion();
+ layer.setGlobalZone(global);
+ sf2.addResource(layer);
+
+ SF2LayerRegion region = new SF2LayerRegion();
+ region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 1800);
+ region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1);
+ region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 1800);
+ region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, 1000);
+ region.putInteger(SF2Region.GENERATOR_SCALETUNING, 0);
+ region.setSample(sample);
+ layer.getRegions().add(region);
+
+ return layer;
+ }
+
+ public static SF2Layer new_side_stick(SF2Soundbank sf2) {
+ double datab[];
+
+ // Make treble part
+ {
+ int fftlen = 4096 * 4;
+ double[] data = new double[2 * fftlen];
+ Random random = new Random(3049912);
+ for (int i = 0; i < data.length; i += 2)
+ data[i] = (2.0 * (random.nextDouble() - 0.5)) * 0.1;
+ fft(data);
+ // Remove all negative frequency
+ for (int i = fftlen / 2; i < data.length; i++)
+ data[i] = 0;
+ for (int i = 1024 * 4; i < 2048 * 4; i++)
+ data[i] = 1.0 - (i - 4096) / 4096.0;
+ for (int i = 0; i < 200; i++) {
+ double g = (1.0 - (i / 200.0));
+ data[i] *= 1.0 + 20 * g * g;
+ }
+ for (int i = 0; i < 30; i++)
+ data[i] = 0;
+ randomPhase(data, new Random(3049912));
+ ifft(data);
+ normalize(data, 0.9);
+ data = realPart(data);
+ double gain = 1.0;
+ for (int i = 0; i < data.length; i++) {
+ data[i] *= gain;
+ gain *= 0.9996;
+ }
+ datab = data;
+ }
+
+ for (int i = 0; i < 10; i++)
+ datab[i] *= i / 10.0;
+
+ SF2Sample sample = newSimpleDrumSample(sf2, "Side Stick", datab);
+
+ SF2Layer layer = new SF2Layer(sf2);
+ layer.setName("Side Stick");
+
+ SF2GlobalRegion global = new SF2GlobalRegion();
+ layer.setGlobalZone(global);
+ sf2.addResource(layer);
+
+ SF2LayerRegion region = new SF2LayerRegion();
+ region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 12000);
+ region.putInteger(SF2Region.GENERATOR_SCALETUNING, 0);
+ region.putInteger(SF2Region.GENERATOR_INITIALATTENUATION, -50);
+ region.setSample(sample);
+ layer.getRegions().add(region);
+
+ return layer;
+
+ }
+
+ public static SF2Sample newSimpleFFTSample(SF2Soundbank sf2, String name,
+ double[] data, double base) {
+ return newSimpleFFTSample(sf2, name, data, base, 10);
+ }
+
+ public static SF2Sample newSimpleFFTSample(SF2Soundbank sf2, String name,
+ double[] data, double base, int fadeuptime) {
+
+ int fftsize = data.length / 2;
+ AudioFormat format = new AudioFormat(44100, 16, 1, true, false);
+ double basefreq = (base / fftsize) * format.getSampleRate() * 0.5;
+
+ randomPhase(data);
+ ifft(data);
+ data = realPart(data);
+ normalize(data, 0.9);
+ float[] fdata = toFloat(data);
+ fdata = loopExtend(fdata, fdata.length + 512);
+ fadeUp(fdata, fadeuptime);
+ byte[] bdata = toBytes(fdata, format);
+
+ /*
+ * Create SoundFont2 sample.
+ */
+ SF2Sample sample = new SF2Sample(sf2);
+ sample.setName(name);
+ sample.setData(bdata);
+ sample.setStartLoop(256);
+ sample.setEndLoop(fftsize + 256);
+ sample.setSampleRate((long) format.getSampleRate());
+ double orgnote = (69 + 12)
+ + (12 * Math.log(basefreq / 440.0) / Math.log(2));
+ sample.setOriginalPitch((int) orgnote);
+ sample.setPitchCorrection((byte) (-(orgnote - (int) orgnote) * 100.0));
+ sf2.addResource(sample);
+
+ return sample;
+ }
+
+ public static SF2Sample newSimpleFFTSample_dist(SF2Soundbank sf2,
+ String name, double[] data, double base, double preamp) {
+
+ int fftsize = data.length / 2;
+ AudioFormat format = new AudioFormat(44100, 16, 1, true, false);
+ double basefreq = (base / fftsize) * format.getSampleRate() * 0.5;
+
+ randomPhase(data);
+ ifft(data);
+ data = realPart(data);
+
+ for (int i = 0; i < data.length; i++) {
+ data[i] = (1 - Math.exp(-Math.abs(data[i] * preamp)))
+ * Math.signum(data[i]);
+ }
+
+ normalize(data, 0.9);
+ float[] fdata = toFloat(data);
+ fdata = loopExtend(fdata, fdata.length + 512);
+ fadeUp(fdata, 80);
+ byte[] bdata = toBytes(fdata, format);
+
+ /*
+ * Create SoundFont2 sample.
+ */
+ SF2Sample sample = new SF2Sample(sf2);
+ sample.setName(name);
+ sample.setData(bdata);
+ sample.setStartLoop(256);
+ sample.setEndLoop(fftsize + 256);
+ sample.setSampleRate((long) format.getSampleRate());
+ double orgnote = (69 + 12)
+ + (12 * Math.log(basefreq / 440.0) / Math.log(2));
+ sample.setOriginalPitch((int) orgnote);
+ sample.setPitchCorrection((byte) (-(orgnote - (int) orgnote) * 100.0));
+ sf2.addResource(sample);
+
+ return sample;
+ }
+
+ public static SF2Sample newSimpleDrumSample(SF2Soundbank sf2, String name,
+ double[] data) {
+
+ int fftsize = data.length;
+ AudioFormat format = new AudioFormat(44100, 16, 1, true, false);
+
+ byte[] bdata = toBytes(toFloat(realPart(data)), format);
+
+ /*
+ * Create SoundFont2 sample.
+ */
+ SF2Sample sample = new SF2Sample(sf2);
+ sample.setName(name);
+ sample.setData(bdata);
+ sample.setStartLoop(256);
+ sample.setEndLoop(fftsize + 256);
+ sample.setSampleRate((long) format.getSampleRate());
+ sample.setOriginalPitch(60);
+ sf2.addResource(sample);
+
+ return sample;
+ }
+
+ public static SF2Layer newLayer(SF2Soundbank sf2, String name, SF2Sample sample) {
+ SF2LayerRegion region = new SF2LayerRegion();
+ region.setSample(sample);
+
+ SF2Layer layer = new SF2Layer(sf2);
+ layer.setName(name);
+ layer.getRegions().add(region);
+ sf2.addResource(layer);
+
+ return layer;
+ }
+
+ public static SF2Instrument newInstrument(SF2Soundbank sf2, String name,
+ Patch patch, SF2Layer... layers) {
+
+ /*
+ * Create SoundFont2 instrument.
+ */
+ SF2Instrument ins = new SF2Instrument(sf2);
+ ins.setPatch(patch);
+ ins.setName(name);
+ sf2.addInstrument(ins);
+
+ /*
+ * Create region for instrument.
+ */
+ for (int i = 0; i < layers.length; i++) {
+ SF2InstrumentRegion insregion = new SF2InstrumentRegion();
+ insregion.setLayer(layers[i]);
+ ins.getRegions().add(insregion);
+ }
+
+ return ins;
+ }
+
+ static public void ifft(double[] data) {
+ new FFT(data.length / 2, 1).transform(data);
+ }
+
+ static public void fft(double[] data) {
+ new FFT(data.length / 2, -1).transform(data);
+ }
+
+ public static void complexGaussianDist(double[] cdata, double m,
+ double s, double v) {
+ for (int x = 0; x < cdata.length / 4; x++) {
+ cdata[x * 2] += v * (1.0 / (s * Math.sqrt(2 * Math.PI))
+ * Math.exp((-1.0 / 2.0) * Math.pow((x - m) / s, 2.0)));
+ }
+ }
+
+ static public void randomPhase(double[] data) {
+ for (int i = 0; i < data.length; i += 2) {
+ double phase = Math.random() * 2 * Math.PI;
+ double d = data[i];
+ data[i] = Math.sin(phase) * d;
+ data[i + 1] = Math.cos(phase) * d;
+ }
+ }
+
+ static public void randomPhase(double[] data, Random random) {
+ for (int i = 0; i < data.length; i += 2) {
+ double phase = random.nextDouble() * 2 * Math.PI;
+ double d = data[i];
+ data[i] = Math.sin(phase) * d;
+ data[i + 1] = Math.cos(phase) * d;
+ }
+ }
+
+ static public void normalize(double[] data, double target) {
+ double maxvalue = 0;
+ for (int i = 0; i < data.length; i++) {
+ if (data[i] > maxvalue)
+ maxvalue = data[i];
+ if (-data[i] > maxvalue)
+ maxvalue = -data[i];
+ }
+ if (maxvalue == 0)
+ return;
+ double gain = target / maxvalue;
+ for (int i = 0; i < data.length; i++)
+ data[i] *= gain;
+ }
+
+ static public void normalize(float[] data, double target) {
+ double maxvalue = 0.5;
+ for (int i = 0; i < data.length; i++) {
+ if (data[i * 2] > maxvalue)
+ maxvalue = data[i * 2];
+ if (-data[i * 2] > maxvalue)
+ maxvalue = -data[i * 2];
+ }
+ double gain = target / maxvalue;
+ for (int i = 0; i < data.length; i++)
+ data[i * 2] *= gain;
+ }
+
+ static public double[] realPart(double[] in) {
+ double[] out = new double[in.length / 2];
+ for (int i = 0; i < out.length; i++) {
+ out[i] = in[i * 2];
+ }
+ return out;
+ }
+
+ static public double[] imgPart(double[] in) {
+ double[] out = new double[in.length / 2];
+ for (int i = 0; i < out.length; i++) {
+ out[i] = in[i * 2];
+ }
+ return out;
+ }
+
+ static public float[] toFloat(double[] in) {
+ float[] out = new float[in.length];
+ for (int i = 0; i < out.length; i++) {
+ out[i] = (float) in[i];
+ }
+ return out;
+ }
+
+ static public byte[] toBytes(float[] in, AudioFormat format) {
+ byte[] out = new byte[in.length * format.getFrameSize()];
+ return AudioFloatConverter.getConverter(format).toByteArray(in, out);
+ }
+
+ static public void fadeUp(double[] data, int samples) {
+ double dsamples = samples;
+ for (int i = 0; i < samples; i++)
+ data[i] *= i / dsamples;
+ }
+
+ static public void fadeUp(float[] data, int samples) {
+ double dsamples = samples;
+ for (int i = 0; i < samples; i++)
+ data[i] *= i / dsamples;
+ }
+
+ static public double[] loopExtend(double[] data, int newsize) {
+ double[] outdata = new double[newsize];
+ int p_len = data.length;
+ int p_ps = 0;
+ for (int i = 0; i < outdata.length; i++) {
+ outdata[i] = data[p_ps];
+ p_ps++;
+ if (p_ps == p_len)
+ p_ps = 0;
+ }
+ return outdata;
+ }
+
+ static public float[] loopExtend(float[] data, int newsize) {
+ float[] outdata = new float[newsize];
+ int p_len = data.length;
+ int p_ps = 0;
+ for (int i = 0; i < outdata.length; i++) {
+ outdata[i] = data[p_ps];
+ p_ps++;
+ if (p_ps == p_len)
+ p_ps = 0;
+ }
+ return outdata;
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/FFT.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/FFT.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,748 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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 double[] w;
+ private int fftFrameSize;
+ private int sign;
+ private int[] bitm_array;
+ private 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;
+ }
+
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/InvalidDataException.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/InvalidDataException.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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);
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/InvalidFormatException.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/InvalidFormatException.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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);
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/JARSoundbankReader.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/JARSoundbankReader.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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.util.ArrayList;
+import javax.sound.midi.InvalidMidiDataException;
+import javax.sound.midi.Soundbank;
+import javax.sound.midi.spi.SoundbankReader;
+
+/**
+ * JarSoundbankReader is used to read sounbank object from jar files.
+ *
+ * @author Karl Helgason
+ */
+public class JARSoundbankReader extends SoundbankReader {
+
+ public 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 {
+ if (!isZIP(url))
+ return null;
+ ArrayList soundbanks = new ArrayList();
+ 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(), true, ucl);
+ Object o = c.newInstance();
+ if (o instanceof Soundbank) {
+ soundbanks.add((Soundbank) o);
+ }
+ } catch (ClassNotFoundException e) {
+ } catch (InstantiationException e) {
+ } catch (IllegalAccessException e) {
+ }
+ }
+ 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 {
+ return getSoundbank(file.toURI().toURL());
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/ModelAbstractChannelMixer.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/ModelAbstractChannelMixer.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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) {
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/ModelAbstractOscillator.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/ModelAbstractOscillator.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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;
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/ModelByteBuffer.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/ModelByteBuffer.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,329 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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 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 RandomAccessFile raf;
+ private long left;
+ private long mark = 0;
+ private long markleft = 0;
+
+ public 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) {
+ 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 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;
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/ModelByteBufferWavetable.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/ModelByteBufferWavetable.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,281 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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 class ModelByteBufferWavetable implements ModelWavetable {
+
+ private class Buffer8PlusInputStream extends InputStream {
+
+ private boolean bigendian;
+ private int framesize_pc;
+ int pos = 0;
+ int pos2 = 0;
+ int markpos = 0;
+ int markpos2 = 0;
+
+ public 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 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()));
+ }
+ 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;
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/ModelChannelMixer.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/ModelChannelMixer.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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.
+ * It can be used to:
+ *
+ * Implement non-voice oriented instruments.
+ * Add insert effect to instruments; for example distortion effect.
+ *
+ *
+ * Warning! Classes that implements ModelChannelMixer must be thread-safe.
+ *
+ * @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();
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/ModelConnectionBlock.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/ModelConnectionBlock.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.media.sound;
+
+/**
+ * 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 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 sources;
+ }
+
+ public void setSources(ModelSource[] source) {
+ this.sources = source;
+ }
+
+ public void addSource(ModelSource source) {
+ ModelSource[] oldsources = sources;
+ sources = new ModelSource[oldsources.length + 1];
+ for (int i = 0; i < oldsources.length; i++) {
+ sources[i] = oldsources[i];
+ }
+ sources[sources.length - 1] = source;
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/ModelDestination.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/ModelDestination.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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 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;
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/ModelDirectedPlayer.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/ModelDirectedPlayer.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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);
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/ModelDirector.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/ModelDirector.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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();
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/ModelIdentifier.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/ModelIdentifier.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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 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;
+ }
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/ModelInstrument.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/ModelInstrument.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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.
+ *
+ *
The main methods to override are:
+ * getPerformer, getDirector, getChannelMixer.
+ *
+ *
Performers are used to define what voices which will
+ * playback when using the instrument.
+ *
+ * ChannelMixer is used to add channel-wide processing
+ * on voices output or to define non-voice oriented instruments.
+ *
+ * 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 ModelStandardDirector(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 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 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 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;
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/ModelInstrumentComparator.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/ModelInstrumentComparator.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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 class ModelInstrumentComparator implements Comparator {
+
+ 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;
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/ModelMappedInstrument.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/ModelMappedInstrument.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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 class ModelMappedInstrument extends ModelInstrument {
+
+ private 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);
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/ModelOscillator.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/ModelOscillator.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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);
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/ModelOscillatorStream.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/ModelOscillatorStream.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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;
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/ModelPatch.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/ModelPatch.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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 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;
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/ModelPerformer.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/ModelPerformer.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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 class ModelPerformer {
+
+ private List oscillators = new ArrayList();
+ private List connectionBlocks
+ = new ArrayList();
+ 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 getConnectionBlocks() {
+ return connectionBlocks;
+ }
+
+ public void setConnectionBlocks(List connectionBlocks) {
+ this.connectionBlocks = connectionBlocks;
+ }
+
+ public List 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;
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/ModelSource.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/ModelSource.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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 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;
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/ModelStandardDirector.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/ModelStandardDirector.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.media.sound;
+
+/**
+ * A standard director who chooses performers
+ * by there keyfrom,keyto,velfrom,velto properties.
+ *
+ * @author Karl Helgason
+ */
+public class ModelStandardDirector implements ModelDirector {
+
+ ModelPerformer[] performers;
+ ModelDirectedPlayer player;
+ boolean noteOnUsed = false;
+ boolean noteOffUsed = false;
+
+ public ModelStandardDirector(ModelPerformer[] performers,
+ ModelDirectedPlayer player) {
+ this.performers = performers;
+ this.player = player;
+ for (int i = 0; i < performers.length; i++) {
+ ModelPerformer p = performers[i];
+ 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);
+ }
+ }
+ }
+ }
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/ModelStandardTransform.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/ModelStandardTransform.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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 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;
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/ModelTransform.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/ModelTransform.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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);
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/ModelWavetable.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/ModelWavetable.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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();
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/Platform.java
--- a/jdk/src/share/classes/com/sun/media/sound/Platform.java Thu Jan 29 21:46:48 2009 -0800
+++ b/jdk/src/share/classes/com/sun/media/sound/Platform.java Tue Feb 03 22:02:55 2009 -0800
@@ -42,8 +42,6 @@
// native library we need to load
private static final String libNameMain = "jsound";
- private static final String libNameMain2 = "jsoundhs";
-
private static final String libNameALSA = "jsoundalsa";
private static final String libNameDSound = "jsoundds";
@@ -158,9 +156,8 @@
if(Printer.trace)Printer.trace(">>Platform.loadLibraries");
try {
- // load the main libraries
+ // load the main library
JSSecurityManager.loadLibrary(libNameMain);
- JSSecurityManager.loadLibrary(libNameMain2);
// just for the heck of it...
loadedLibs |= LIB_MAIN;
} catch (SecurityException e) {
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/RIFFInvalidDataException.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/RIFFInvalidDataException.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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 class RIFFInvalidDataException extends InvalidDataException {
+
+ private static final long serialVersionUID = 1L;
+
+ public RIFFInvalidDataException() {
+ super("Invalid Data!");
+ }
+
+ public RIFFInvalidDataException(String s) {
+ super(s);
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/RIFFInvalidFormatException.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/RIFFInvalidFormatException.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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 class RIFFInvalidFormatException extends InvalidFormatException {
+
+ private static final long serialVersionUID = 1L;
+
+ public RIFFInvalidFormatException() {
+ super("Invalid format!");
+ }
+
+ public RIFFInvalidFormatException(String s) {
+ super(s);
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/RIFFReader.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/RIFFReader.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,332 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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 class RIFFReader extends InputStream {
+
+ private RIFFReader root;
+ private long filepointer = 0;
+ private String fourcc;
+ private String riff_type = null;
+ private long ckSize = 0;
+ private InputStream stream;
+ private long avail;
+ private RIFFReader lastiterator = null;
+
+ public RIFFReader(InputStream stream) throws IOException {
+
+ if (stream instanceof RIFFReader)
+ root = ((RIFFReader)stream).root;
+ else
+ root = this;
+
+ this.stream = stream;
+ avail = Integer.MAX_VALUE;
+ ckSize = Integer.MAX_VALUE;
+
+ // 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 = this.ckSize;
+
+ if (getFormat().equals("RIFF") || getFormat().equals("LIST")) {
+ 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)
+ 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)
+ 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;
+ }
+ }
+
+ public final long skipBytes(long n) throws IOException {
+ if (n < 0)
+ return 0;
+ long skipped = 0;
+ while (skipped != n) {
+ long s = skip(n - skipped);
+ if (s < 0)
+ break;
+ if (s == 0)
+ Thread.yield();
+ skipped += s;
+ }
+ return skipped;
+ }
+
+ public long skip(long n) throws IOException {
+ if (avail == 0)
+ return -1;
+ if (n > avail) {
+ long len = stream.skip(avail);
+ if (len != -1)
+ filepointer += len;
+ avail = 0;
+ return len;
+ } else {
+ long ret = stream.skip(n);
+ if (ret == -1)
+ return -1;
+ avail -= ret;
+ filepointer += ret;
+ return ret;
+ }
+ }
+
+ public int available() {
+ return (int)avail;
+ }
+
+ public void finish() throws IOException {
+ if (avail != 0) {
+ skipBytes(avail);
+ }
+ }
+
+ // Read ASCII chars from stream
+ public String readString(int len) throws IOException {
+ byte[] buff = new byte[len];
+ 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);
+ }
+
+ public void close() throws IOException {
+ finish();
+ if (this == root)
+ stream.close();
+ stream = null;
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/RIFFWriter.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/RIFFWriter.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,365 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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 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;
+
+ public RandomAccessFileWriter(File file) throws FileNotFoundException {
+ this.raf = new RandomAccessFile(file, "rw");
+ }
+
+ public 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;
+ OutputStream stream;
+
+ public 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 long chunksizepointer;
+ private 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);
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/RealTimeSequencer.java
--- a/jdk/src/share/classes/com/sun/media/sound/RealTimeSequencer.java Thu Jan 29 21:46:48 2009 -0800
+++ b/jdk/src/share/classes/com/sun/media/sound/RealTimeSequencer.java Tue Feb 03 22:02:55 2009 -0800
@@ -54,10 +54,6 @@
private final static boolean DEBUG_PUMP = false;
private final static boolean DEBUG_PUMP_ALL = false;
-
- /** if true, we bridge RMF files over to the old MixerSequencer */
- private final static boolean RMF = true;
-
/**
* Event Dispatcher thread. Should be using a shared event
* dispatcher instance with a factory in EventDispatcher
@@ -145,9 +141,6 @@
private ArrayList controllerEventListeners = new ArrayList();
- /** for RMF media we need the RMF sequencer */
- private MixerSequencer seqBridge = null;
-
/** automatic connection support */
private boolean autoConnect = false;
@@ -220,21 +213,6 @@
playThread.setSequence(sequence);
}
}
- if (RMF) {
- if (seqBridge != null) {
- seqBridge.close();
- seqBridge = null;
- }
- // if previous file was an RMF, but this file is not RMF,
- // then need to call implOpen again!
- if (isOpen() && sequence != null && playThread == null) {
- try {
- implOpen();
- } catch (MidiUnavailableException mue) {
- if (Printer.err) mue.printStackTrace();
- }
- }
- }
if (Printer.trace) Printer.trace("<< RealTimeSequencer: setSequence(" + sequence +") completed");
}
@@ -249,52 +227,6 @@
return;
}
- // need to be able to detect RMF
- if (RMF) {
- MidiFileFormat fileFormat = MidiSystem.getMidiFileFormat(stream); // can throw IOException, InvalidMidiDataException
- int type = fileFormat.getType();
- int resolution = fileFormat.getResolution();
- if (Printer.debug) Printer.debug("Got file with type="+type+" and resolution="+resolution);
- if (resolution == MidiFileFormat.UNKNOWN_LENGTH) {
- // seems to be RMF
- if (seqBridge == null) {
- try {
- seqBridge = new MixerSequencer();
- if (isOpen()) {
- seqBridge.open();
- }
- } catch (MidiUnavailableException mue) {
- // uhum, strange situation. Need to cast to InvalidMidiDataException
- throw new InvalidMidiDataException(mue.getMessage());
- }
- }
- seqBridge.setSequence(stream);
- // propagate state
- seqBridge.setTempoFactor(getTempoFactor());
-
- // propagate listeners
- synchronized(metaEventListeners) {
- for (int i = 0 ; i < metaEventListeners.size(); i++) {
- seqBridge.addMetaEventListener((MetaEventListener) (metaEventListeners.get(i)));
- }
- }
- synchronized(controllerEventListeners) {
- for (int i = 0 ; i < controllerEventListeners.size(); i++) {
- ControllerListElement cve = (ControllerListElement) (controllerEventListeners.get(i));
- seqBridge.addControllerEventListener(cve.listener, cve.controllers);
- }
- }
- // disable the current sequence of RealTimeSequencer
- //setSequence((Sequence) null); -> will remove bridge again!
- this.sequence = null;
- return;
- }
- if (seqBridge != null) {
- seqBridge.close();
- seqBridge = null;
- }
- }
-
Sequence seq = MidiSystem.getSequence(stream); // can throw IOException, InvalidMidiDataException
setSequence(seq);
@@ -305,22 +237,11 @@
public Sequence getSequence() {
- if (RMF) {
- if (seqBridge != null) {
- return seqBridge.getSequence();
- }
- }
return sequence;
}
public synchronized void start() {
- if (RMF) {
- if (seqBridge != null) {
- seqBridge.start();
- return;
- }
- }
if (Printer.trace) Printer.trace(">> RealTimeSequencer: start()");
// sequencer not open: throw an exception
@@ -346,12 +267,6 @@
public synchronized void stop() {
- if (RMF) {
- if (seqBridge != null) {
- seqBridge.stop();
- return;
- }
- }
if (Printer.trace) Printer.trace(">> RealTimeSequencer: stop()");
if (!isOpen()) {
@@ -373,23 +288,11 @@
public boolean isRunning() {
- if (RMF) {
- if (seqBridge != null) {
- return seqBridge.isRunning();
- }
- }
return running;
}
public void startRecording() {
- if (RMF) {
- if (seqBridge != null) {
- seqBridge.startRecording();
- return;
- }
- }
-
if (!isOpen()) {
throw new IllegalStateException("Sequencer not open");
}
@@ -400,13 +303,6 @@
public void stopRecording() {
- if (RMF) {
- if (seqBridge != null) {
- seqBridge.stopRecording();
- return;
- }
- }
-
if (!isOpen()) {
throw new IllegalStateException("Sequencer not open");
}
@@ -415,23 +311,11 @@
public boolean isRecording() {
- if (RMF) {
- if (seqBridge != null) {
- return seqBridge.isRecording();
- }
- }
return recording;
}
public void recordEnable(Track track, int channel) {
- if (RMF) {
- if (seqBridge != null) {
- seqBridge.recordEnable(track, channel);
- return;
- }
- }
-
if (!findTrack(track)) {
throw new IllegalArgumentException("Track does not exist in the current sequence");
}
@@ -449,13 +333,6 @@
public void recordDisable(Track track) {
- if (RMF) {
- if (seqBridge != null) {
- seqBridge.recordDisable(track);
- return;
- }
- }
-
synchronized(recordingTracks) {
RecordingTrack rc = RecordingTrack.get(recordingTracks, track);
if (rc != null) {
@@ -482,11 +359,6 @@
public float getTempoInBPM() {
- if (RMF) {
- if (seqBridge != null) {
- return seqBridge.getTempoInBPM();
- }
- }
if (Printer.trace) Printer.trace(">> RealTimeSequencer: getTempoInBPM() ");
return (float) MidiUtils.convertTempo(getTempoInMPQ());
@@ -494,12 +366,6 @@
public void setTempoInBPM(float bpm) {
- if (RMF) {
- if (seqBridge != null) {
- seqBridge.setTempoInBPM(bpm);
- return;
- }
- }
if (Printer.trace) Printer.trace(">> RealTimeSequencer: setTempoInBPM() ");
if (bpm <= 0) {
// should throw IllegalArgumentException
@@ -511,12 +377,6 @@
public float getTempoInMPQ() {
- if (RMF) {
- if (seqBridge != null) {
- return seqBridge.getTempoInMPQ();
- }
- }
-
if (Printer.trace) Printer.trace(">> RealTimeSequencer: getTempoInMPQ() ");
if (needCaching()) {
@@ -537,12 +397,6 @@
public void setTempoInMPQ(float mpq) {
- if (RMF) {
- if (seqBridge != null) {
- seqBridge.setTempoInMPQ(mpq);
- return;
- }
- }
if (mpq <= 0) {
// should throw IllegalArgumentException
mpq = 1.0f;
@@ -564,12 +418,6 @@
public void setTempoFactor(float factor) {
- if (RMF) {
- if (seqBridge != null) {
- seqBridge.setTempoFactor(factor);
- return;
- }
- }
if (factor <= 0) {
// should throw IllegalArgumentException
return;
@@ -588,11 +436,6 @@
public float getTempoFactor() {
- if (RMF) {
- if (seqBridge != null) {
- return seqBridge.getTempoFactor();
- }
- }
if (Printer.trace) Printer.trace(">> RealTimeSequencer: getTempoFactor() ");
if (needCaching()) {
@@ -606,11 +449,6 @@
public long getTickLength() {
- if (RMF) {
- if (seqBridge != null) {
- return seqBridge.getTickLength();
- }
- }
if (Printer.trace) Printer.trace(">> RealTimeSequencer: getTickLength() ");
if (sequence == null) {
@@ -622,11 +460,6 @@
public synchronized long getTickPosition() {
- if (RMF) {
- if (seqBridge != null) {
- return seqBridge.getTickPosition();
- }
- }
if (Printer.trace) Printer.trace(">> RealTimeSequencer: getTickPosition() ");
if (getDataPump() == null || sequence == null) {
@@ -638,12 +471,6 @@
public synchronized void setTickPosition(long tick) {
- if (RMF) {
- if (seqBridge != null) {
- seqBridge.setTickPosition(tick);
- return;
- }
- }
if (tick < 0) {
// should throw IllegalArgumentException
return;
@@ -667,12 +494,6 @@
public long getMicrosecondLength() {
- if (RMF) {
- if (seqBridge != null) {
- return seqBridge.getMicrosecondLength();
- }
- }
-
if (Printer.trace) Printer.trace(">> RealTimeSequencer: getMicrosecondLength() ");
if (sequence == null) {
@@ -684,12 +505,6 @@
public long getMicrosecondPosition() {
- if (RMF) {
- if (seqBridge != null) {
- return seqBridge.getMicrosecondPosition();
- }
- }
-
if (Printer.trace) Printer.trace(">> RealTimeSequencer: getMicrosecondPosition() ");
if (getDataPump() == null || sequence == null) {
@@ -702,13 +517,6 @@
public void setMicrosecondPosition(long microseconds) {
- if (RMF) {
- if (seqBridge != null) {
- seqBridge.setMicrosecondPosition(microseconds);
- return;
- }
- }
-
if (microseconds < 0) {
// should throw IllegalArgumentException
return;
@@ -734,33 +542,16 @@
public void setMasterSyncMode(Sequencer.SyncMode sync) {
- if (RMF) {
- if (seqBridge != null) {
- seqBridge.setMasterSyncMode(sync);
- return;
- }
- }
// not supported
}
public Sequencer.SyncMode getMasterSyncMode() {
- if (RMF) {
- if (seqBridge != null) {
- return seqBridge.getMasterSyncMode();
- }
- }
return masterSyncMode;
}
public Sequencer.SyncMode[] getMasterSyncModes() {
- if (RMF) {
- if (seqBridge != null) {
- return seqBridge.getMasterSyncModes();
- }
- }
-
Sequencer.SyncMode[] returnedModes = new Sequencer.SyncMode[masterSyncModes.length];
System.arraycopy(masterSyncModes, 0, returnedModes, 0, masterSyncModes.length);
return returnedModes;
@@ -768,33 +559,16 @@
public void setSlaveSyncMode(Sequencer.SyncMode sync) {
- if (RMF) {
- if (seqBridge != null) {
- seqBridge.setSlaveSyncMode(sync);
- return;
- }
- }
// not supported
}
public Sequencer.SyncMode getSlaveSyncMode() {
- if (RMF) {
- if (seqBridge != null) {
- return seqBridge.getSlaveSyncMode();
- }
- }
return slaveSyncMode;
}
public Sequencer.SyncMode[] getSlaveSyncModes() {
- if (RMF) {
- if (seqBridge != null) {
- return seqBridge.getSlaveSyncModes();
- }
- }
-
Sequencer.SyncMode[] returnedModes = new Sequencer.SyncMode[slaveSyncModes.length];
System.arraycopy(slaveSyncModes, 0, returnedModes, 0, slaveSyncModes.length);
return returnedModes;
@@ -812,12 +586,6 @@
public synchronized void setTrackMute(int track, boolean mute) {
- if (RMF) {
- if (seqBridge != null) {
- seqBridge.setTrackMute(track, mute);
- return;
- }
- }
int trackCount = getTrackCount();
if (track < 0 || track >= getTrackCount()) return;
trackMuted = ensureBoolArraySize(trackMuted, trackCount);
@@ -829,11 +597,6 @@
public synchronized boolean getTrackMute(int track) {
- if (RMF) {
- if (seqBridge != null) {
- return seqBridge.getTrackMute(track);
- }
- }
if (track < 0 || track >= getTrackCount()) return false;
if (trackMuted == null || trackMuted.length <= track) return false;
return trackMuted[track];
@@ -841,12 +604,6 @@
public synchronized void setTrackSolo(int track, boolean solo) {
- if (RMF) {
- if (seqBridge != null) {
- seqBridge.setTrackSolo(track, solo);
- return;
- }
- }
int trackCount = getTrackCount();
if (track < 0 || track >= getTrackCount()) return;
trackSolo = ensureBoolArraySize(trackSolo, trackCount);
@@ -858,11 +615,6 @@
public synchronized boolean getTrackSolo(int track) {
- if (RMF) {
- if (seqBridge != null) {
- return seqBridge.getTrackSolo(track);
- }
- }
if (track < 0 || track >= getTrackCount()) return false;
if (trackSolo == null || trackSolo.length <= track) return false;
return trackSolo[track];
@@ -870,12 +622,6 @@
public boolean addMetaEventListener(MetaEventListener listener) {
- if (RMF) {
- if (seqBridge != null) {
- seqBridge.addMetaEventListener(listener);
- // do not return here!
- }
- }
synchronized(metaEventListeners) {
if (! metaEventListeners.contains(listener)) {
@@ -887,12 +633,6 @@
public void removeMetaEventListener(MetaEventListener listener) {
- if (RMF) {
- if (seqBridge != null) {
- seqBridge.removeMetaEventListener(listener);
- // do not return here!
- }
- }
synchronized(metaEventListeners) {
int index = metaEventListeners.indexOf(listener);
if (index >= 0) {
@@ -903,13 +643,6 @@
public int[] addControllerEventListener(ControllerEventListener listener, int[] controllers) {
- if (RMF) {
- if (seqBridge != null) {
- seqBridge.addControllerEventListener(listener, controllers);
- // do not return here!
- }
- }
-
synchronized(controllerEventListeners) {
// first find the listener. if we have one, add the controllers
@@ -938,12 +671,6 @@
public int[] removeControllerEventListener(ControllerEventListener listener, int[] controllers) {
- if (RMF) {
- if (seqBridge != null) {
- seqBridge.removeControllerEventListener(listener, controllers);
- // do not return here!
- }
- }
synchronized(controllerEventListeners) {
ControllerListElement cve = null;
boolean flag = false;
@@ -973,12 +700,6 @@
////////////////// LOOPING (added in 1.5) ///////////////////////
public void setLoopStartPoint(long tick) {
- if (RMF) {
- if (seqBridge != null) {
- seqBridge.setLoopStartPoint(tick);
- return;
- }
- }
if ((tick > getTickLength())
|| ((loopEnd != -1) && (tick > loopEnd))
|| (tick < 0)) {
@@ -988,21 +709,10 @@
}
public long getLoopStartPoint() {
- if (RMF) {
- if (seqBridge != null) {
- return seqBridge.getLoopStartPoint();
- }
- }
return loopStart;
}
public void setLoopEndPoint(long tick) {
- if (RMF) {
- if (seqBridge != null) {
- seqBridge.setLoopEndPoint(tick);
- return;
- }
- }
if ((tick > getTickLength())
|| ((loopStart > tick) && (tick != -1))
|| (tick < -1)) {
@@ -1012,21 +722,10 @@
}
public long getLoopEndPoint() {
- if (RMF) {
- if (seqBridge != null) {
- return seqBridge.getLoopEndPoint();
- }
- }
return loopEnd;
}
public void setLoopCount(int count) {
- if (RMF) {
- if (seqBridge != null) {
- seqBridge.setLoopCount(count);
- return;
- }
- }
if (count != LOOP_CONTINUOUSLY
&& count < 0) {
throw new IllegalArgumentException("illegal value for loop count: "+count);
@@ -1038,11 +737,6 @@
}
public int getLoopCount() {
- if (RMF) {
- if (seqBridge != null) {
- return seqBridge.getLoopCount();
- }
- }
return loopCount;
}
@@ -1053,13 +747,6 @@
*/
protected void implOpen() throws MidiUnavailableException {
if (Printer.trace) Printer.trace(">> RealTimeSequencer: implOpen()");
- if (RMF) {
- if (seqBridge != null) {
- seqBridge.open();
- if (Printer.trace) Printer.trace("<< RealTimeSequencer: -> called seqBridge.open");
- return;
- }
- }
//openInternalSynth();
@@ -1095,12 +782,6 @@
synth.open();
if (synth instanceof ReferenceCountingDevice) {
rec = ((ReferenceCountingDevice) synth).getReceiverReferenceCounting();
- if (synth.getClass().toString().contains("com.sun.media.sound.MixerSynth")
- && (synth.getDefaultSoundbank() == null)) {
- // don't use this receiver if no soundbank available
- rec = null;
- synth.close();
- }
} else {
rec = synth.getReceiver();
}
@@ -1147,12 +828,6 @@
protected synchronized void implClose() {
- if (RMF) {
- if (seqBridge != null) {
- seqBridge.close();
- // don't return here!
- }
- }
if (Printer.trace) Printer.trace(">> RealTimeSequencer: implClose() ");
if (playThread == null) {
@@ -1302,12 +977,6 @@
// OVERRIDES OF ABSTRACT MIDI DEVICE METHODS
protected boolean hasReceivers() {
- if (RMF) {
- if (seqBridge != null) {
- //RMF does not allow recording
- return false;
- }
- }
return true;
}
@@ -1318,12 +987,6 @@
protected boolean hasTransmitters() {
- if (RMF) {
- if (seqBridge != null) {
- //RMF does never allow setting own receivers
- return false;
- }
- }
return true;
}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SF2GlobalRegion.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SF2GlobalRegion.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.media.sound;
+
+/**
+ * Soundfont global region.
+ *
+ * @author Karl Helgason
+ */
+public class SF2GlobalRegion extends SF2Region {
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SF2Instrument.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SF2Instrument.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,911 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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 class SF2Instrument extends ModelInstrument {
+
+ protected String name = "";
+ protected int preset = 0;
+ protected int bank = 0;
+ protected long library = 0;
+ protected long genre = 0;
+ protected long morphology = 0;
+ protected SF2GlobalRegion globalregion = null;
+ protected List regions
+ = new ArrayList();
+
+ 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 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 pgenerators = new HashMap();
+ 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 generators = new HashMap();
+ if (layerglobal != null)
+ generators.putAll(layerglobal.getGenerators());
+ generators.putAll(layerzone.getGenerators());
+ for (Map.Entry 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;
+ }
+
+ protected 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 generators, int gen) {
+ if (generators.containsKey(gen))
+ return generators.get(gen);
+ return SF2Region.getDefaultValue(gen);
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SF2InstrumentRegion.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SF2InstrumentRegion.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.media.sound;
+
+/**
+ * Soundfont instrument region.
+ *
+ * @author Karl Helgason
+ */
+public class SF2InstrumentRegion extends SF2Region {
+
+ protected SF2Layer layer;
+
+ public SF2Layer getLayer() {
+ return layer;
+ }
+
+ public void setLayer(SF2Layer layer) {
+ this.layer = layer;
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SF2Layer.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SF2Layer.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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 class SF2Layer extends SoundbankResource {
+
+ protected String name = "";
+ protected SF2GlobalRegion globalregion = null;
+ protected List regions = new ArrayList();
+
+ 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 getRegions() {
+ return regions;
+ }
+
+ public SF2GlobalRegion getGlobalRegion() {
+ return globalregion;
+ }
+
+ public void setGlobalZone(SF2GlobalRegion zone) {
+ globalregion = zone;
+ }
+
+ public String toString() {
+ return "Layer: " + name;
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SF2LayerRegion.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SF2LayerRegion.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.media.sound;
+
+/**
+ * Soundfont layer region.
+ *
+ * @author Karl Helgason
+ */
+public class SF2LayerRegion extends SF2Region {
+
+ protected SF2Sample sample;
+
+ public SF2Sample getSample() {
+ return sample;
+ }
+
+ public void setSample(SF2Sample sample) {
+ this.sample = sample;
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SF2Modulator.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SF2Modulator.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.media.sound;
+
+/**
+ * Soundfont modulator container.
+ *
+ * @author Karl Helgason
+ */
+public 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;
+ protected int sourceOperator;
+ protected int destinationOperator;
+ protected short amount;
+ protected int amountSourceOperator;
+ protected 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;
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SF2Region.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SF2Region.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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 generators = new HashMap();
+ protected List modulators = new ArrayList();
+
+ public Map 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 getModulators() {
+ return modulators;
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SF2Sample.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SF2Sample.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,216 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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 class SF2Sample extends SoundbankResource {
+
+ protected String name = "";
+ protected long startLoop = 0;
+ protected long endLoop = 0;
+ protected long sampleRate = 44100;
+ protected int originalPitch = 60;
+ protected byte pitchCorrection = 0;
+ protected int sampleLink = 0;
+ protected int sampleType = 0;
+ protected ModelByteBuffer data;
+ protected 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;
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SF2Soundbank.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SF2Soundbank.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,973 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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:
+ * http://developer.creative.com
+ * http://www.soundfont.com/ ;
+ *
+ * @author Karl Helgason
+ */
+public class SF2Soundbank implements Soundbank {
+
+ // version of the Sound Font RIFF file
+ protected int major = 2;
+ protected int minor = 1;
+ // target Sound Engine
+ protected String targetEngine = "EMU8000";
+ // Sound Font Bank Name
+ protected String name = "untitled";
+ // Sound ROM Name
+ protected String romName = null;
+ // Sound ROM Version
+ protected int romVersionMajor = -1;
+ protected int romVersionMinor = -1;
+ // Date of Creation of the Bank
+ protected String creationDate = null;
+ // Sound Designers and Engineers for the Bank
+ protected String engineers = null;
+ // Product for which the Bank was intended
+ protected String product = null;
+ // Copyright message
+ protected String copyright = null;
+ // Comments
+ protected String comments = null;
+ // The SoundFont tools used to create and alter the bank
+ protected 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 List instruments = new ArrayList();
+ private List layers = new ArrayList();
+ private List samples = new ArrayList();
+
+ 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 presets = new ArrayList();
+ List presets_bagNdx = new ArrayList();
+ List presets_splits_gen
+ = new ArrayList();
+ List presets_splits_mod
+ = new ArrayList();
+
+ List instruments = new ArrayList();
+ List instruments_bagNdx = new ArrayList();
+ List instruments_splits_gen
+ = new ArrayList();
+ List instruments_splits_mod
+ = new ArrayList();
+
+ 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--;
+ }
+
+ 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--;
+ }
+
+ 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();
+ 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();
+ 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 liter = this.layers.iterator();
+ while (liter.hasNext()) {
+ SF2Layer layer = liter.next();
+ Iterator 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);
+ 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 iiter = this.instruments.iterator();
+ while (iiter.hasNext()) {
+ SF2Instrument instrument = iiter.next();
+ Iterator 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);
+ 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 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 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 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);
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SF2SoundbankReader.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SF2SoundbankReader.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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 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;
+ }
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SimpleInstrument.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SimpleInstrument.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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 parts
+ = new ArrayList();
+
+ 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();
+ }
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SimpleSoundbank.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SimpleSoundbank.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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 resources = new ArrayList();
+ List instruments = new ArrayList();
+
+ 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);
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SoftAbstractResampler.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SoftAbstractResampler.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,390 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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;
+
+ public 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 SoftResamplerStreamer openStreamer() {
+ return new ModelAbstractResamplerStream();
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SoftAudioBuffer.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SoftAudioBuffer.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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 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 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;
+ }
+ }
+ }
+
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SoftAudioProcessor.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SoftAudioProcessor.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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();
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SoftAudioPusher.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SoftAudioPusher.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.media.sound;
+
+import java.io.IOException;
+
+import javax.sound.sampled.AudioInputStream;
+import javax.sound.sampled.SourceDataLine;
+
+/**
+ * This is a processor object that writes into SourceDataLine
+ *
+ * @author Karl Helgason
+ */
+public class SoftAudioPusher implements Runnable {
+
+ private volatile boolean active = false;
+ private SourceDataLine sourceDataLine = null;
+ private Thread audiothread;
+ private AudioInputStream ais;
+ private byte[] buffer;
+
+ public SoftAudioPusher(SourceDataLine sourceDataLine, AudioInputStream ais,
+ int workbuffersizer) {
+ this.ais = ais;
+ this.buffer = new byte[workbuffersizer];
+ this.sourceDataLine = sourceDataLine;
+ }
+
+ public synchronized void start() {
+ if (active)
+ return;
+ active = true;
+ audiothread = new Thread(this);
+ audiothread.setPriority(Thread.MAX_PRIORITY);
+ audiothread.start();
+ }
+
+ public synchronized void stop() {
+ if (!active)
+ return;
+ active = false;
+ try {
+ audiothread.join();
+ } catch (InterruptedException e) {
+ //e.printStackTrace();
+ }
+ }
+
+ public void run() {
+ byte[] buffer = SoftAudioPusher.this.buffer;
+ AudioInputStream ais = SoftAudioPusher.this.ais;
+ SourceDataLine sourceDataLine = SoftAudioPusher.this.sourceDataLine;
+
+ try {
+ while (active) {
+ // Read from audio source
+ int count = ais.read(buffer);
+ if(count < 0) break;
+ // Write byte buffer to source output
+ sourceDataLine.write(buffer, 0, count);
+ }
+ } catch (IOException e) {
+ active = false;
+ //e.printStackTrace();
+ }
+
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SoftChannel.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SoftChannel.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,1548 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.sound.midi.MidiChannel;
+import javax.sound.midi.Patch;
+
+/**
+ * Software Synthesizer MIDI channel class.
+ *
+ * @author Karl Helgason
+ */
+public class SoftChannel implements MidiChannel, ModelDirectedPlayer {
+
+ private static boolean[] dontResetControls = new boolean[128];
+ static {
+ for (int i = 0; i < dontResetControls.length; i++)
+ dontResetControls[i] = false;
+
+ dontResetControls[0] = true; // Bank Select (MSB)
+ dontResetControls[32] = true; // Bank Select (LSB)
+ dontResetControls[7] = true; // Channel Volume (MSB)
+ dontResetControls[8] = true; // Balance (MSB)
+ dontResetControls[10] = true; // Pan (MSB)
+ dontResetControls[11] = true; // Expression (MSB)
+ dontResetControls[91] = true; // Effects 1 Depth (default: Reverb Send)
+ dontResetControls[92] = true; // Effects 2 Depth (default: Tremolo Depth)
+ dontResetControls[93] = true; // Effects 3 Depth (default: Chorus Send)
+ dontResetControls[94] = true; // Effects 4 Depth (default: Celeste [Detune] Depth)
+ dontResetControls[95] = true; // Effects 5 Depth (default: Phaser Depth)
+ dontResetControls[70] = true; // Sound Controller 1 (default: Sound Variation)
+ dontResetControls[71] = true; // Sound Controller 2 (default: Timbre / Harmonic Quality)
+ dontResetControls[72] = true; // Sound Controller 3 (default: Release Time)
+ dontResetControls[73] = true; // Sound Controller 4 (default: Attack Time)
+ dontResetControls[74] = true; // Sound Controller 5 (default: Brightness)
+ dontResetControls[75] = true; // Sound Controller 6 (GM2 default: Decay Time)
+ dontResetControls[76] = true; // Sound Controller 7 (GM2 default: Vibrato Rate)
+ dontResetControls[77] = true; // Sound Controller 8 (GM2 default: Vibrato Depth)
+ dontResetControls[78] = true; // Sound Controller 9 (GM2 default: Vibrato Delay)
+ dontResetControls[79] = true; // Sound Controller 10 (GM2 default: Undefined)
+ dontResetControls[120] = true; // All Sound Off
+ dontResetControls[121] = true; // Reset All Controllers
+ dontResetControls[122] = true; // Local Control On/Off
+ dontResetControls[123] = true; // All Notes Off
+ dontResetControls[124] = true; // Omni Mode Off
+ dontResetControls[125] = true; // Omni Mode On
+ dontResetControls[126] = true; // Poly Mode Off
+ dontResetControls[127] = true; // Poly Mode On
+
+ dontResetControls[6] = true; // Data Entry (MSB)
+ dontResetControls[38] = true; // Data Entry (LSB)
+ dontResetControls[96] = true; // Data Increment
+ dontResetControls[97] = true; // Data Decrement
+ dontResetControls[98] = true; // Non-Registered Parameter Number (LSB)
+ dontResetControls[99] = true; // Non-Registered Parameter Number(MSB)
+ dontResetControls[100] = true; // RPN = Null
+ dontResetControls[101] = true; // RPN = Null
+
+ }
+
+ private static final int RPN_NULL_VALUE = (127 << 7) + 127;
+ private int rpn_control = RPN_NULL_VALUE;
+ private int nrpn_control = RPN_NULL_VALUE;
+ protected double portamento_time = 1; // keyschanges per control buffer time
+ protected int[] portamento_lastnote = new int[128];
+ protected int portamento_lastnote_ix = 0;
+ private int portamento_control_note = -1;
+ private boolean portamento = false;
+ private boolean mono = false;
+ private boolean mute = false;
+ private boolean solo = false;
+ private boolean solomute = false;
+ private Object control_mutex;
+ private int channel;
+ private SoftVoice[] voices;
+ private int bank;
+ private int program;
+ private SoftSynthesizer synthesizer;
+ private SoftMainMixer mainmixer;
+ private int[] polypressure = new int[128];
+ private int channelpressure = 0;
+ private int[] controller = new int[128];
+ private int pitchbend;
+ private double[] co_midi_pitch = new double[1];
+ private double[] co_midi_channel_pressure = new double[1];
+ protected SoftTuning tuning = new SoftTuning();
+ protected int tuning_bank = 0;
+ protected int tuning_program = 0;
+ protected SoftInstrument current_instrument = null;
+ protected ModelChannelMixer current_mixer = null;
+ private ModelDirector current_director = null;
+
+ // Controller Destination Settings
+ protected int cds_control_number = -1;
+ protected ModelConnectionBlock[] cds_control_connections = null;
+ protected ModelConnectionBlock[] cds_channelpressure_connections = null;
+ protected ModelConnectionBlock[] cds_polypressure_connections = null;
+ protected boolean sustain = false;
+ protected boolean[][] keybasedcontroller_active = null;
+ protected double[][] keybasedcontroller_value = null;
+
+ private class MidiControlObject implements SoftControl {
+ double[] pitch = co_midi_pitch;
+ double[] channel_pressure = co_midi_channel_pressure;
+ double[] poly_pressure = new double[1];
+
+ public double[] get(int instance, String name) {
+ if (name == null)
+ return null;
+ if (name.equals("pitch"))
+ return pitch;
+ if (name.equals("channel_pressure"))
+ return channel_pressure;
+ if (name.equals("poly_pressure"))
+ return poly_pressure;
+ return null;
+ }
+ }
+
+ private SoftControl[] co_midi = new SoftControl[128];
+ {
+ for (int i = 0; i < co_midi.length; i++) {
+ co_midi[i] = new MidiControlObject();
+ }
+ }
+
+ private double[][] co_midi_cc_cc = new double[128][1];
+ private SoftControl co_midi_cc = new SoftControl() {
+ double[][] cc = co_midi_cc_cc;
+ public double[] get(int instance, String name) {
+ if (name == null)
+ return null;
+ return cc[Integer.parseInt(name)];
+ }
+ };
+ Map co_midi_rpn_rpn_i = new HashMap();
+ Map co_midi_rpn_rpn = new HashMap();
+ private SoftControl co_midi_rpn = new SoftControl() {
+ Map rpn = co_midi_rpn_rpn;
+ public double[] get(int instance, String name) {
+ if (name == null)
+ return null;
+ int iname = Integer.parseInt(name);
+ double[] v = rpn.get(iname);
+ if (v == null) {
+ v = new double[1];
+ rpn.put(iname, v);
+ }
+ return v;
+ }
+ };
+ Map co_midi_nrpn_nrpn_i = new HashMap();
+ Map co_midi_nrpn_nrpn = new HashMap();
+ private SoftControl co_midi_nrpn = new SoftControl() {
+ Map nrpn = co_midi_nrpn_nrpn;
+ public double[] get(int instance, String name) {
+ if (name == null)
+ return null;
+ int iname = Integer.parseInt(name);
+ double[] v = nrpn.get(iname);
+ if (v == null) {
+ v = new double[1];
+ nrpn.put(iname, v);
+ }
+ return v;
+ }
+ };
+
+ private static int restrict7Bit(int value)
+ {
+ if(value < 0) return 0;
+ if(value > 127) return 127;
+ return value;
+ }
+
+ private static int restrict14Bit(int value)
+ {
+ if(value < 0) return 0;
+ if(value > 16256) return 16256;
+ return value;
+ }
+
+ public SoftChannel(SoftSynthesizer synth, int channel) {
+ this.channel = channel;
+ this.voices = synth.getVoices();
+ this.synthesizer = synth;
+ this.mainmixer = synth.getMainMixer();
+ control_mutex = synth.control_mutex;
+ resetAllControllers(true);
+ }
+
+ private int findFreeVoice(int x) {
+ for (int i = x; i < voices.length; i++)
+ if (!voices[i].active)
+ return i;
+
+ // No free voice was found, we must steal one
+
+ int vmode = synthesizer.getVoiceAllocationMode();
+ if (vmode == 1) {
+ // DLS Static Voice Allocation
+
+ // * priority ( 10, 1-9, 11-16)
+ // Search for channel to steal from
+ int steal_channel = channel;
+ for (int j = 0; j < voices.length; j++) {
+ if (voices[j].stealer_channel == null) {
+ if (steal_channel == 9) {
+ steal_channel = voices[j].channel;
+ } else {
+ if (voices[j].channel != 9) {
+ if (voices[j].channel > steal_channel)
+ steal_channel = voices[j].channel;
+ }
+ }
+ }
+ }
+
+ int voiceNo = -1;
+
+ SoftVoice v = null;
+ // Search for oldest voice in off state on steal_channel
+ for (int j = 0; j < voices.length; j++) {
+ if (voices[j].channel == steal_channel) {
+ if (voices[j].stealer_channel == null && !voices[j].on) {
+ if (v == null) {
+ v = voices[j];
+ voiceNo = j;
+ }
+ if (voices[j].voiceID < v.voiceID) {
+ v = voices[j];
+ voiceNo = j;
+ }
+ }
+ }
+ }
+ // Search for oldest voice in on state on steal_channel
+ if (voiceNo == -1) {
+ for (int j = 0; j < voices.length; j++) {
+ if (voices[j].channel == steal_channel) {
+ if (voices[j].stealer_channel == null) {
+ if (v == null) {
+ v = voices[j];
+ voiceNo = j;
+ }
+ if (voices[j].voiceID < v.voiceID) {
+ v = voices[j];
+ voiceNo = j;
+ }
+ }
+ }
+ }
+ }
+
+ return voiceNo;
+
+ } else {
+ // Default Voice Allocation
+ // * Find voice that is on
+ // and Find voice which has lowest voiceID ( oldest voice)
+ // * Or find voice that is off
+ // and Find voice which has lowest voiceID ( oldest voice)
+
+ int voiceNo = -1;
+
+ SoftVoice v = null;
+ // Search for oldest voice in off state
+ for (int j = 0; j < voices.length; j++) {
+ if (voices[j].stealer_channel == null && !voices[j].on) {
+ if (v == null) {
+ v = voices[j];
+ voiceNo = j;
+ }
+ if (voices[j].voiceID < v.voiceID) {
+ v = voices[j];
+ voiceNo = j;
+ }
+ }
+ }
+ // Search for oldest voice in on state
+ if (voiceNo == -1) {
+
+ for (int j = 0; j < voices.length; j++) {
+ if (voices[j].stealer_channel == null) {
+ if (v == null) {
+ v = voices[j];
+ voiceNo = j;
+ }
+ if (voices[j].voiceID < v.voiceID) {
+ v = voices[j];
+ voiceNo = j;
+ }
+ }
+ }
+ }
+
+ return voiceNo;
+ }
+
+ }
+
+ protected void initVoice(SoftVoice voice, SoftPerformer p, int voiceID,
+ int noteNumber, int velocity, ModelConnectionBlock[] connectionBlocks,
+ ModelChannelMixer channelmixer, boolean releaseTriggered) {
+ if (voice.active) {
+ // Voice is active , we must steal the voice
+ voice.stealer_channel = this;
+ voice.stealer_performer = p;
+ voice.stealer_voiceID = voiceID;
+ voice.stealer_noteNumber = noteNumber;
+ voice.stealer_velocity = velocity;
+ voice.stealer_extendedConnectionBlocks = connectionBlocks;
+ voice.stealer_channelmixer = channelmixer;
+ voice.stealer_releaseTriggered = releaseTriggered;
+ for (int i = 0; i < voices.length; i++)
+ if (voices[i].active && voices[i].voiceID == voice.voiceID)
+ voices[i].soundOff();
+ return;
+ }
+
+ voice.extendedConnectionBlocks = connectionBlocks;
+ voice.channelmixer = channelmixer;
+ voice.releaseTriggered = releaseTriggered;
+ voice.voiceID = voiceID;
+ voice.tuning = tuning;
+ voice.exclusiveClass = p.exclusiveClass;
+ voice.softchannel = this;
+ voice.channel = channel;
+ voice.bank = bank;
+ voice.program = program;
+ voice.instrument = current_instrument;
+ voice.performer = p;
+ voice.objects.clear();
+ voice.objects.put("midi", co_midi[noteNumber]);
+ voice.objects.put("midi_cc", co_midi_cc);
+ voice.objects.put("midi_rpn", co_midi_rpn);
+ voice.objects.put("midi_nrpn", co_midi_nrpn);
+ voice.noteOn(noteNumber, velocity);
+ voice.setMute(mute);
+ voice.setSoloMute(solomute);
+ if (releaseTriggered)
+ return;
+ if (portamento_control_note != -1) {
+ voice.co_noteon_keynumber[0]
+ = (tuning.getTuning(portamento_control_note) / 100.0)
+ * (1f / 128f);
+ voice.portamento = true;
+ portamento_control_note = -1;
+ } else if (portamento) {
+ if (mono) {
+ if (portamento_lastnote[0] != -1) {
+ voice.co_noteon_keynumber[0]
+ = (tuning.getTuning(portamento_lastnote[0]) / 100.0)
+ * (1f / 128f);
+ voice.portamento = true;
+ portamento_control_note = -1;
+ }
+ portamento_lastnote[0] = noteNumber;
+ } else {
+ if (portamento_lastnote_ix != 0) {
+ portamento_lastnote_ix--;
+ voice.co_noteon_keynumber[0]
+ = (tuning.getTuning(
+ portamento_lastnote[portamento_lastnote_ix])
+ / 100.0)
+ * (1f / 128f);
+ voice.portamento = true;
+ }
+ }
+ }
+ }
+
+ public void noteOn(int noteNumber, int velocity) {
+ noteNumber = restrict7Bit(noteNumber);
+ velocity = restrict7Bit(velocity);
+ noteOn_internal(noteNumber, velocity);
+ if (current_mixer != null)
+ current_mixer.noteOn(noteNumber, velocity);
+ }
+
+ private void noteOn_internal(int noteNumber, int velocity) {
+
+ if (velocity == 0) {
+ noteOff_internal(noteNumber, 64);
+ return;
+ }
+
+ synchronized (control_mutex) {
+ if (sustain) {
+ sustain = false;
+ for (int i = 0; i < voices.length; i++) {
+ if ((voices[i].sustain || voices[i].on)
+ && voices[i].channel == channel && voices[i].active
+ && voices[i].note == noteNumber) {
+ voices[i].sustain = false;
+ voices[i].on = true;
+ voices[i].noteOff(0);
+ }
+ }
+ sustain = true;
+ }
+
+ mainmixer.activity();
+
+ if (mono) {
+ if (portamento) {
+ boolean n_found = false;
+ for (int i = 0; i < voices.length; i++) {
+ if (voices[i].on && voices[i].channel == channel
+ && voices[i].active
+ && voices[i].releaseTriggered == false) {
+ voices[i].portamento = true;
+ voices[i].setNote(noteNumber);
+ n_found = true;
+ }
+ }
+ if (n_found) {
+ portamento_lastnote[0] = noteNumber;
+ return;
+ }
+ }
+
+ if (portamento_control_note != -1) {
+ boolean n_found = false;
+ for (int i = 0; i < voices.length; i++) {
+ if (voices[i].on && voices[i].channel == channel
+ && voices[i].active
+ && voices[i].note == portamento_control_note
+ && voices[i].releaseTriggered == false) {
+ voices[i].portamento = true;
+ voices[i].setNote(noteNumber);
+ n_found = true;
+ }
+ }
+ portamento_control_note = -1;
+ if (n_found)
+ return;
+ }
+ }
+
+ if (mono)
+ allNotesOff();
+
+ if (current_instrument == null) {
+ current_instrument
+ = synthesizer.findInstrument(program, bank, channel);
+ if (current_instrument == null)
+ return;
+ if (current_mixer != null)
+ mainmixer.stopMixer(current_mixer);
+ current_mixer = current_instrument.getSourceInstrument()
+ .getChannelMixer(this, synthesizer.getFormat());
+ if (current_mixer != null)
+ mainmixer.registerMixer(current_mixer);
+ current_director = current_instrument.getDirector(this, this);
+ applyInstrumentCustomization();
+ }
+ prevVoiceID = synthesizer.voiceIDCounter++;
+ firstVoice = true;
+ voiceNo = 0;
+
+ int tunedKey = (int)(Math.round(tuning.getTuning()[noteNumber]/100.0));
+ play_noteNumber = noteNumber;
+ play_velocity = velocity;
+ play_releasetriggered = false;
+ lastVelocity[noteNumber] = velocity;
+ current_director.noteOn(tunedKey, velocity);
+
+ /*
+ SoftPerformer[] performers = current_instrument.getPerformers();
+ for (int i = 0; i < performers.length; i++) {
+ SoftPerformer p = performers[i];
+ if (p.keyFrom <= tunedKey && p.keyTo >= tunedKey) {
+ if (p.velFrom <= velocity && p.velTo >= velocity) {
+ if (firstVoice) {
+ firstVoice = false;
+ if (p.exclusiveClass != 0) {
+ int x = p.exclusiveClass;
+ for (int j = 0; j < voices.length; j++) {
+ if (voices[j].active
+ && voices[j].channel == channel
+ && voices[j].exclusiveClass == x) {
+ if (!(p.selfNonExclusive
+ && voices[j].note == noteNumber))
+ voices[j].shutdown();
+ }
+ }
+ }
+ }
+ voiceNo = findFreeVoice(voiceNo);
+ if (voiceNo == -1)
+ return;
+ initVoice(voices[voiceNo], p, prevVoiceID, noteNumber,
+ velocity);
+ }
+ }
+ }
+ */
+ }
+ }
+
+ public void noteOff(int noteNumber, int velocity) {
+ noteNumber = restrict7Bit(noteNumber);
+ velocity = restrict7Bit(velocity);
+ noteOff_internal(noteNumber, velocity);
+
+ if (current_mixer != null)
+ current_mixer.noteOff(noteNumber, velocity);
+ }
+
+ private void noteOff_internal(int noteNumber, int velocity) {
+ synchronized (control_mutex) {
+
+ if (!mono) {
+ if (portamento) {
+ if (portamento_lastnote_ix != 127) {
+ portamento_lastnote[portamento_lastnote_ix] = noteNumber;
+ portamento_lastnote_ix++;
+ }
+ }
+ }
+
+ mainmixer.activity();
+ for (int i = 0; i < voices.length; i++) {
+ if (voices[i].on && voices[i].channel == channel
+ && voices[i].note == noteNumber
+ && voices[i].releaseTriggered == false) {
+ voices[i].noteOff(velocity);
+ }
+ }
+
+ // Try play back note-off triggered voices,
+
+ if (current_instrument == null) {
+ current_instrument
+ = synthesizer.findInstrument(program, bank, channel);
+ if (current_instrument == null)
+ return;
+ if (current_mixer != null)
+ mainmixer.stopMixer(current_mixer);
+ current_mixer = current_instrument.getSourceInstrument()
+ .getChannelMixer(this, synthesizer.getFormat());
+ if (current_mixer != null)
+ mainmixer.registerMixer(current_mixer);
+ current_director = current_instrument.getDirector(this, this);
+ applyInstrumentCustomization();
+
+ }
+ prevVoiceID = synthesizer.voiceIDCounter++;
+ firstVoice = true;
+ voiceNo = 0;
+
+ int tunedKey = (int)(Math.round(tuning.getTuning()[noteNumber]/100.0));
+ play_noteNumber = noteNumber;
+ play_velocity = lastVelocity[noteNumber];
+ play_releasetriggered = true;
+ current_director.noteOff(tunedKey, velocity);
+
+ }
+ }
+ private int[] lastVelocity = new int[128];
+ private int prevVoiceID;
+ private boolean firstVoice = true;
+ private int voiceNo = 0;
+ private int play_noteNumber = 0;
+ private int play_velocity = 0;
+ private boolean play_releasetriggered = false;
+
+ public void play(int performerIndex, ModelConnectionBlock[] connectionBlocks) {
+
+ int noteNumber = play_noteNumber;
+ int velocity = play_velocity;
+ boolean releasetriggered = play_releasetriggered;
+
+ SoftPerformer p = current_instrument.getPerformers()[performerIndex];
+
+ if (firstVoice) {
+ firstVoice = false;
+ if (p.exclusiveClass != 0) {
+ int x = p.exclusiveClass;
+ for (int j = 0; j < voices.length; j++) {
+ if (voices[j].active && voices[j].channel == channel
+ && voices[j].exclusiveClass == x) {
+ if (!(p.selfNonExclusive && voices[j].note == noteNumber))
+ voices[j].shutdown();
+ }
+ }
+ }
+ }
+
+ voiceNo = findFreeVoice(voiceNo);
+
+ if (voiceNo == -1)
+ return;
+
+ initVoice(voices[voiceNo], p, prevVoiceID, noteNumber, velocity,
+ connectionBlocks, current_mixer, releasetriggered);
+ }
+
+ public void noteOff(int noteNumber) {
+ if(noteNumber < 0 || noteNumber > 127) return;
+ noteOff_internal(noteNumber, 64);
+ }
+
+ public void setPolyPressure(int noteNumber, int pressure) {
+ noteNumber = restrict7Bit(noteNumber);
+ pressure = restrict7Bit(pressure);
+
+ if (current_mixer != null)
+ current_mixer.setPolyPressure(noteNumber, pressure);
+
+ synchronized (control_mutex) {
+ mainmixer.activity();
+ co_midi[noteNumber].get(0, "poly_pressure")[0] = pressure*(1.0/128.0);
+ polypressure[noteNumber] = pressure;
+ for (int i = 0; i < voices.length; i++) {
+ if (voices[i].active && voices[i].note == noteNumber)
+ voices[i].setPolyPressure(pressure);
+ }
+ }
+ }
+
+ public int getPolyPressure(int noteNumber) {
+ synchronized (control_mutex) {
+ return polypressure[noteNumber];
+ }
+ }
+
+ public void setChannelPressure(int pressure) {
+ pressure = restrict7Bit(pressure);
+ if (current_mixer != null)
+ current_mixer.setChannelPressure(pressure);
+ synchronized (control_mutex) {
+ mainmixer.activity();
+ co_midi_channel_pressure[0] = pressure * (1.0 / 128.0);
+ channelpressure = pressure;
+ for (int i = 0; i < voices.length; i++) {
+ if (voices[i].active)
+ voices[i].setChannelPressure(pressure);
+ }
+ }
+ }
+
+ public int getChannelPressure() {
+ synchronized (control_mutex) {
+ return channelpressure;
+ }
+ }
+
+ protected void applyInstrumentCustomization() {
+ if (cds_control_connections == null
+ && cds_channelpressure_connections == null
+ && cds_polypressure_connections == null) {
+ return;
+ }
+
+ ModelInstrument src_instrument = current_instrument.getSourceInstrument();
+ ModelPerformer[] performers = src_instrument.getPerformers();
+ ModelPerformer[] new_performers = new ModelPerformer[performers.length];
+ for (int i = 0; i < new_performers.length; i++) {
+ ModelPerformer performer = performers[i];
+ ModelPerformer new_performer = new ModelPerformer();
+ new_performer.setName(performer.getName());
+ new_performer.setExclusiveClass(performer.getExclusiveClass());
+ new_performer.setKeyFrom(performer.getKeyFrom());
+ new_performer.setKeyTo(performer.getKeyTo());
+ new_performer.setVelFrom(performer.getVelFrom());
+ new_performer.setVelTo(performer.getVelTo());
+ new_performer.getOscillators().addAll(performer.getOscillators());
+ new_performer.getConnectionBlocks().addAll(
+ performer.getConnectionBlocks());
+ new_performers[i] = new_performer;
+
+ List connblocks =
+ new_performer.getConnectionBlocks();
+
+ if (cds_control_connections != null) {
+ String cc = Integer.toString(cds_control_number);
+ Iterator iter = connblocks.iterator();
+ while (iter.hasNext()) {
+ ModelConnectionBlock conn = iter.next();
+ ModelSource[] sources = conn.getSources();
+ boolean removeok = false;
+ if (sources != null) {
+ for (int j = 0; j < sources.length; j++) {
+ ModelSource src = sources[j];
+ if ("midi_cc".equals(src.getIdentifier().getObject())
+ && cc.equals(src.getIdentifier().getVariable())) {
+ removeok = true;
+ }
+ }
+ }
+ if (removeok)
+ iter.remove();
+ }
+ for (int j = 0; j < cds_control_connections.length; j++)
+ connblocks.add(cds_control_connections[j]);
+ }
+
+ if (cds_polypressure_connections != null) {
+ Iterator iter = connblocks.iterator();
+ while (iter.hasNext()) {
+ ModelConnectionBlock conn = iter.next();
+ ModelSource[] sources = conn.getSources();
+ boolean removeok = false;
+ if (sources != null) {
+ for (int j = 0; j < sources.length; j++) {
+ ModelSource src = sources[j];
+ if ("midi".equals(src.getIdentifier().getObject())
+ && "poly_pressure".equals(
+ src.getIdentifier().getVariable())) {
+ removeok = true;
+ }
+ }
+ }
+ if (removeok)
+ iter.remove();
+ }
+ for (int j = 0; j < cds_polypressure_connections.length; j++)
+ connblocks.add(cds_polypressure_connections[j]);
+ }
+
+
+ if (cds_channelpressure_connections != null) {
+ Iterator iter = connblocks.iterator();
+ while (iter.hasNext()) {
+ ModelConnectionBlock conn = iter.next();
+ ModelSource[] sources = conn.getSources();
+ boolean removeok = false;
+ if (sources != null) {
+ for (int j = 0; j < sources.length; j++) {
+ ModelIdentifier srcid = sources[j].getIdentifier();
+ if ("midi".equals(srcid.getObject()) &&
+ "channel_pressure".equals(srcid.getVariable())) {
+ removeok = true;
+ }
+ }
+ }
+ if (removeok)
+ iter.remove();
+ }
+ for (int j = 0; j < cds_channelpressure_connections.length; j++)
+ connblocks.add(cds_channelpressure_connections[j]);
+ }
+
+ }
+
+ current_instrument = new SoftInstrument(src_instrument, new_performers);
+
+ }
+
+ private ModelConnectionBlock[] createModelConnections(ModelIdentifier sid,
+ int[] destination, int[] range) {
+
+ /*
+ controlled parameter (pp)|range (rr)| Description |Default
+ -------------------------|----------|-------------------------|-------
+ 00 Pitch Control | 28H..58H | -24..+24 semitones | 40H
+ 01 Filter Cutoff Control | 00H..7FH | -9600..+9450 cents | 40H
+ 02 Amplitude Control | 00H..7FH | 0..(127/64)*100 percent | 40H
+ 03 LFO Pitch Depth | 00H..7FH | 0..600 cents | 0
+ 04 LFO Filter Depth | 00H..7FH | 0..2400 cents | 0
+ 05 LFO Amplitude Depth | 00H..7FH | 0..100 percent | 0
+ */
+
+ List conns = new ArrayList();
+
+ for (int i = 0; i < destination.length; i++) {
+ int d = destination[i];
+ int r = range[i];
+ if (d == 0) {
+ double scale = (r - 64) * 100;
+ ModelConnectionBlock conn = new ModelConnectionBlock(
+ new ModelSource(sid,
+ ModelStandardTransform.DIRECTION_MIN2MAX,
+ ModelStandardTransform.POLARITY_UNIPOLAR,
+ ModelStandardTransform.TRANSFORM_LINEAR),
+ scale,
+ new ModelDestination(
+ new ModelIdentifier("osc", "pitch")));
+ conns.add(conn);
+
+ }
+ if (d == 1) {
+ double scale = (r / 64.0 - 1.0) * 9600.0;
+ ModelConnectionBlock conn;
+ if (scale > 0) {
+ conn = new ModelConnectionBlock(
+ new ModelSource(sid,
+ ModelStandardTransform.DIRECTION_MAX2MIN,
+ ModelStandardTransform.POLARITY_UNIPOLAR,
+ ModelStandardTransform.TRANSFORM_LINEAR),
+ -scale,
+ new ModelDestination(
+ ModelDestination.DESTINATION_FILTER_FREQ));
+ } else {
+ conn = new ModelConnectionBlock(
+ new ModelSource(sid,
+ ModelStandardTransform.DIRECTION_MIN2MAX,
+ ModelStandardTransform.POLARITY_UNIPOLAR,
+ ModelStandardTransform.TRANSFORM_LINEAR),
+ scale,
+ new ModelDestination(
+ ModelDestination.DESTINATION_FILTER_FREQ));
+ }
+ conns.add(conn);
+ }
+ if (d == 2) {
+ final double scale = (r / 64.0);
+ ModelTransform mt = new ModelTransform() {
+ double s = scale;
+ public double transform(double value) {
+ if (s < 1)
+ value = s + (value * (1.0 - s));
+ else if (s > 1)
+ value = 1 + (value * (s - 1.0));
+ else
+ return 0;
+ return -((5.0 / 12.0) / Math.log(10)) * Math.log(value);
+ }
+ };
+
+ ModelConnectionBlock conn = new ModelConnectionBlock(
+ new ModelSource(sid, mt), -960,
+ new ModelDestination(ModelDestination.DESTINATION_GAIN));
+ conns.add(conn);
+
+ }
+ if (d == 3) {
+ double scale = (r / 64.0 - 1.0) * 9600.0;
+ ModelConnectionBlock conn = new ModelConnectionBlock(
+ new ModelSource(ModelSource.SOURCE_LFO1,
+ ModelStandardTransform.DIRECTION_MIN2MAX,
+ ModelStandardTransform.POLARITY_BIPOLAR,
+ ModelStandardTransform.TRANSFORM_LINEAR),
+ new ModelSource(sid,
+ ModelStandardTransform.DIRECTION_MIN2MAX,
+ ModelStandardTransform.POLARITY_UNIPOLAR,
+ ModelStandardTransform.TRANSFORM_LINEAR),
+ scale,
+ new ModelDestination(
+ ModelDestination.DESTINATION_PITCH));
+ conns.add(conn);
+ }
+ if (d == 4) {
+ double scale = (r / 128.0) * 2400.0;
+ ModelConnectionBlock conn = new ModelConnectionBlock(
+ new ModelSource(ModelSource.SOURCE_LFO1,
+ ModelStandardTransform.DIRECTION_MIN2MAX,
+ ModelStandardTransform.POLARITY_BIPOLAR,
+ ModelStandardTransform.TRANSFORM_LINEAR),
+ new ModelSource(sid,
+ ModelStandardTransform.DIRECTION_MIN2MAX,
+ ModelStandardTransform.POLARITY_UNIPOLAR,
+ ModelStandardTransform.TRANSFORM_LINEAR),
+ scale,
+ new ModelDestination(
+ ModelDestination.DESTINATION_FILTER_FREQ));
+ conns.add(conn);
+ }
+ if (d == 5) {
+ final double scale = (r / 127.0);
+
+ ModelTransform mt = new ModelTransform() {
+ double s = scale;
+ public double transform(double value) {
+ return -((5.0 / 12.0) / Math.log(10))
+ * Math.log(1 - value * s);
+ }
+ };
+
+ ModelConnectionBlock conn = new ModelConnectionBlock(
+ new ModelSource(ModelSource.SOURCE_LFO1,
+ ModelStandardTransform.DIRECTION_MIN2MAX,
+ ModelStandardTransform.POLARITY_UNIPOLAR,
+ ModelStandardTransform.TRANSFORM_LINEAR),
+ new ModelSource(sid, mt),
+ -960,
+ new ModelDestination(
+ ModelDestination.DESTINATION_GAIN));
+ conns.add(conn);
+ }
+ }
+
+ return conns.toArray(new ModelConnectionBlock[conns.size()]);
+ }
+
+ public void mapPolyPressureToDestination(int[] destination, int[] range) {
+ current_instrument = null;
+ if (destination.length == 0) {
+ cds_polypressure_connections = null;
+ return;
+ }
+ cds_polypressure_connections
+ = createModelConnections(
+ new ModelIdentifier("midi", "poly_pressure"),
+ destination, range);
+ }
+
+ public void mapChannelPressureToDestination(int[] destination, int[] range) {
+ current_instrument = null;
+ if (destination.length == 0) {
+ cds_channelpressure_connections = null;
+ return;
+ }
+ cds_channelpressure_connections
+ = createModelConnections(
+ new ModelIdentifier("midi", "channel_pressure"),
+ destination, range);
+ }
+
+ public void mapControlToDestination(int control, int[] destination, int[] range) {
+
+ if (!((control >= 0x01 && control <= 0x1F)
+ || (control >= 0x40 && control <= 0x5F))) {
+ cds_control_connections = null;
+ return;
+ }
+
+ current_instrument = null;
+ cds_control_number = control;
+ if (destination.length == 0) {
+ cds_control_connections = null;
+ return;
+ }
+ cds_control_connections
+ = createModelConnections(
+ new ModelIdentifier("midi_cc", Integer.toString(control)),
+ destination, range);
+ }
+
+ public void controlChangePerNote(int noteNumber, int controller, int value) {
+
+/*
+ CC# | nn | Name | vv | default | description
+-----|------|-------------------------|----------------|------------|-------------------------------
+7 |07H |Note Volume |00H-40H-7FH |40H |0-100-(127/64)*100(%)(Relative)
+10 |0AH |*Pan |00H-7FH absolute|Preset Value|Left-Center-Right (absolute)
+33-63|21-3FH|LSB for |01H-1FH | |
+71 |47H |Timbre/Harmonic Intensity|00H-40H-7FH |40H (???) |
+72 |48H |Release Time |00H-40H-7FH |40H (???) |
+73 |49H |Attack Time |00H-40H-7FH |40H (???) |
+74 |4AH |Brightness |00H-40H-7FH |40H (???) |
+75 |4BH |Decay Time |00H-40H-7FH |40H (???) |
+76 |4CH |Vibrato Rate |00H-40H-7FH |40H (???) |
+77 |4DH |Vibrato Depth |00H-40H-7FH |40H (???) |
+78 |4EH |Vibrato Delay |00H-40H-7FH |40H (???) |
+91 |5BH |*Reverb Send |00H-7FH absolute|Preset Value|Left-Center-Right (absolute)
+93 |5DH |*Chorus Send |00H-7FH absolute|Preset Value|Left-Center-Right (absolute)
+120 |78H |**Fine Tuning |00H-40H-7FH |40H (???) |
+121 |79H |**Coarse Tuning |00H-40H-7FH |40H (???) |
+*/
+
+ if (keybasedcontroller_active == null) {
+ keybasedcontroller_active = new boolean[128][];
+ keybasedcontroller_value = new double[128][];
+ }
+ if (keybasedcontroller_active[noteNumber] == null) {
+ keybasedcontroller_active[noteNumber] = new boolean[128];
+ Arrays.fill(keybasedcontroller_active[noteNumber], false);
+ keybasedcontroller_value[noteNumber] = new double[128];
+ Arrays.fill(keybasedcontroller_value[noteNumber], 0);
+ }
+
+ if (value == -1) {
+ keybasedcontroller_active[noteNumber][controller] = false;
+ } else {
+ keybasedcontroller_active[noteNumber][controller] = true;
+ keybasedcontroller_value[noteNumber][controller] = value / 128.0;
+ }
+
+ if (controller < 120) {
+ for (int i = 0; i < voices.length; i++)
+ if (voices[i].active)
+ voices[i].controlChange(controller, -1);
+ } else if (controller == 120) {
+ for (int i = 0; i < voices.length; i++)
+ if (voices[i].active)
+ voices[i].rpnChange(1, -1);
+ } else if (controller == 121) {
+ for (int i = 0; i < voices.length; i++)
+ if (voices[i].active)
+ voices[i].rpnChange(2, -1);
+ }
+
+ }
+
+ public int getControlPerNote(int noteNumber, int controller) {
+ if (keybasedcontroller_active == null)
+ return -1;
+ if (keybasedcontroller_active[noteNumber] == null)
+ return -1;
+ if (!keybasedcontroller_active[noteNumber][controller])
+ return -1;
+ return (int)(keybasedcontroller_value[noteNumber][controller] * 128);
+ }
+
+ public void controlChange(int controller, int value) {
+ controller = restrict7Bit(controller);
+ value = restrict7Bit(value);
+ if (current_mixer != null)
+ current_mixer.controlChange(controller, value);
+
+ synchronized (control_mutex) {
+ switch (controller) {
+ /*
+ Mapco_midi_rpn_rpn_i = new HashMap();
+ Mapco_midi_rpn_rpn = new HashMap();
+ Mapco_midi_nrpn_nrpn_i = new HashMap();
+ Mapco_midi_nrpn_nrpn = new HashMap();
+ */
+
+ case 5:
+ // This produce asin-like curve
+ // as described in General Midi Level 2 Specification, page 6
+ double x = -Math.asin((value / 128.0) * 2 - 1) / Math.PI + 0.5;
+ x = Math.pow(100000.0, x) / 100.0; // x is now cent/msec
+ // Convert x from cent/msec to key/controlbuffertime
+ x = x / 100.0; // x is now keys/msec
+ x = x * 1000.0; // x is now keys/sec
+ x = x / synthesizer.getControlRate(); // x is now keys/controlbuffertime
+ portamento_time = x;
+ break;
+ case 6:
+ case 38:
+ case 96:
+ case 97:
+ int val = 0;
+ if (nrpn_control != RPN_NULL_VALUE) {
+ int[] val_i = co_midi_nrpn_nrpn_i.get(nrpn_control);
+ if (val_i != null)
+ val = val_i[0];
+ }
+ if (rpn_control != RPN_NULL_VALUE) {
+ int[] val_i = co_midi_rpn_rpn_i.get(rpn_control);
+ if (val_i != null)
+ val = val_i[0];
+ }
+
+ if (controller == 6)
+ val = (val & 127) + (value << 7);
+ else if (controller == 38)
+ val = (val & (127 << 7)) + value;
+ else if (controller == 96 || controller == 97) {
+ int step = 1;
+ if (rpn_control == 2 || rpn_control == 3 || rpn_control == 4)
+ step = 128;
+ if (controller == 96)
+ val += step;
+ if (controller == 97)
+ val -= step;
+ }
+
+ if (nrpn_control != RPN_NULL_VALUE)
+ nrpnChange(nrpn_control, val);
+ if (rpn_control != RPN_NULL_VALUE)
+ rpnChange(rpn_control, val);
+
+ break;
+ case 64: // Hold1 (Damper) (cc#64)
+ boolean on = value >= 64;
+ if (sustain != on) {
+ sustain = on;
+ if (!on) {
+ for (int i = 0; i < voices.length; i++) {
+ if (voices[i].active && voices[i].sustain &&
+ voices[i].channel == channel) {
+ voices[i].sustain = false;
+ if (!voices[i].on) {
+ voices[i].on = true;
+ voices[i].noteOff(0);
+ }
+ }
+ }
+ } else {
+ for (int i = 0; i < voices.length; i++)
+ if (voices[i].active && voices[i].channel == channel)
+ voices[i].redamp();
+ }
+ }
+ break;
+ case 65:
+ //allNotesOff();
+ portamento = value >= 64;
+ portamento_lastnote[0] = -1;
+ /*
+ for (int i = 0; i < portamento_lastnote.length; i++)
+ portamento_lastnote[i] = -1;
+ */
+ portamento_lastnote_ix = 0;
+ break;
+ case 66: // Sostenuto (cc#66)
+ on = value >= 64;
+ if (on) {
+ for (int i = 0; i < voices.length; i++) {
+ if (voices[i].active && voices[i].on &&
+ voices[i].channel == channel) {
+ voices[i].sostenuto = true;
+ }
+ }
+ }
+ if (!on) {
+ for (int i = 0; i < voices.length; i++) {
+ if (voices[i].active && voices[i].sostenuto &&
+ voices[i].channel == channel) {
+ voices[i].sostenuto = false;
+ if (!voices[i].on) {
+ voices[i].on = true;
+ voices[i].noteOff(0);
+ }
+ }
+ }
+ }
+ break;
+ case 84:
+ portamento_control_note = value;
+ break;
+ case 98:
+ nrpn_control = (nrpn_control & (127 << 7)) + value;
+ rpn_control = RPN_NULL_VALUE;
+ break;
+ case 99:
+ nrpn_control = (nrpn_control & 127) + (value << 7);
+ rpn_control = RPN_NULL_VALUE;
+ break;
+ case 100:
+ rpn_control = (rpn_control & (127 << 7)) + value;
+ nrpn_control = RPN_NULL_VALUE;
+ break;
+ case 101:
+ rpn_control = (rpn_control & 127) + (value << 7);
+ nrpn_control = RPN_NULL_VALUE;
+ break;
+ case 120:
+ allSoundOff();
+ break;
+ case 121:
+ resetAllControllers(value == 127);
+ break;
+ case 122:
+ localControl(value >= 64);
+ break;
+ case 123:
+ allNotesOff();
+ break;
+ case 124:
+ setOmni(false);
+ break;
+ case 125:
+ setOmni(true);
+ break;
+ case 126:
+ if (value == 1)
+ setMono(true);
+ break;
+ case 127:
+ setMono(false);
+ break;
+
+ default:
+ break;
+ }
+
+ co_midi_cc_cc[controller][0] = value * (1.0 / 128.0);
+
+ if (controller == 0x00) {
+ bank = /*(bank & 127) +*/ (value << 7);
+ return;
+ }
+
+ if (controller == 0x20) {
+ bank = (bank & (127 << 7)) + value;
+ return;
+ }
+
+ this.controller[controller] = value;
+ if(controller < 0x20)
+ this.controller[controller + 0x20] = 0;
+
+ for (int i = 0; i < voices.length; i++)
+ if (voices[i].active)
+ voices[i].controlChange(controller, value);
+
+ }
+ }
+
+ public int getController(int controller) {
+ synchronized (control_mutex) {
+ // Should only return lower 7 bits,
+ // even when controller is "boosted" higher.
+ return this.controller[controller] & 127;
+ }
+ }
+
+ public void tuningChange(int program) {
+ tuningChange(0, program);
+ }
+
+ public void tuningChange(int bank, int program) {
+ synchronized (control_mutex) {
+ tuning = synthesizer.getTuning(new Patch(bank, program));
+ }
+ }
+
+ public void programChange(int program) {
+ programChange(bank, program);
+ }
+
+ public void programChange(int bank, int program) {
+ bank = restrict7Bit(bank);
+ program = restrict7Bit(program);
+ synchronized (control_mutex) {
+ mainmixer.activity();
+ this.bank = bank;
+ this.program = program;
+ current_instrument = null;
+ }
+ }
+
+ public int getProgram() {
+ synchronized (control_mutex) {
+ return program;
+ }
+ }
+
+ public void setPitchBend(int bend) {
+ bend = restrict14Bit(bend);
+ if (current_mixer != null)
+ current_mixer.setPitchBend(bend);
+ synchronized (control_mutex) {
+ mainmixer.activity();
+ co_midi_pitch[0] = bend * (1.0 / 16384.0);
+ pitchbend = bend;
+ for (int i = 0; i < voices.length; i++)
+ if (voices[i].active)
+ voices[i].setPitchBend(bend);
+ }
+ }
+
+ public int getPitchBend() {
+ synchronized (control_mutex) {
+ return pitchbend;
+ }
+ }
+
+ public void nrpnChange(int controller, int value) {
+
+ /*
+ System.out.println("(" + channel + ").nrpnChange("
+ + Integer.toHexString(controller >> 7)
+ + " " + Integer.toHexString(controller & 127)
+ + ", " + Integer.toHexString(value >> 7)
+ + " " + Integer.toHexString(value & 127) + ")");
+ */
+
+ if (synthesizer.getGeneralMidiMode() == 0) {
+ if (controller == (0x01 << 7) + (0x08)) // Vibrato Rate
+ controlChange(76, value >> 7);
+ if (controller == (0x01 << 7) + (0x09)) // Vibrato Depth
+ controlChange(77, value >> 7);
+ if (controller == (0x01 << 7) + (0x0A)) // Vibrato Delay
+ controlChange(78, value >> 7);
+ if (controller == (0x01 << 7) + (0x20)) // Brightness
+ controlChange(74, value >> 7);
+ if (controller == (0x01 << 7) + (0x21)) // Filter Resonance
+ controlChange(71, value >> 7);
+ if (controller == (0x01 << 7) + (0x63)) // Attack Time
+ controlChange(73, value >> 7);
+ if (controller == (0x01 << 7) + (0x64)) // Decay Time
+ controlChange(75, value >> 7);
+ if (controller == (0x01 << 7) + (0x66)) // Release Time
+ controlChange(72, value >> 7);
+
+ if (controller >> 7 == 0x18) // Pitch coarse
+ controlChangePerNote(controller % 128, 120, value >> 7);
+ if (controller >> 7 == 0x1A) // Volume
+ controlChangePerNote(controller % 128, 7, value >> 7);
+ if (controller >> 7 == 0x1C) // Panpot
+ controlChangePerNote(controller % 128, 10, value >> 7);
+ if (controller >> 7 == 0x1D) // Reverb
+ controlChangePerNote(controller % 128, 91, value >> 7);
+ if (controller >> 7 == 0x1E) // Chorus
+ controlChangePerNote(controller % 128, 93, value >> 7);
+ }
+
+ int[] val_i = co_midi_nrpn_nrpn_i.get(controller);
+ double[] val_d = co_midi_nrpn_nrpn.get(controller);
+ if (val_i == null) {
+ val_i = new int[1];
+ co_midi_nrpn_nrpn_i.put(controller, val_i);
+ }
+ if (val_d == null) {
+ val_d = new double[1];
+ co_midi_nrpn_nrpn.put(controller, val_d);
+ }
+ val_i[0] = value;
+ val_d[0] = val_i[0] * (1.0 / 16384.0);
+
+ for (int i = 0; i < voices.length; i++)
+ if (voices[i].active)
+ voices[i].nrpnChange(controller, val_i[0]);
+
+ }
+
+ public void rpnChange(int controller, int value) {
+
+ /*
+ System.out.println("(" + channel + ").rpnChange("
+ + Integer.toHexString(controller >> 7)
+ + " " + Integer.toHexString(controller & 127)
+ + ", " + Integer.toHexString(value >> 7)
+ + " " + Integer.toHexString(value & 127) + ")");
+ */
+
+ if (controller == 3) {
+ tuning_program = (value >> 7) & 127;
+ tuningChange(tuning_bank, tuning_program);
+ }
+ if (controller == 4) {
+ tuning_bank = (value >> 7) & 127;
+ }
+
+ int[] val_i = co_midi_rpn_rpn_i.get(controller);
+ double[] val_d = co_midi_rpn_rpn.get(controller);
+ if (val_i == null) {
+ val_i = new int[1];
+ co_midi_rpn_rpn_i.put(controller, val_i);
+ }
+ if (val_d == null) {
+ val_d = new double[1];
+ co_midi_rpn_rpn.put(controller, val_d);
+ }
+ val_i[0] = value;
+ val_d[0] = val_i[0] * (1.0 / 16384.0);
+
+ for (int i = 0; i < voices.length; i++)
+ if (voices[i].active)
+ voices[i].rpnChange(controller, val_i[0]);
+ }
+
+ public void resetAllControllers() {
+ resetAllControllers(false);
+ }
+
+ public void resetAllControllers(boolean allControls) {
+ synchronized (control_mutex) {
+ mainmixer.activity();
+
+ for (int i = 0; i < 128; i++) {
+ setPolyPressure(i, 0);
+ }
+ setChannelPressure(0);
+ setPitchBend(8192);
+ for (int i = 0; i < 128; i++) {
+ if (!dontResetControls[i])
+ controlChange(i, 0);
+ }
+
+ controlChange(71, 64); // Filter Resonance
+ controlChange(72, 64); // Release Time
+ controlChange(73, 64); // Attack Time
+ controlChange(74, 64); // Brightness
+ controlChange(75, 64); // Decay Time
+ controlChange(76, 64); // Vibrato Rate
+ controlChange(77, 64); // Vibrato Depth
+ controlChange(78, 64); // Vibrato Delay
+
+ controlChange(8, 64); // Balance
+ controlChange(11, 127); // Expression
+ controlChange(98, 127); // NRPN Null
+ controlChange(99, 127); // NRPN Null
+ controlChange(100, 127); // RPN = Null
+ controlChange(101, 127); // RPN = Null
+
+ // see DLS 2.1 (Power-on Default Values)
+ if (allControls) {
+
+ keybasedcontroller_active = null;
+ keybasedcontroller_value = null;
+
+ controlChange(7, 100); // Volume
+ controlChange(10, 64); // Pan
+ controlChange(91, 40); // Reverb
+
+ for (int controller : co_midi_rpn_rpn.keySet()) {
+ // don't reset tuning settings
+ if (controller != 3 && controller != 4)
+ rpnChange(controller, 0);
+ }
+ for (int controller : co_midi_nrpn_nrpn.keySet())
+ nrpnChange(controller, 0);
+ rpnChange(0, 2 << 7); // Bitch Bend sensitivity
+ rpnChange(1, 64 << 7); // Channel fine tunning
+ rpnChange(2, 64 << 7); // Channel Coarse Tuning
+ rpnChange(5, 64); // Modulation Depth, +/- 50 cent
+
+ tuning_bank = 0;
+ tuning_program = 0;
+ tuning = new SoftTuning();
+
+ }
+
+ }
+ }
+
+ public void allNotesOff() {
+ if (current_mixer != null)
+ current_mixer.allNotesOff();
+ synchronized (control_mutex) {
+ for (int i = 0; i < voices.length; i++)
+ if (voices[i].on && voices[i].channel == channel
+ && voices[i].releaseTriggered == false) {
+ voices[i].noteOff(0);
+ }
+ }
+ }
+
+ public void allSoundOff() {
+ if (current_mixer != null)
+ current_mixer.allSoundOff();
+ synchronized (control_mutex) {
+ for (int i = 0; i < voices.length; i++)
+ if (voices[i].on && voices[i].channel == channel)
+ voices[i].soundOff();
+ }
+ }
+
+ public boolean localControl(boolean on) {
+ return false;
+ }
+
+ public void setMono(boolean on) {
+ if (current_mixer != null)
+ current_mixer.setMono(on);
+ synchronized (control_mutex) {
+ allNotesOff();
+ mono = on;
+ }
+ }
+
+ public boolean getMono() {
+ synchronized (control_mutex) {
+ return mono;
+ }
+ }
+
+ public void setOmni(boolean on) {
+ if (current_mixer != null)
+ current_mixer.setOmni(on);
+ allNotesOff();
+ // Omni is not supported by GM2
+ }
+
+ public boolean getOmni() {
+ return false;
+ }
+
+ public void setMute(boolean mute) {
+ if (current_mixer != null)
+ current_mixer.setMute(mute);
+ synchronized (control_mutex) {
+ this.mute = mute;
+ for (int i = 0; i < voices.length; i++)
+ if (voices[i].active && voices[i].channel == channel)
+ voices[i].setMute(mute);
+ }
+ }
+
+ public boolean getMute() {
+ synchronized (control_mutex) {
+ return mute;
+ }
+ }
+
+ public void setSolo(boolean soloState) {
+ if (current_mixer != null)
+ current_mixer.setSolo(soloState);
+
+ synchronized (control_mutex) {
+ this.solo = soloState;
+
+ boolean soloinuse = false;
+ for (SoftChannel c : synthesizer.channels) {
+ if (c.solo) {
+ soloinuse = true;
+ break;
+ }
+ }
+
+ if (!soloinuse) {
+ for (SoftChannel c : synthesizer.channels)
+ c.setSoloMute(false);
+ return;
+ }
+
+ for (SoftChannel c : synthesizer.channels)
+ c.setSoloMute(!c.solo);
+
+ }
+
+ }
+
+ private void setSoloMute(boolean mute) {
+ synchronized (control_mutex) {
+ if (solomute == mute)
+ return;
+ this.solomute = mute;
+ for (int i = 0; i < voices.length; i++)
+ if (voices[i].active && voices[i].channel == channel)
+ voices[i].setSoloMute(solomute);
+ }
+ }
+
+ public boolean getSolo() {
+ synchronized (control_mutex) {
+ return solo;
+ }
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SoftChannelProxy.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SoftChannelProxy.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,202 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.media.sound;
+
+import javax.sound.midi.MidiChannel;
+
+/**
+ * A MidiChannel proxy object used for external access to synthesizer internal
+ * channel objects.
+ *
+ * @author Karl Helgason
+ */
+public class SoftChannelProxy implements MidiChannel {
+
+ private MidiChannel channel = null;
+
+ public MidiChannel getChannel() {
+ return channel;
+ }
+
+ public void setChannel(MidiChannel channel) {
+ this.channel = channel;
+ }
+
+ public void allNotesOff() {
+ if (channel == null)
+ return;
+ channel.allNotesOff();
+ }
+
+ public void allSoundOff() {
+ if (channel == null)
+ return;
+ channel.allSoundOff();
+ }
+
+ public void controlChange(int controller, int value) {
+ if (channel == null)
+ return;
+ channel.controlChange(controller, value);
+ }
+
+ public int getChannelPressure() {
+ if (channel == null)
+ return 0;
+ return channel.getChannelPressure();
+ }
+
+ public int getController(int controller) {
+ if (channel == null)
+ return 0;
+ return channel.getController(controller);
+ }
+
+ public boolean getMono() {
+ if (channel == null)
+ return false;
+ return channel.getMono();
+ }
+
+ public boolean getMute() {
+ if (channel == null)
+ return false;
+ return channel.getMute();
+ }
+
+ public boolean getOmni() {
+ if (channel == null)
+ return false;
+ return channel.getOmni();
+ }
+
+ public int getPitchBend() {
+ if (channel == null)
+ return 8192;
+ return channel.getPitchBend();
+ }
+
+ public int getPolyPressure(int noteNumber) {
+ if (channel == null)
+ return 0;
+ return channel.getPolyPressure(noteNumber);
+ }
+
+ public int getProgram() {
+ if (channel == null)
+ return 0;
+ return channel.getProgram();
+ }
+
+ public boolean getSolo() {
+ if (channel == null)
+ return false;
+ return channel.getSolo();
+ }
+
+ public boolean localControl(boolean on) {
+ if (channel == null)
+ return false;
+ return channel.localControl(on);
+ }
+
+ public void noteOff(int noteNumber) {
+ if (channel == null)
+ return;
+ channel.noteOff(noteNumber);
+ }
+
+ public void noteOff(int noteNumber, int velocity) {
+ if (channel == null)
+ return;
+ channel.noteOff(noteNumber, velocity);
+ }
+
+ public void noteOn(int noteNumber, int velocity) {
+ if (channel == null)
+ return;
+ channel.noteOn(noteNumber, velocity);
+ }
+
+ public void programChange(int program) {
+ if (channel == null)
+ return;
+ channel.programChange(program);
+ }
+
+ public void programChange(int bank, int program) {
+ if (channel == null)
+ return;
+ channel.programChange(bank, program);
+ }
+
+ public void resetAllControllers() {
+ if (channel == null)
+ return;
+ channel.resetAllControllers();
+ }
+
+ public void setChannelPressure(int pressure) {
+ if (channel == null)
+ return;
+ channel.setChannelPressure(pressure);
+ }
+
+ public void setMono(boolean on) {
+ if (channel == null)
+ return;
+ channel.setMono(on);
+ }
+
+ public void setMute(boolean mute) {
+ if (channel == null)
+ return;
+ channel.setMute(mute);
+ }
+
+ public void setOmni(boolean on) {
+ if (channel == null)
+ return;
+ channel.setOmni(on);
+ }
+
+ public void setPitchBend(int bend) {
+ if (channel == null)
+ return;
+ channel.setPitchBend(bend);
+ }
+
+ public void setPolyPressure(int noteNumber, int pressure) {
+ if (channel == null)
+ return;
+ channel.setPolyPressure(noteNumber, pressure);
+ }
+
+ public void setSolo(boolean soloState) {
+ if (channel == null)
+ return;
+ channel.setSolo(soloState);
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SoftChorus.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SoftChorus.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,341 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.media.sound;
+
+import java.util.Arrays;
+
+/**
+ * A chorus effect made using LFO and variable delay. One for each channel
+ * (left,right), with different starting phase for stereo effect.
+ *
+ * @author Karl Helgason
+ */
+public class SoftChorus implements SoftAudioProcessor {
+
+ private static class VariableDelay {
+
+ private float[] delaybuffer;
+ private int rovepos = 0;
+ private volatile float gain = 1;
+ private volatile float rgain = 0;
+ private volatile float delay = 0;
+ private float lastdelay = 0;
+ private volatile float feedback = 0;
+
+ public VariableDelay(int maxbuffersize) {
+ delaybuffer = new float[maxbuffersize];
+ }
+
+ public void setDelay(float delay) {
+ this.delay = delay;
+ }
+
+ public void setFeedBack(float feedback) {
+ this.feedback = feedback;
+ }
+
+ public void setGain(float gain) {
+ this.gain = gain;
+ }
+
+ public void setReverbSendGain(float rgain) {
+ this.rgain = rgain;
+ }
+
+ public void processMix(float[] in, float[] out, float[] rout) {
+ float gain = this.gain;
+ float delay = this.delay;
+ float feedback = this.feedback;
+
+ float[] delaybuffer = this.delaybuffer;
+ int len = in.length;
+ float delaydelta = (delay - lastdelay) / len;
+ int rnlen = delaybuffer.length;
+ int rovepos = this.rovepos;
+
+ if (rout == null)
+ for (int i = 0; i < len; i++) {
+ float r = rovepos - (lastdelay + 2) + rnlen;
+ int ri = (int) r;
+ float s = r - ri;
+ float a = delaybuffer[ri % rnlen];
+ float b = delaybuffer[(ri + 1) % rnlen];
+ float o = a * (1 - s) + b * (s);
+ out[i] += o * gain;
+ delaybuffer[rovepos] = in[i] + o * feedback;
+ rovepos = (rovepos + 1) % rnlen;
+ lastdelay += delaydelta;
+ }
+ else
+ for (int i = 0; i < len; i++) {
+ float r = rovepos - (lastdelay + 2) + rnlen;
+ int ri = (int) r;
+ float s = r - ri;
+ float a = delaybuffer[ri % rnlen];
+ float b = delaybuffer[(ri + 1) % rnlen];
+ float o = a * (1 - s) + b * (s);
+ out[i] += o * gain;
+ rout[i] += o * rgain;
+ delaybuffer[rovepos] = in[i] + o * feedback;
+ rovepos = (rovepos + 1) % rnlen;
+ lastdelay += delaydelta;
+ }
+ this.rovepos = rovepos;
+ lastdelay = delay;
+ }
+
+ public void processReplace(float[] in, float[] out, float[] rout) {
+ Arrays.fill(out, 0);
+ Arrays.fill(rout, 0);
+ processMix(in, out, rout);
+ }
+ }
+
+ private static class LFODelay {
+
+ private volatile double c_cos_delta;
+ private volatile double c_sin_delta;
+ private double c_cos = 1;
+ private double c_sin = 0;
+ private double depth = 0;
+ private VariableDelay vdelay;
+ private double samplerate;
+ private double controlrate;
+
+ public LFODelay(double samplerate, double controlrate) {
+ this.samplerate = samplerate;
+ this.controlrate = controlrate;
+ // vdelay = new VariableDelay((int)(samplerate*4));
+ vdelay = new VariableDelay((int) ((this.depth + 10) * 2));
+
+ }
+
+ public void setDepth(double depth) {
+ this.depth = depth * samplerate;
+ vdelay = new VariableDelay((int) ((this.depth + 10) * 2));
+ }
+
+ public void setRate(double rate) {
+ double g = (Math.PI * 2) * (rate / controlrate);
+ c_cos_delta = Math.cos(g);
+ c_sin_delta = Math.sin(g);
+ }
+
+ public void setPhase(double phase) {
+ c_cos = Math.cos(phase);
+ c_sin = Math.sin(phase);
+ }
+
+ public void setFeedBack(float feedback) {
+ vdelay.setFeedBack(feedback);
+ }
+
+ public void setGain(float gain) {
+ vdelay.setGain(gain);
+ }
+
+ public void setReverbSendGain(float rgain) {
+ vdelay.setReverbSendGain(rgain);
+ }
+
+ public void processMix(float[] in, float[] out, float[] rout) {
+ c_cos = c_cos * c_cos_delta - c_sin * c_sin_delta;
+ c_sin = c_cos * c_sin_delta + c_sin * c_cos_delta;
+ vdelay.setDelay((float) (depth * 0.5 * (c_cos + 2)));
+ vdelay.processMix(in, out, rout);
+ }
+
+ public void processReplace(float[] in, float[] out, float[] rout) {
+ c_cos = c_cos * c_cos_delta - c_sin * c_sin_delta;
+ c_sin = c_cos * c_sin_delta + c_sin * c_cos_delta;
+ vdelay.setDelay((float) (depth * 0.5 * (c_cos + 2)));
+ vdelay.processReplace(in, out, rout);
+
+ }
+ }
+ private boolean mix = true;
+ private SoftAudioBuffer inputA;
+ private SoftAudioBuffer left;
+ private SoftAudioBuffer right;
+ private SoftAudioBuffer reverb;
+ private LFODelay vdelay1L;
+ private LFODelay vdelay1R;
+ private float rgain = 0;
+ private boolean dirty = true;
+ private double dirty_vdelay1L_rate;
+ private double dirty_vdelay1R_rate;
+ private double dirty_vdelay1L_depth;
+ private double dirty_vdelay1R_depth;
+ private float dirty_vdelay1L_feedback;
+ private float dirty_vdelay1R_feedback;
+ private float dirty_vdelay1L_reverbsendgain;
+ private float dirty_vdelay1R_reverbsendgain;
+ private float controlrate;
+
+ public void init(float samplerate, float controlrate) {
+ this.controlrate = controlrate;
+ vdelay1L = new LFODelay(samplerate, controlrate);
+ vdelay1R = new LFODelay(samplerate, controlrate);
+ vdelay1L.setGain(1.0f); // %
+ vdelay1R.setGain(1.0f); // %
+ vdelay1L.setPhase(0.5 * Math.PI);
+ vdelay1R.setPhase(0);
+
+ globalParameterControlChange(new int[]{0x01 * 128 + 0x02}, 0, 2);
+ }
+
+ public void globalParameterControlChange(int[] slothpath, long param,
+ long value) {
+ if (slothpath.length == 1) {
+ if (slothpath[0] == 0x01 * 128 + 0x02) {
+ if (param == 0) { // Chorus Type
+ switch ((int)value) {
+ case 0: // Chorus 1 0 (0%) 3 (0.4Hz) 5 (1.9ms) 0 (0%)
+ globalParameterControlChange(slothpath, 3, 0);
+ globalParameterControlChange(slothpath, 1, 3);
+ globalParameterControlChange(slothpath, 2, 5);
+ globalParameterControlChange(slothpath, 4, 0);
+ break;
+ case 1: // Chorus 2 5 (4%) 9 (1.1Hz) 19 (6.3ms) 0 (0%)
+ globalParameterControlChange(slothpath, 3, 5);
+ globalParameterControlChange(slothpath, 1, 9);
+ globalParameterControlChange(slothpath, 2, 19);
+ globalParameterControlChange(slothpath, 4, 0);
+ break;
+ case 2: // Chorus 3 8 (6%) 3 (0.4Hz) 19 (6.3ms) 0 (0%)
+ globalParameterControlChange(slothpath, 3, 8);
+ globalParameterControlChange(slothpath, 1, 3);
+ globalParameterControlChange(slothpath, 2, 19);
+ globalParameterControlChange(slothpath, 4, 0);
+ break;
+ case 3: // Chorus 4 16 (12%) 9 (1.1Hz) 16 (5.3ms) 0 (0%)
+ globalParameterControlChange(slothpath, 3, 16);
+ globalParameterControlChange(slothpath, 1, 9);
+ globalParameterControlChange(slothpath, 2, 16);
+ globalParameterControlChange(slothpath, 4, 0);
+ break;
+ case 4: // FB Chorus 64 (49%) 2 (0.2Hz) 24 (7.8ms) 0 (0%)
+ globalParameterControlChange(slothpath, 3, 64);
+ globalParameterControlChange(slothpath, 1, 2);
+ globalParameterControlChange(slothpath, 2, 24);
+ globalParameterControlChange(slothpath, 4, 0);
+ break;
+ case 5: // Flanger 112 (86%) 1 (0.1Hz) 5 (1.9ms) 0 (0%)
+ globalParameterControlChange(slothpath, 3, 112);
+ globalParameterControlChange(slothpath, 1, 1);
+ globalParameterControlChange(slothpath, 2, 5);
+ globalParameterControlChange(slothpath, 4, 0);
+ break;
+ default:
+ break;
+ }
+ } else if (param == 1) { // Mod Rate
+ dirty_vdelay1L_rate = (value * 0.122);
+ dirty_vdelay1R_rate = (value * 0.122);
+ dirty = true;
+ } else if (param == 2) { // Mod Depth
+ dirty_vdelay1L_depth = ((value + 1) / 3200.0);
+ dirty_vdelay1R_depth = ((value + 1) / 3200.0);
+ dirty = true;
+ } else if (param == 3) { // Feedback
+ dirty_vdelay1L_feedback = (value * 0.00763f);
+ dirty_vdelay1R_feedback = (value * 0.00763f);
+ dirty = true;
+ }
+ if (param == 4) { // Send to Reverb
+ rgain = value * 0.00787f;
+ dirty_vdelay1L_reverbsendgain = (value * 0.00787f);
+ dirty_vdelay1R_reverbsendgain = (value * 0.00787f);
+ dirty = true;
+ }
+
+ }
+ }
+ }
+
+ public void processControlLogic() {
+ if (dirty) {
+ dirty = false;
+ vdelay1L.setRate(dirty_vdelay1L_rate);
+ vdelay1R.setRate(dirty_vdelay1R_rate);
+ vdelay1L.setDepth(dirty_vdelay1L_depth);
+ vdelay1R.setDepth(dirty_vdelay1R_depth);
+ vdelay1L.setFeedBack(dirty_vdelay1L_feedback);
+ vdelay1R.setFeedBack(dirty_vdelay1R_feedback);
+ vdelay1L.setReverbSendGain(dirty_vdelay1L_reverbsendgain);
+ vdelay1R.setReverbSendGain(dirty_vdelay1R_reverbsendgain);
+ }
+ }
+ double silentcounter = 1000;
+
+ public void processAudio() {
+
+ if (inputA.isSilent()) {
+ silentcounter += 1 / controlrate;
+
+ if (silentcounter > 1) {
+ if (!mix) {
+ left.clear();
+ right.clear();
+ }
+ return;
+ }
+ } else
+ silentcounter = 0;
+
+ float[] inputA = this.inputA.array();
+ float[] left = this.left.array();
+ float[] right = this.right == null ? null : this.right.array();
+ float[] reverb = rgain != 0 ? this.reverb.array() : null;
+
+ if (mix) {
+ vdelay1L.processMix(inputA, left, reverb);
+ if (right != null)
+ vdelay1R.processMix(inputA, right, reverb);
+ } else {
+ vdelay1L.processReplace(inputA, left, reverb);
+ if (right != null)
+ vdelay1R.processReplace(inputA, right, reverb);
+ }
+ }
+
+ public void setInput(int pin, SoftAudioBuffer input) {
+ if (pin == 0)
+ inputA = input;
+ }
+
+ public void setMixMode(boolean mix) {
+ this.mix = mix;
+ }
+
+ public void setOutput(int pin, SoftAudioBuffer output) {
+ if (pin == 0)
+ left = output;
+ if (pin == 1)
+ right = output;
+ if (pin == 2)
+ reverb = output;
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SoftControl.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SoftControl.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.media.sound;
+
+/**
+ * SoftControl
are the basic controls
+ * used for control-rate processing.
+ *
+ * @author Karl Helgason
+ */
+public interface SoftControl {
+
+ public double[] get(int instance, String name);
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SoftCubicResampler.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SoftCubicResampler.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.media.sound;
+
+/**
+ * A resampler that uses third-order (cubic) interpolation.
+ *
+ * @author Karl Helgason
+ */
+public class SoftCubicResampler extends SoftAbstractResampler {
+
+ public int getPadding() {
+ return 3;
+ }
+
+ public void interpolate(float[] in, float[] in_offset, float in_end,
+ float[] startpitch, float pitchstep, float[] out, int[] out_offset,
+ int out_end) {
+ float pitch = startpitch[0];
+ float ix = in_offset[0];
+ int ox = out_offset[0];
+ float ix_end = in_end;
+ int ox_end = out_end;
+ if (pitchstep == 0) {
+ while (ix < ix_end && ox < ox_end) {
+ int iix = (int) ix;
+ float fix = ix - iix;
+ float y0 = in[iix - 1];
+ float y1 = in[iix];
+ float y2 = in[iix + 1];
+ float y3 = in[iix + 2];
+ float a0 = y3 - y2 + y1 - y0;
+ float a1 = y0 - y1 - a0;
+ float a2 = y2 - y0;
+ float a3 = y1;
+ //float fix2 = fix * fix;
+ //out[ox++] = (a0 * fix + a1) * fix2 + (a2 * fix + a3);
+ out[ox++] = ((a0 * fix + a1) * fix + a2) * fix + a3;
+ ix += pitch;
+ }
+ } else {
+ while (ix < ix_end && ox < ox_end) {
+ int iix = (int) ix;
+ float fix = ix - iix;
+ float y0 = in[iix - 1];
+ float y1 = in[iix];
+ float y2 = in[iix + 1];
+ float y3 = in[iix + 2];
+ float a0 = y3 - y2 + y1 - y0;
+ float a1 = y0 - y1 - a0;
+ float a2 = y2 - y0;
+ float a3 = y1;
+ //float fix2 = fix * fix;
+ //out[ox++] = (a0 * fix + a1) * fix2 + (a2 * fix + a3);
+ out[ox++] = ((a0 * fix + a1) * fix + a2) * fix + a3;
+ ix += pitch;
+ pitch += pitchstep;
+ }
+ }
+ in_offset[0] = ix;
+ out_offset[0] = ox;
+ startpitch[0] = pitch;
+
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SoftEnvelopeGenerator.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SoftEnvelopeGenerator.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,298 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.media.sound;
+
+/**
+ * AHDSR control signal envelope generator.
+ *
+ * @author Karl Helgason
+ */
+public class SoftEnvelopeGenerator implements SoftProcess {
+
+ public final static int EG_OFF = 0;
+ public final static int EG_DELAY = 1;
+ public final static int EG_ATTACK = 2;
+ public final static int EG_HOLD = 3;
+ public final static int EG_DECAY = 4;
+ public final static int EG_SUSTAIN = 5;
+ public final static int EG_RELEASE = 6;
+ public final static int EG_SHUTDOWN = 7;
+ public final static int EG_END = 8;
+ int max_count = 10;
+ int used_count = 0;
+ private int[] stage = new int[max_count];
+ private int[] stage_ix = new int[max_count];
+ private double[] stage_v = new double[max_count];
+ private int[] stage_count = new int[max_count];
+ private double[][] on = new double[max_count][1];
+ private double[][] active = new double[max_count][1];
+ private double[][] out = new double[max_count][1];
+ private double[][] delay = new double[max_count][1];
+ private double[][] attack = new double[max_count][1];
+ private double[][] hold = new double[max_count][1];
+ private double[][] decay = new double[max_count][1];
+ private double[][] sustain = new double[max_count][1];
+ private double[][] release = new double[max_count][1];
+ private double[][] shutdown = new double[max_count][1];
+ private double[][] release2 = new double[max_count][1];
+ private double[][] attack2 = new double[max_count][1];
+ private double[][] decay2 = new double[max_count][1];
+ private double control_time = 0;
+
+ public void reset() {
+ for (int i = 0; i < used_count; i++) {
+ stage[i] = 0;
+ on[i][0] = 0;
+ out[i][0] = 0;
+ delay[i][0] = 0;
+ attack[i][0] = 0;
+ hold[i][0] = 0;
+ decay[i][0] = 0;
+ sustain[i][0] = 0;
+ release[i][0] = 0;
+ shutdown[i][0] = 0;
+ attack2[i][0] = 0;
+ decay2[i][0] = 0;
+ release2[i][0] = 0;
+ }
+ used_count = 0;
+ }
+
+ public void init(SoftSynthesizer synth) {
+ control_time = 1.0 / synth.getControlRate();
+ processControlLogic();
+ }
+
+ public double[] get(int instance, String name) {
+ if (instance >= used_count)
+ used_count = instance + 1;
+ if (name == null)
+ return out[instance];
+ if (name.equals("on"))
+ return on[instance];
+ if (name.equals("active"))
+ return active[instance];
+ if (name.equals("delay"))
+ return delay[instance];
+ if (name.equals("attack"))
+ return attack[instance];
+ if (name.equals("hold"))
+ return hold[instance];
+ if (name.equals("decay"))
+ return decay[instance];
+ if (name.equals("sustain"))
+ return sustain[instance];
+ if (name.equals("release"))
+ return release[instance];
+ if (name.equals("shutdown"))
+ return shutdown[instance];
+ if (name.equals("attack2"))
+ return attack2[instance];
+ if (name.equals("decay2"))
+ return decay2[instance];
+ if (name.equals("release2"))
+ return release2[instance];
+
+ return null;
+ }
+
+ public void processControlLogic() {
+ for (int i = 0; i < used_count; i++) {
+
+ if (stage[i] == EG_END)
+ continue;
+
+ if ((stage[i] > EG_OFF) && (stage[i] < EG_RELEASE)) {
+ if (on[i][0] < 0.5) {
+ if (on[i][0] < -0.5) {
+ stage_count[i] = (int)(Math.pow(2,
+ this.shutdown[i][0] / 1200.0) / control_time);
+ if (stage_count[i] < 0)
+ stage_count[i] = 0;
+ stage_v[i] = out[i][0];
+ stage_ix[i] = 0;
+ stage[i] = EG_SHUTDOWN;
+ } else {
+ if ((release2[i][0] < 0.000001) && release[i][0] < 0
+ && Double.isInfinite(release[i][0])) {
+ out[i][0] = 0;
+ active[i][0] = 0;
+ stage[i] = EG_END;
+ continue;
+ }
+
+ stage_count[i] = (int)(Math.pow(2,
+ this.release[i][0] / 1200.0) / control_time);
+ stage_count[i]
+ += (int)(this.release2[i][0]/(control_time * 1000));
+ if (stage_count[i] < 0)
+ stage_count[i] = 0;
+ // stage_v[i] = out[i][0];
+ stage_ix[i] = 0;
+
+ double m = 1 - out[i][0];
+ stage_ix[i] = (int)(stage_count[i] * m);
+
+ stage[i] = EG_RELEASE;
+ }
+ }
+ }
+
+ switch (stage[i]) {
+ case EG_OFF:
+ active[i][0] = 1;
+ if (on[i][0] < 0.5)
+ break;
+ stage[i] = EG_DELAY;
+ stage_ix[i] = (int)(Math.pow(2,
+ this.delay[i][0] / 1200.0) / control_time);
+ if (stage_ix[i] < 0)
+ stage_ix[i] = 0;
+ case EG_DELAY:
+ if (stage_ix[i] == 0) {
+ double attack = this.attack[i][0];
+ double attack2 = this.attack2[i][0];
+
+ if (attack2 < 0.000001
+ && (attack < 0 && Double.isInfinite(attack))) {
+ out[i][0] = 1;
+ stage[i] = EG_HOLD;
+ stage_count[i] = (int)(Math.pow(2,
+ this.hold[i][0] / 1200.0) / control_time);
+ stage_ix[i] = 0;
+ } else {
+ stage[i] = EG_ATTACK;
+ stage_count[i] = (int)(Math.pow(2,
+ attack / 1200.0) / control_time);
+ stage_count[i] += (int)(attack2 / (control_time * 1000));
+ if (stage_count[i] < 0)
+ stage_count[i] = 0;
+ stage_ix[i] = 0;
+ }
+ } else
+ stage_ix[i]--;
+ break;
+ case EG_ATTACK:
+ stage_ix[i]++;
+ if (stage_ix[i] >= stage_count[i]) {
+ out[i][0] = 1;
+ stage[i] = EG_HOLD;
+ } else {
+ // CONVEX attack
+ double a = ((double)stage_ix[i]) / ((double)stage_count[i]);
+ a = 1 + ((40.0 / 96.0) / Math.log(10)) * Math.log(a);
+ if (a < 0)
+ a = 0;
+ else if (a > 1)
+ a = 1;
+ out[i][0] = a;
+ }
+ break;
+ case EG_HOLD:
+ stage_ix[i]++;
+ if (stage_ix[i] >= stage_count[i]) {
+ stage[i] = EG_DECAY;
+ stage_count[i] = (int)(Math.pow(2,
+ this.decay[i][0] / 1200.0) / control_time);
+ stage_count[i] += (int)(this.decay2[i][0]/(control_time*1000));
+ if (stage_count[i] < 0)
+ stage_count[i] = 0;
+ stage_ix[i] = 0;
+ }
+ break;
+ case EG_DECAY:
+ stage_ix[i]++;
+ double sustain = this.sustain[i][0] * (1.0 / 1000.0);
+ if (stage_ix[i] >= stage_count[i]) {
+ out[i][0] = sustain;
+ stage[i] = EG_SUSTAIN;
+ if (sustain < 0.001) {
+ out[i][0] = 0;
+ active[i][0] = 0;
+ stage[i] = EG_END;
+ }
+ } else {
+ double m = ((double)stage_ix[i]) / ((double)stage_count[i]);
+ out[i][0] = (1 - m) + sustain * m;
+ }
+ break;
+ case EG_SUSTAIN:
+ break;
+ case EG_RELEASE:
+ stage_ix[i]++;
+ if (stage_ix[i] >= stage_count[i]) {
+ out[i][0] = 0;
+ active[i][0] = 0;
+ stage[i] = EG_END;
+ } else {
+ double m = ((double)stage_ix[i]) / ((double)stage_count[i]);
+ out[i][0] = (1 - m); // *stage_v[i];
+
+ if (on[i][0] < -0.5) {
+ stage_count[i] = (int)(Math.pow(2,
+ this.shutdown[i][0] / 1200.0) / control_time);
+ if (stage_count[i] < 0)
+ stage_count[i] = 0;
+ stage_v[i] = out[i][0];
+ stage_ix[i] = 0;
+ stage[i] = EG_SHUTDOWN;
+ }
+
+ // re-damping
+ if (on[i][0] > 0.5) {
+ sustain = this.sustain[i][0] * (1.0 / 1000.0);
+ if (out[i][0] > sustain) {
+ stage[i] = EG_DECAY;
+ stage_count[i] = (int)(Math.pow(2,
+ this.decay[i][0] / 1200.0) / control_time);
+ stage_count[i] +=
+ (int)(this.decay2[i][0]/(control_time*1000));
+ if (stage_count[i] < 0)
+ stage_count[i] = 0;
+ m = (out[i][0] - 1) / (sustain - 1);
+ stage_ix[i] = (int) (stage_count[i] * m);
+ }
+ }
+
+ }
+ break;
+ case EG_SHUTDOWN:
+ stage_ix[i]++;
+ if (stage_ix[i] >= stage_count[i]) {
+ out[i][0] = 0;
+ active[i][0] = 0;
+ stage[i] = EG_END;
+ } else {
+ double m = ((double)stage_ix[i]) / ((double)stage_count[i]);
+ out[i][0] = (1 - m) * stage_v[i];
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SoftFilter.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SoftFilter.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,614 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.media.sound;
+
+/**
+ * Infinite impulse response (IIR) filter class.
+ *
+ * The filters where implemented and adapted using algorithms from musicdsp.org
+ * archive: 1-RC and C filter, Simple 2-pole LP LP and HP filter, biquad,
+ * tweaked butterworth RBJ Audio-EQ-Cookbook, EQ filter kookbook
+ *
+ * @author Karl Helgason
+ */
+public class SoftFilter {
+
+ public final static int FILTERTYPE_LP6 = 0x00;
+ public final static int FILTERTYPE_LP12 = 0x01;
+ public final static int FILTERTYPE_HP12 = 0x11;
+ public final static int FILTERTYPE_BP12 = 0x21;
+ public final static int FILTERTYPE_NP12 = 0x31;
+ public final static int FILTERTYPE_LP24 = 0x03;
+ public final static int FILTERTYPE_HP24 = 0x13;
+
+ //
+ // 0x0 = 1st-order, 6 dB/oct
+ // 0x1 = 2nd-order, 12 dB/oct
+ // 0x2 = 3rd-order, 18 dB/oct
+ // 0x3 = 4th-order, 24 db/oct
+ //
+ // 0x00 = LP, Low Pass Filter
+ // 0x10 = HP, High Pass Filter
+ // 0x20 = BP, Band Pass Filter
+ // 0x30 = NP, Notch or Band Elimination Filter
+ //
+ private int filtertype = FILTERTYPE_LP6;
+ private float samplerate;
+ private float x1;
+ private float x2;
+ private float y1;
+ private float y2;
+ private float xx1;
+ private float xx2;
+ private float yy1;
+ private float yy2;
+ private float a0;
+ private float a1;
+ private float a2;
+ private float b1;
+ private float b2;
+ private float q;
+ private float gain = 1;
+ private float wet = 0;
+ private float last_wet = 0;
+ private float last_a0;
+ private float last_a1;
+ private float last_a2;
+ private float last_b1;
+ private float last_b2;
+ private float last_q;
+ private float last_gain;
+ private boolean last_set = false;
+ private double cutoff = 44100;
+ private double resonancedB = 0;
+ private boolean dirty = true;
+
+ public SoftFilter(float samplerate) {
+ this.samplerate = samplerate;
+ dirty = true;
+ }
+
+ public void setFrequency(double cent) {
+ if (cutoff == cent)
+ return;
+ cutoff = cent;
+ dirty = true;
+ }
+
+ public void setResonance(double db) {
+ if (resonancedB == db)
+ return;
+ resonancedB = db;
+ dirty = true;
+ }
+
+ public void reset() {
+ dirty = true;
+ last_set = false;
+ x1 = 0;
+ x2 = 0;
+ y1 = 0;
+ y2 = 0;
+ xx1 = 0;
+ xx2 = 0;
+ yy1 = 0;
+ yy2 = 0;
+ wet = 0.0f;
+ gain = 1.0f;
+ a0 = 0;
+ a1 = 0;
+ a2 = 0;
+ b1 = 0;
+ b2 = 0;
+ }
+
+ public void setFilterType(int filtertype) {
+ this.filtertype = filtertype;
+ }
+
+ public void processAudio(SoftAudioBuffer sbuffer) {
+ if (filtertype == FILTERTYPE_LP6)
+ filter1(sbuffer);
+ if (filtertype == FILTERTYPE_LP12)
+ filter2(sbuffer);
+ if (filtertype == FILTERTYPE_HP12)
+ filter2(sbuffer);
+ if (filtertype == FILTERTYPE_BP12)
+ filter2(sbuffer);
+ if (filtertype == FILTERTYPE_NP12)
+ filter2(sbuffer);
+ if (filtertype == FILTERTYPE_LP24)
+ filter4(sbuffer);
+ if (filtertype == FILTERTYPE_HP24)
+ filter4(sbuffer);
+ }
+
+ public void filter4(SoftAudioBuffer sbuffer) {
+
+ float[] buffer = sbuffer.array();
+
+ if (dirty) {
+ filter2calc();
+ dirty = false;
+ }
+ if (!last_set) {
+ last_a0 = a0;
+ last_a1 = a1;
+ last_a2 = a2;
+ last_b1 = b1;
+ last_b2 = b2;
+ last_gain = gain;
+ last_wet = wet;
+ last_set = true;
+ }
+
+ if (wet > 0 || last_wet > 0) {
+
+ int len = buffer.length;
+ float a0 = this.last_a0;
+ float a1 = this.last_a1;
+ float a2 = this.last_a2;
+ float b1 = this.last_b1;
+ float b2 = this.last_b2;
+ float gain = this.last_gain;
+ float wet = this.last_wet;
+ float a0_delta = (this.a0 - this.last_a0) / len;
+ float a1_delta = (this.a1 - this.last_a1) / len;
+ float a2_delta = (this.a2 - this.last_a2) / len;
+ float b1_delta = (this.b1 - this.last_b1) / len;
+ float b2_delta = (this.b2 - this.last_b2) / len;
+ float gain_delta = (this.gain - this.last_gain) / len;
+ float wet_delta = (this.wet - this.last_wet) / len;
+ float x1 = this.x1;
+ float x2 = this.x2;
+ float y1 = this.y1;
+ float y2 = this.y2;
+ float xx1 = this.xx1;
+ float xx2 = this.xx2;
+ float yy1 = this.yy1;
+ float yy2 = this.yy2;
+
+ if (wet_delta != 0) {
+ for (int i = 0; i < len; i++) {
+ a0 += a0_delta;
+ a1 += a1_delta;
+ a2 += a2_delta;
+ b1 += b1_delta;
+ b2 += b2_delta;
+ gain += gain_delta;
+ wet += wet_delta;
+ float x = buffer[i];
+ float y = (a0*x + a1*x1 + a2*x2 - b1*y1 - b2*y2);
+ float xx = (y * gain) * wet + (x) * (1 - wet);
+ x2 = x1;
+ x1 = x;
+ y2 = y1;
+ y1 = y;
+ float yy = (a0*xx + a1*xx1 + a2*xx2 - b1*yy1 - b2*yy2);
+ buffer[i] = (yy * gain) * wet + (xx) * (1 - wet);
+ xx2 = xx1;
+ xx1 = xx;
+ yy2 = yy1;
+ yy1 = yy;
+ }
+ } else if (a0_delta == 0 && a1_delta == 0 && a2_delta == 0
+ && b1_delta == 0 && b2_delta == 0) {
+ for (int i = 0; i < len; i++) {
+ float x = buffer[i];
+ float y = (a0*x + a1*x1 + a2*x2 - b1*y1 - b2*y2);
+ float xx = (y * gain) * wet + (x) * (1 - wet);
+ x2 = x1;
+ x1 = x;
+ y2 = y1;
+ y1 = y;
+ float yy = (a0*xx + a1*xx1 + a2*xx2 - b1*yy1 - b2*yy2);
+ buffer[i] = (yy * gain) * wet + (xx) * (1 - wet);
+ xx2 = xx1;
+ xx1 = xx;
+ yy2 = yy1;
+ yy1 = yy;
+ }
+ } else {
+ for (int i = 0; i < len; i++) {
+ a0 += a0_delta;
+ a1 += a1_delta;
+ a2 += a2_delta;
+ b1 += b1_delta;
+ b2 += b2_delta;
+ gain += gain_delta;
+ float x = buffer[i];
+ float y = (a0*x + a1*x1 + a2*x2 - b1*y1 - b2*y2);
+ float xx = (y * gain) * wet + (x) * (1 - wet);
+ x2 = x1;
+ x1 = x;
+ y2 = y1;
+ y1 = y;
+ float yy = (a0*xx + a1*xx1 + a2*xx2 - b1*yy1 - b2*yy2);
+ buffer[i] = (yy * gain) * wet + (xx) * (1 - wet);
+ xx2 = xx1;
+ xx1 = xx;
+ yy2 = yy1;
+ yy1 = yy;
+ }
+ }
+
+ if (Math.abs(x1) < 1.0E-8)
+ x1 = 0;
+ if (Math.abs(x2) < 1.0E-8)
+ x2 = 0;
+ if (Math.abs(y1) < 1.0E-8)
+ y1 = 0;
+ if (Math.abs(y2) < 1.0E-8)
+ y2 = 0;
+ this.x1 = x1;
+ this.x2 = x2;
+ this.y1 = y1;
+ this.y2 = y2;
+ this.xx1 = xx1;
+ this.xx2 = xx2;
+ this.yy1 = yy1;
+ this.yy2 = yy2;
+ }
+
+ this.last_a0 = this.a0;
+ this.last_a1 = this.a1;
+ this.last_a2 = this.a2;
+ this.last_b1 = this.b1;
+ this.last_b2 = this.b2;
+ this.last_gain = this.gain;
+ this.last_wet = this.wet;
+
+ }
+
+ private double sinh(double x) {
+ return (Math.exp(x) - Math.exp(-x)) * 0.5;
+ }
+
+ public void filter2calc() {
+
+ double resonancedB = this.resonancedB;
+ if (resonancedB < 0)
+ resonancedB = 0; // Negative dB are illegal.
+ if (resonancedB > 30)
+ resonancedB = 30; // At least 22.5 dB is needed.
+ if (filtertype == FILTERTYPE_LP24 || filtertype == FILTERTYPE_HP24)
+ resonancedB *= 0.6;
+
+ if (filtertype == FILTERTYPE_BP12) {
+ wet = 1;
+ double r = (cutoff / samplerate);
+ if (r > 0.45)
+ r = 0.45;
+
+ double bandwidth = Math.PI * Math.pow(10.0, -(resonancedB / 20));
+
+ double omega = 2 * Math.PI * r;
+ double cs = Math.cos(omega);
+ double sn = Math.sin(omega);
+ double alpha = sn * sinh((Math.log(2)*bandwidth*omega) / (sn * 2));
+
+ double b0 = alpha;
+ double b1 = 0;
+ double b2 = -alpha;
+ double a0 = 1 + alpha;
+ double a1 = -2 * cs;
+ double a2 = 1 - alpha;
+
+ double cf = 1.0 / a0;
+ this.b1 = (float) (a1 * cf);
+ this.b2 = (float) (a2 * cf);
+ this.a0 = (float) (b0 * cf);
+ this.a1 = (float) (b1 * cf);
+ this.a2 = (float) (b2 * cf);
+ }
+
+ if (filtertype == FILTERTYPE_NP12) {
+ wet = 1;
+ double r = (cutoff / samplerate);
+ if (r > 0.45)
+ r = 0.45;
+
+ double bandwidth = Math.PI * Math.pow(10.0, -(resonancedB / 20));
+
+ double omega = 2 * Math.PI * r;
+ double cs = Math.cos(omega);
+ double sn = Math.sin(omega);
+ double alpha = sn * sinh((Math.log(2)*bandwidth*omega) / (sn*2));
+
+ double b0 = 1;
+ double b1 = -2 * cs;
+ double b2 = 1;
+ double a0 = 1 + alpha;
+ double a1 = -2 * cs;
+ double a2 = 1 - alpha;
+
+ double cf = 1.0 / a0;
+ this.b1 = (float)(a1 * cf);
+ this.b2 = (float)(a2 * cf);
+ this.a0 = (float)(b0 * cf);
+ this.a1 = (float)(b1 * cf);
+ this.a2 = (float)(b2 * cf);
+ }
+
+ if (filtertype == FILTERTYPE_LP12 || filtertype == FILTERTYPE_LP24) {
+ double r = (cutoff / samplerate);
+ if (r > 0.45) {
+ if (wet == 0) {
+ if (resonancedB < 0.00001)
+ wet = 0.0f;
+ else
+ wet = 1.0f;
+ }
+ r = 0.45;
+ } else
+ wet = 1.0f;
+
+ double c = 1.0 / (Math.tan(Math.PI * r));
+ double csq = c * c;
+ double resonance = Math.pow(10.0, -(resonancedB / 20));
+ double q = Math.sqrt(2.0f) * resonance;
+ double a0 = 1.0 / (1.0 + (q * c) + (csq));
+ double a1 = 2.0 * a0;
+ double a2 = a0;
+ double b1 = (2.0 * a0) * (1.0 - csq);
+ double b2 = a0 * (1.0 - (q * c) + csq);
+
+ this.a0 = (float)a0;
+ this.a1 = (float)a1;
+ this.a2 = (float)a2;
+ this.b1 = (float)b1;
+ this.b2 = (float)b2;
+
+ }
+
+ if (filtertype == FILTERTYPE_HP12 || filtertype == FILTERTYPE_HP24) {
+ double r = (cutoff / samplerate);
+ if (r > 0.45)
+ r = 0.45;
+ if (r < 0.0001)
+ r = 0.0001;
+ wet = 1.0f;
+ double c = (Math.tan(Math.PI * (r)));
+ double csq = c * c;
+ double resonance = Math.pow(10.0, -(resonancedB / 20));
+ double q = Math.sqrt(2.0f) * resonance;
+ double a0 = 1.0 / (1.0 + (q * c) + (csq));
+ double a1 = -2.0 * a0;
+ double a2 = a0;
+ double b1 = (2.0 * a0) * (csq - 1.0);
+ double b2 = a0 * (1.0 - (q * c) + csq);
+
+ this.a0 = (float)a0;
+ this.a1 = (float)a1;
+ this.a2 = (float)a2;
+ this.b1 = (float)b1;
+ this.b2 = (float)b2;
+
+ }
+
+ }
+
+ public void filter2(SoftAudioBuffer sbuffer) {
+
+ float[] buffer = sbuffer.array();
+
+ if (dirty) {
+ filter2calc();
+ dirty = false;
+ }
+ if (!last_set) {
+ last_a0 = a0;
+ last_a1 = a1;
+ last_a2 = a2;
+ last_b1 = b1;
+ last_b2 = b2;
+ last_q = q;
+ last_gain = gain;
+ last_wet = wet;
+ last_set = true;
+ }
+
+ if (wet > 0 || last_wet > 0) {
+
+ int len = buffer.length;
+ float a0 = this.last_a0;
+ float a1 = this.last_a1;
+ float a2 = this.last_a2;
+ float b1 = this.last_b1;
+ float b2 = this.last_b2;
+ float gain = this.last_gain;
+ float wet = this.last_wet;
+ float a0_delta = (this.a0 - this.last_a0) / len;
+ float a1_delta = (this.a1 - this.last_a1) / len;
+ float a2_delta = (this.a2 - this.last_a2) / len;
+ float b1_delta = (this.b1 - this.last_b1) / len;
+ float b2_delta = (this.b2 - this.last_b2) / len;
+ float gain_delta = (this.gain - this.last_gain) / len;
+ float wet_delta = (this.wet - this.last_wet) / len;
+ float x1 = this.x1;
+ float x2 = this.x2;
+ float y1 = this.y1;
+ float y2 = this.y2;
+
+ if (wet_delta != 0) {
+ for (int i = 0; i < len; i++) {
+ a0 += a0_delta;
+ a1 += a1_delta;
+ a2 += a2_delta;
+ b1 += b1_delta;
+ b2 += b2_delta;
+ gain += gain_delta;
+ wet += wet_delta;
+ float x = buffer[i];
+ float y = (a0*x + a1*x1 + a2*x2 - b1*y1 - b2*y2);
+ buffer[i] = (y * gain) * wet + (x) * (1 - wet);
+ x2 = x1;
+ x1 = x;
+ y2 = y1;
+ y1 = y;
+ }
+ } else if (a0_delta == 0 && a1_delta == 0 && a2_delta == 0
+ && b1_delta == 0 && b2_delta == 0) {
+ for (int i = 0; i < len; i++) {
+ float x = buffer[i];
+ float y = (a0*x + a1*x1 + a2*x2 - b1*y1 - b2*y2);
+ buffer[i] = y * gain;
+ x2 = x1;
+ x1 = x;
+ y2 = y1;
+ y1 = y;
+ }
+ } else {
+ for (int i = 0; i < len; i++) {
+ a0 += a0_delta;
+ a1 += a1_delta;
+ a2 += a2_delta;
+ b1 += b1_delta;
+ b2 += b2_delta;
+ gain += gain_delta;
+ float x = buffer[i];
+ float y = (a0*x + a1*x1 + a2*x2 - b1*y1 - b2*y2);
+ buffer[i] = y * gain;
+ x2 = x1;
+ x1 = x;
+ y2 = y1;
+ y1 = y;
+ }
+ }
+
+ if (Math.abs(x1) < 1.0E-8)
+ x1 = 0;
+ if (Math.abs(x2) < 1.0E-8)
+ x2 = 0;
+ if (Math.abs(y1) < 1.0E-8)
+ y1 = 0;
+ if (Math.abs(y2) < 1.0E-8)
+ y2 = 0;
+ this.x1 = x1;
+ this.x2 = x2;
+ this.y1 = y1;
+ this.y2 = y2;
+ }
+
+ this.last_a0 = this.a0;
+ this.last_a1 = this.a1;
+ this.last_a2 = this.a2;
+ this.last_b1 = this.b1;
+ this.last_b2 = this.b2;
+ this.last_q = this.q;
+ this.last_gain = this.gain;
+ this.last_wet = this.wet;
+
+ }
+
+ public void filter1calc() {
+ if (cutoff < 120)
+ cutoff = 120;
+ double c = (7.0 / 6.0) * Math.PI * 2 * cutoff / samplerate;
+ if (c > 1)
+ c = 1;
+ a0 = (float)(Math.sqrt(1 - Math.cos(c)) * Math.sqrt(0.5 * Math.PI));
+ if (resonancedB < 0)
+ resonancedB = 0;
+ if (resonancedB > 20)
+ resonancedB = 20;
+ q = (float)(Math.sqrt(0.5) * Math.pow(10.0, -(resonancedB / 20)));
+ gain = (float)Math.pow(10, -((resonancedB)) / 40.0);
+ if (wet == 0.0f)
+ if (resonancedB > 0.00001 || c < 0.9999999)
+ wet = 1.0f;
+ }
+
+ public void filter1(SoftAudioBuffer sbuffer) {
+
+ float[] buffer = sbuffer.array();
+
+ if (dirty) {
+ filter1calc();
+ dirty = false;
+ }
+ if (!last_set) {
+ last_a0 = a0;
+ last_q = q;
+ last_gain = gain;
+ last_wet = wet;
+ last_set = true;
+ }
+
+ if (wet > 0 || last_wet > 0) {
+
+ int len = buffer.length;
+ float a0 = this.last_a0;
+ float q = this.last_q;
+ float gain = this.last_gain;
+ float wet = this.last_wet;
+ float a0_delta = (this.a0 - this.last_a0) / len;
+ float q_delta = (this.q - this.last_q) / len;
+ float gain_delta = (this.gain - this.last_gain) / len;
+ float wet_delta = (this.wet - this.last_wet) / len;
+ float y2 = this.y2;
+ float y1 = this.y1;
+
+ if (wet_delta != 0) {
+ for (int i = 0; i < len; i++) {
+ a0 += a0_delta;
+ q += q_delta;
+ gain += gain_delta;
+ wet += wet_delta;
+ y1 = (1 - q * a0) * y1 - (a0) * y2 + (a0) * buffer[i];
+ y2 = (1 - q * a0) * y2 + (a0) * y1;
+ buffer[i] = y2 * gain * wet + buffer[i] * (1 - wet);
+ }
+ } else if (a0_delta == 0 && q_delta == 0) {
+ for (int i = 0; i < len; i++) {
+ y1 = (1 - q * a0) * y1 - (a0) * y2 + (a0) * buffer[i];
+ y2 = (1 - q * a0) * y2 + (a0) * y1;
+ buffer[i] = y2 * gain;
+ }
+ } else {
+ for (int i = 0; i < len; i++) {
+ a0 += a0_delta;
+ q += q_delta;
+ gain += gain_delta;
+ y1 = (1 - q * a0) * y1 - (a0) * y2 + (a0) * buffer[i];
+ y2 = (1 - q * a0) * y2 + (a0) * y1;
+ buffer[i] = y2 * gain;
+ }
+ }
+
+ if (Math.abs(y2) < 1.0E-8)
+ y2 = 0;
+ if (Math.abs(y1) < 1.0E-8)
+ y1 = 0;
+ this.y2 = y2;
+ this.y1 = y1;
+ }
+
+ this.last_a0 = this.a0;
+ this.last_q = this.q;
+ this.last_gain = this.gain;
+ this.last_wet = this.wet;
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SoftInstrument.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SoftInstrument.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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;
+
+/**
+ * Software synthesizer internal instrument.
+ *
+ * @author Karl Helgason
+ */
+public class SoftInstrument extends Instrument {
+
+ private SoftPerformer[] performers;
+ private ModelPerformer[] modelperformers;
+ private Object data;
+ private ModelInstrument ins;
+
+ public SoftInstrument(ModelInstrument ins) {
+ super(ins.getSoundbank(), ins.getPatch(), ins.getName(),
+ ins.getDataClass());
+ data = ins.getData();
+ this.ins = ins;
+ initPerformers(((ModelInstrument)ins).getPerformers());
+ }
+
+ public SoftInstrument(ModelInstrument ins,
+ ModelPerformer[] overrideperformers) {
+ super(ins.getSoundbank(), ins.getPatch(), ins.getName(),
+ ins.getDataClass());
+ data = ins.getData();
+ this.ins = ins;
+ initPerformers(overrideperformers);
+ }
+
+ private void initPerformers(ModelPerformer[] modelperformers) {
+ this.modelperformers = modelperformers;
+ performers = new SoftPerformer[modelperformers.length];
+ for (int i = 0; i < modelperformers.length; i++)
+ performers[i] = new SoftPerformer(modelperformers[i]);
+ }
+
+ public ModelDirector getDirector(MidiChannel channel,
+ ModelDirectedPlayer player) {
+ return ins.getDirector(modelperformers, channel, player);
+ }
+
+ public ModelInstrument getSourceInstrument() {
+ return ins;
+ }
+
+ public Object getData() {
+ return data;
+ }
+
+ public SoftPerformer[] getPerformers() {
+ return performers;
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SoftJitterCorrector.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SoftJitterCorrector.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,276 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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;
+
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.AudioInputStream;
+
+/**
+ * A jitter corrector to be used with SoftAudioPusher.
+ *
+ * @author Karl Helgason
+ */
+public class SoftJitterCorrector extends AudioInputStream {
+
+ private static class JitterStream extends InputStream {
+
+ static int MAX_BUFFER_SIZE = 1048576;
+ boolean active = true;
+ Thread thread;
+ AudioInputStream stream;
+ // Cyclic buffer
+ int writepos = 0;
+ int readpos = 0;
+ byte[][] buffers;
+ Object buffers_mutex = new Object();
+
+ // Adapative Drift Statistics
+ int w_count = 1000;
+ int w_min_tol = 2;
+ int w_max_tol = 10;
+ int w = 0;
+ int w_min = -1;
+ // Current read buffer
+ int bbuffer_pos = 0;
+ int bbuffer_max = 0;
+ byte[] bbuffer = null;
+
+ public byte[] nextReadBuffer() {
+ synchronized (buffers_mutex) {
+ if (writepos > readpos) {
+ int w_m = writepos - readpos;
+ if (w_m < w_min)
+ w_min = w_m;
+
+ int buffpos = readpos;
+ readpos++;
+ return buffers[buffpos % buffers.length];
+ }
+ w_min = -1;
+ w = w_count - 1;
+ }
+ while (true) {
+ try {
+ Thread.sleep(1);
+ } catch (InterruptedException e) {
+ //e.printStackTrace();
+ return null;
+ }
+ synchronized (buffers_mutex) {
+ if (writepos > readpos) {
+ w = 0;
+ w_min = -1;
+ w = w_count - 1;
+ int buffpos = readpos;
+ readpos++;
+ return buffers[buffpos % buffers.length];
+ }
+ }
+ }
+ }
+
+ public byte[] nextWriteBuffer() {
+ synchronized (buffers_mutex) {
+ return buffers[writepos % buffers.length];
+ }
+ }
+
+ public void commit() {
+ synchronized (buffers_mutex) {
+ writepos++;
+ if ((writepos - readpos) > buffers.length) {
+ int newsize = (writepos - readpos) + 10;
+ newsize = Math.max(buffers.length * 2, newsize);
+ buffers = new byte[newsize][buffers[0].length];
+ }
+ }
+ }
+
+ public JitterStream(AudioInputStream s, int buffersize,
+ int smallbuffersize) {
+ this.w_count = 10 * (buffersize / smallbuffersize);
+ if (w_count < 100)
+ w_count = 100;
+ this.buffers
+ = new byte[(buffersize/smallbuffersize)+10][smallbuffersize];
+ this.bbuffer_max = MAX_BUFFER_SIZE / smallbuffersize;
+ this.stream = s;
+
+
+ Runnable runnable = new Runnable() {
+
+ public void run() {
+ AudioFormat format = stream.getFormat();
+ int bufflen = buffers[0].length;
+ int frames = bufflen / format.getFrameSize();
+ long nanos = (long) (frames * 1000000000.0
+ / format.getSampleRate());
+ long now = System.nanoTime();
+ long next = now + nanos;
+ int correction = 0;
+ while (true) {
+ synchronized (JitterStream.this) {
+ if (!active)
+ break;
+ }
+ int curbuffsize;
+ synchronized (buffers) {
+ curbuffsize = writepos - readpos;
+ if (correction == 0) {
+ w++;
+ if (w_min != Integer.MAX_VALUE) {
+ if (w == w_count) {
+ correction = 0;
+ if (w_min < w_min_tol) {
+ correction = (w_min_tol + w_max_tol)
+ / 2 - w_min;
+ }
+ if (w_min > w_max_tol) {
+ correction = (w_min_tol + w_max_tol)
+ / 2 - w_min;
+ }
+ w = 0;
+ w_min = Integer.MAX_VALUE;
+ }
+ }
+ }
+ }
+ while (curbuffsize > bbuffer_max) {
+ synchronized (buffers) {
+ curbuffsize = writepos - readpos;
+ }
+ synchronized (JitterStream.this) {
+ if (!active)
+ break;
+ }
+ try {
+ Thread.sleep(1);
+ } catch (InterruptedException e) {
+ //e.printStackTrace();
+ }
+ }
+
+ if (correction < 0)
+ correction++;
+ else {
+ byte[] buff = nextWriteBuffer();
+ try {
+ int n = 0;
+ while (n != buff.length) {
+ int s = stream.read(buff, n, buff.length
+ - n);
+ if (s < 0)
+ throw new EOFException();
+ if (s == 0)
+ Thread.yield();
+ n += s;
+ }
+ } catch (IOException e1) {
+ //e1.printStackTrace();
+ }
+ commit();
+ }
+
+ if (correction > 0) {
+ correction--;
+ next = System.nanoTime() + nanos;
+ continue;
+ }
+ long wait = next - System.nanoTime();
+ if (wait > 0) {
+ try {
+ Thread.sleep(wait / 1000000L);
+ } catch (InterruptedException e) {
+ //e.printStackTrace();
+ }
+ }
+ next += nanos;
+ }
+ }
+ };
+
+ thread = new Thread(runnable);
+ thread.setPriority(Thread.MAX_PRIORITY);
+ thread.start();
+ }
+
+ public void close() throws IOException {
+ synchronized (this) {
+ active = false;
+ }
+ try {
+ thread.join();
+ } catch (InterruptedException e) {
+ //e.printStackTrace();
+ }
+ stream.close();
+ }
+
+ public int read() throws IOException {
+ byte[] b = new byte[1];
+ if (read(b) == -1)
+ return -1;
+ return b[0] & 0xFF;
+ }
+
+ public void fillBuffer() {
+ bbuffer = nextReadBuffer();
+ bbuffer_pos = 0;
+ }
+
+ public int read(byte[] b, int off, int len) {
+ if (bbuffer == null)
+ fillBuffer();
+ int bbuffer_len = bbuffer.length;
+ int offlen = off + len;
+ while (off < offlen) {
+ if (available() == 0)
+ fillBuffer();
+ else {
+ byte[] bbuffer = this.bbuffer;
+ int bbuffer_pos = this.bbuffer_pos;
+ while (off < offlen && bbuffer_pos < bbuffer_len)
+ b[off++] = bbuffer[bbuffer_pos++];
+ this.bbuffer_pos = bbuffer_pos;
+ }
+ }
+ return len;
+ }
+
+ public int available() {
+ return bbuffer.length - bbuffer_pos;
+ }
+ }
+
+ public SoftJitterCorrector(AudioInputStream stream, int buffersize,
+ int smallbuffersize) {
+ super(new JitterStream(stream, buffersize, smallbuffersize),
+ stream.getFormat(), stream.getFrameLength());
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SoftLanczosResampler.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SoftLanczosResampler.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.media.sound;
+
+/**
+ * Lanczos interpolation resampler.
+ *
+ * @author Karl Helgason
+ */
+public class SoftLanczosResampler extends SoftAbstractResampler {
+
+ float[][] sinc_table;
+ int sinc_table_fsize = 2000;
+ int sinc_table_size = 5;
+ int sinc_table_center = sinc_table_size / 2;
+
+ public SoftLanczosResampler() {
+ super();
+ sinc_table = new float[sinc_table_fsize][];
+ for (int i = 0; i < sinc_table_fsize; i++) {
+ sinc_table[i] = sincTable(sinc_table_size, -i
+ / ((float) sinc_table_fsize));
+ }
+ }
+
+ // Normalized sinc function
+ public static double sinc(double x) {
+ return (x == 0.0) ? 1.0 : Math.sin(Math.PI * x) / (Math.PI * x);
+ }
+
+ // Generate sinc table
+ public static float[] sincTable(int size, float offset) {
+ int center = size / 2;
+ float[] w = new float[size];
+ for (int k = 0; k < size; k++) {
+ float x = (-center + k + offset);
+ if (x < -2 || x > 2)
+ w[k] = 0;
+ else if (x == 0)
+ w[k] = 1;
+ else {
+ w[k] = (float)(2.0 * Math.sin(Math.PI * x)
+ * Math.sin(Math.PI * x / 2.0)
+ / ((Math.PI * x) * (Math.PI * x)));
+ }
+ }
+ return w;
+ }
+
+ public int getPadding() // must be at least half of sinc_table_size
+ {
+ return sinc_table_size / 2 + 2;
+ }
+
+ public void interpolate(float[] in, float[] in_offset, float in_end,
+ float[] startpitch, float pitchstep, float[] out, int[] out_offset,
+ int out_end) {
+ float pitch = startpitch[0];
+ float ix = in_offset[0];
+ int ox = out_offset[0];
+ float ix_end = in_end;
+ int ox_end = out_end;
+
+ if (pitchstep == 0) {
+ while (ix < ix_end && ox < ox_end) {
+ int iix = (int) ix;
+ float[] sinc_table
+ = this.sinc_table[(int) ((ix - iix) * sinc_table_fsize)];
+ int xx = iix - sinc_table_center;
+ float y = 0;
+ for (int i = 0; i < sinc_table_size; i++, xx++)
+ y += in[xx] * sinc_table[i];
+ out[ox++] = y;
+ ix += pitch;
+ }
+ } else {
+ while (ix < ix_end && ox < ox_end) {
+ int iix = (int) ix;
+ float[] sinc_table
+ = this.sinc_table[(int) ((ix - iix) * sinc_table_fsize)];
+ int xx = iix - sinc_table_center;
+ float y = 0;
+ for (int i = 0; i < sinc_table_size; i++, xx++)
+ y += in[xx] * sinc_table[i];
+ out[ox++] = y;
+
+ ix += pitch;
+ pitch += pitchstep;
+ }
+ }
+ in_offset[0] = ix;
+ out_offset[0] = ox;
+ startpitch[0] = pitch;
+
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SoftLimiter.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SoftLimiter.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.media.sound;
+
+/**
+ * A simple look-ahead volume limiter with very fast attack and fast release.
+ * This filter is used for preventing clipping.
+ *
+ * @author Karl Helgason
+ */
+public class SoftLimiter implements SoftAudioProcessor {
+
+ float lastmax = 0;
+ float gain = 1;
+ float[] temp_bufferL;
+ float[] temp_bufferR;
+ boolean mix = false;
+ SoftAudioBuffer bufferL;
+ SoftAudioBuffer bufferR;
+ SoftAudioBuffer bufferLout;
+ SoftAudioBuffer bufferRout;
+ float controlrate;
+
+ public void init(float samplerate, float controlrate) {
+ this.controlrate = controlrate;
+ }
+
+ public void setInput(int pin, SoftAudioBuffer input) {
+ if (pin == 0)
+ bufferL = input;
+ if (pin == 1)
+ bufferR = input;
+ }
+
+ public void setOutput(int pin, SoftAudioBuffer output) {
+ if (pin == 0)
+ bufferLout = output;
+ if (pin == 1)
+ bufferRout = output;
+ }
+
+ public void setMixMode(boolean mix) {
+ this.mix = mix;
+ }
+
+ public void globalParameterControlChange(int[] slothpath, long param,
+ long value) {
+ }
+
+ double silentcounter = 0;
+
+ public void processAudio() {
+ if (this.bufferL.isSilent()
+ && (this.bufferR == null || this.bufferR.isSilent())) {
+ silentcounter += 1 / controlrate;
+
+ if (silentcounter > 60) {
+ if (!mix) {
+ bufferLout.clear();
+ bufferRout.clear();
+ }
+ return;
+ }
+ } else
+ silentcounter = 0;
+
+ float[] bufferL = this.bufferL.array();
+ float[] bufferR = this.bufferR == null ? null : this.bufferR.array();
+ float[] bufferLout = this.bufferLout.array();
+ float[] bufferRout = this.bufferRout == null
+ ? null : this.bufferRout.array();
+
+ if (temp_bufferL == null || temp_bufferL.length < bufferL.length)
+ temp_bufferL = new float[bufferL.length];
+ if (bufferR != null)
+ if (temp_bufferR == null || temp_bufferR.length < bufferR.length)
+ temp_bufferR = new float[bufferR.length];
+
+ float max = 0;
+ int len = bufferL.length;
+
+ if (bufferR == null) {
+ for (int i = 0; i < len; i++) {
+ if (bufferL[i] > max)
+ max = bufferL[i];
+ if (-bufferL[i] > max)
+ max = -bufferL[i];
+ }
+ } else {
+ for (int i = 0; i < len; i++) {
+ if (bufferL[i] > max)
+ max = bufferL[i];
+ if (bufferR[i] > max)
+ max = bufferR[i];
+ if (-bufferL[i] > max)
+ max = -bufferL[i];
+ if (-bufferR[i] > max)
+ max = -bufferR[i];
+ }
+ }
+
+ float lmax = lastmax;
+ lastmax = max;
+ if (lmax > max)
+ max = lmax;
+
+ float newgain = 1;
+ if (max > 0.99f)
+ newgain = 0.99f / max;
+ else
+ newgain = 1;
+
+ if (newgain > gain)
+ newgain = (newgain + gain * 9) / 10f;
+
+ float gaindelta = (newgain - gain) / len;
+ if (mix) {
+ if (bufferR == null) {
+ for (int i = 0; i < len; i++) {
+ gain += gaindelta;
+ float bL = bufferL[i];
+ float tL = temp_bufferL[i];
+ temp_bufferL[i] = bL;
+ bufferLout[i] += tL * gain;
+ }
+ } else {
+ for (int i = 0; i < len; i++) {
+ gain += gaindelta;
+ float bL = bufferL[i];
+ float bR = bufferR[i];
+ float tL = temp_bufferL[i];
+ float tR = temp_bufferR[i];
+ temp_bufferL[i] = bL;
+ temp_bufferR[i] = bR;
+ bufferLout[i] += tL * gain;
+ bufferRout[i] += tR * gain;
+ }
+ }
+
+ } else {
+ if (bufferR == null) {
+ for (int i = 0; i < len; i++) {
+ gain += gaindelta;
+ float bL = bufferL[i];
+ float tL = temp_bufferL[i];
+ temp_bufferL[i] = bL;
+ bufferLout[i] = tL * gain;
+ }
+ } else {
+ for (int i = 0; i < len; i++) {
+ gain += gaindelta;
+ float bL = bufferL[i];
+ float bR = bufferR[i];
+ float tL = temp_bufferL[i];
+ float tR = temp_bufferR[i];
+ temp_bufferL[i] = bL;
+ temp_bufferR[i] = bR;
+ bufferLout[i] = tL * gain;
+ bufferRout[i] = tR * gain;
+ }
+ }
+
+ }
+ gain = newgain;
+ }
+
+ public void processControlLogic() {
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SoftLinearResampler.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SoftLinearResampler.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.media.sound;
+
+/**
+ * A resampler that uses first-order (linear) interpolation.
+ *
+ * @author Karl Helgason
+ */
+public class SoftLinearResampler extends SoftAbstractResampler {
+
+ public int getPadding() {
+ return 2;
+ }
+
+ public void interpolate(float[] in, float[] in_offset, float in_end,
+ float[] startpitch, float pitchstep, float[] out, int[] out_offset,
+ int out_end) {
+
+ float pitch = startpitch[0];
+ float ix = in_offset[0];
+ int ox = out_offset[0];
+ float ix_end = in_end;
+ int ox_end = out_end;
+ if (pitchstep == 0f) {
+ while (ix < ix_end && ox < ox_end) {
+ int iix = (int) ix;
+ float fix = ix - iix;
+ float i = in[iix];
+ out[ox++] = i + (in[iix + 1] - i) * fix;
+ ix += pitch;
+ }
+ } else {
+ while (ix < ix_end && ox < ox_end) {
+ int iix = (int) ix;
+ float fix = ix - iix;
+ float i = in[iix];
+ out[ox++] = i + (in[iix + 1] - i) * fix;
+ ix += pitch;
+ pitch += pitchstep;
+ }
+ }
+ in_offset[0] = ix;
+ out_offset[0] = ox;
+ startpitch[0] = pitch;
+
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SoftLinearResampler2.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SoftLinearResampler2.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.media.sound;
+
+/**
+ * A resampler that uses first-order (linear) interpolation.
+ *
+ * This one doesn't perform float to int casting inside the processing loop.
+ *
+ * @author Karl Helgason
+ */
+public class SoftLinearResampler2 extends SoftAbstractResampler {
+
+ public int getPadding() {
+ return 2;
+ }
+
+ public void interpolate(float[] in, float[] in_offset, float in_end,
+ float[] startpitch, float pitchstep, float[] out, int[] out_offset,
+ int out_end) {
+
+ float pitch = startpitch[0];
+ float ix = in_offset[0];
+ int ox = out_offset[0];
+ float ix_end = in_end;
+ int ox_end = out_end;
+
+ // Check if we have do anything
+ if (!(ix < ix_end && ox < ox_end))
+ return;
+
+ // 15 bit shift was choosed because
+ // it resulted in no drift between p_ix and ix.
+ int p_ix = (int) (ix * (1 << 15));
+ int p_ix_end = (int) (ix_end * (1 << 15));
+ int p_pitch = (int) (pitch * (1 << 15));
+ // Pitch needs to recalculated
+ // to ensure no drift between p_ix and ix.
+ pitch = p_pitch * (1f / (1 << 15));
+
+ if (pitchstep == 0f) {
+
+ // To reduce
+ // while (p_ix < p_ix_end && ox < ox_end)
+ // into
+ // while (ox < ox_end)
+ // We need to calculate new ox_end value.
+ int p_ix_len = p_ix_end - p_ix;
+ int p_mod = p_ix_len % p_pitch;
+ if (p_mod != 0)
+ p_ix_len += p_pitch - p_mod;
+ int ox_end2 = ox + p_ix_len / p_pitch;
+ if (ox_end2 < ox_end)
+ ox_end = ox_end2;
+
+ while (ox < ox_end) {
+ int iix = p_ix >> 15;
+ float fix = ix - iix;
+ float i = in[iix];
+ out[ox++] = i + (in[iix + 1] - i) * fix;
+ p_ix += p_pitch;
+ ix += pitch;
+ }
+
+ } else {
+
+ int p_pitchstep = (int) (pitchstep * (1 << 15));
+ pitchstep = p_pitchstep * (1f / (1 << 15));
+
+ while (p_ix < p_ix_end && ox < ox_end) {
+ int iix = p_ix >> 15;
+ float fix = ix - iix;
+ float i = in[iix];
+ out[ox++] = i + (in[iix + 1] - i) * fix;
+ ix += pitch;
+ p_ix += p_pitch;
+ pitch += pitchstep;
+ p_pitch += p_pitchstep;
+ }
+ }
+ in_offset[0] = ix;
+ out_offset[0] = ox;
+ startpitch[0] = pitch;
+
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SoftLowFrequencyOscillator.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SoftLowFrequencyOscillator.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.media.sound;
+
+/**
+ * LFO control signal generator.
+ *
+ * @author Karl Helgason
+ */
+public class SoftLowFrequencyOscillator implements SoftProcess {
+
+ private int max_count = 10;
+ private int used_count = 0;
+ private double[][] out = new double[max_count][1];
+ private double[][] delay = new double[max_count][1];
+ private double[][] delay2 = new double[max_count][1];
+ private double[][] freq = new double[max_count][1];
+ private int[] delay_counter = new int[max_count];
+ private double[] sin_phase = new double[max_count];
+ private double[] sin_stepfreq = new double[max_count];
+ private double[] sin_step = new double[max_count];
+ private double control_time = 0;
+ private double sin_factor = 0;
+ private static double PI2 = 2.0 * Math.PI;
+
+ public void reset() {
+ for (int i = 0; i < used_count; i++) {
+ out[i][0] = 0;
+ delay[i][0] = 0;
+ delay2[i][0] = 0;
+ freq[i][0] = 0;
+ delay_counter[i] = 0;
+ sin_phase[i] = 0;
+ sin_stepfreq[i] = 0;
+ sin_step[i] = 0;
+ }
+ used_count = 0;
+ }
+
+ public void init(SoftSynthesizer synth) {
+ control_time = 1.0 / synth.getControlRate();
+ sin_factor = control_time * 2 * Math.PI;
+ for (int i = 0; i < used_count; i++) {
+ delay_counter[i] = (int)(Math.pow(2,
+ this.delay[i][0] / 1200.0) / control_time);
+ delay_counter[i] += (int)(delay2[i][0] / (control_time * 1000));
+ }
+ processControlLogic();
+ }
+
+ public void processControlLogic() {
+ for (int i = 0; i < used_count; i++) {
+ if (delay_counter[i] > 0) {
+ delay_counter[i]--;
+ out[i][0] = 0.5;
+ } else {
+ double f = freq[i][0];
+
+ if (sin_stepfreq[i] != f) {
+ sin_stepfreq[i] = f;
+ double fr = 440.0 * Math.exp(
+ (f - 6900.0) * (Math.log(2) / 1200.0));
+ sin_step[i] = fr * sin_factor;
+ }
+ /*
+ double fr = 440.0 * Math.pow(2.0,
+ (freq[i][0] - 6900.0) / 1200.0);
+ sin_phase[i] += fr * sin_factor;
+ */
+ /*
+ sin_phase[i] += sin_step[i];
+ while (sin_phase[i] > PI2)
+ sin_phase[i] -= PI2;
+ out[i][0] = 0.5 + Math.sin(sin_phase[i]) * 0.5;
+ */
+ double p = sin_phase[i];
+ p += sin_step[i];
+ while (p > PI2)
+ p -= PI2;
+ out[i][0] = 0.5 + Math.sin(p) * 0.5;
+ sin_phase[i] = p;
+
+ }
+ }
+ }
+
+ public double[] get(int instance, String name) {
+ if (instance >= used_count)
+ used_count = instance + 1;
+ if (name == null)
+ return out[instance];
+ if (name.equals("delay"))
+ return delay[instance];
+ if (name.equals("delay2"))
+ return delay2[instance];
+ if (name.equals("freq"))
+ return freq[instance];
+ return null;
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SoftMainMixer.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SoftMainMixer.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,982 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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.Arrays;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.Map.Entry;
+
+import javax.sound.midi.MidiMessage;
+import javax.sound.midi.Patch;
+import javax.sound.midi.ShortMessage;
+import javax.sound.sampled.AudioInputStream;
+import javax.sound.sampled.AudioSystem;
+
+/**
+ * Software synthesizer main audio mixer.
+ *
+ * @author Karl Helgason
+ */
+public class SoftMainMixer {
+
+ public final static int CHANNEL_LEFT = 0;
+ public final static int CHANNEL_RIGHT = 1;
+ public final static int CHANNEL_EFFECT1 = 2;
+ public final static int CHANNEL_EFFECT2 = 3;
+ public final static int CHANNEL_EFFECT3 = 4;
+ public final static int CHANNEL_EFFECT4 = 5;
+ public final static int CHANNEL_LEFT_DRY = 10;
+ public final static int CHANNEL_RIGHT_DRY = 11;
+ public final static int CHANNEL_SCRATCH1 = 12;
+ public final static int CHANNEL_SCRATCH2 = 13;
+ public final static int CHANNEL_CHANNELMIXER_LEFT = 14;
+ public final static int CHANNEL_CHANNELMIXER_RIGHT = 15;
+ protected boolean active_sensing_on = false;
+ private long msec_last_activity = -1;
+ private boolean pusher_silent = false;
+ private int pusher_silent_count = 0;
+ private long msec_pos = 0;
+ protected boolean readfully = true;
+ private Object control_mutex;
+ private SoftSynthesizer synth;
+ private int nrofchannels = 2;
+ private SoftVoice[] voicestatus = null;
+ private SoftAudioBuffer[] buffers;
+ private SoftReverb reverb;
+ private SoftAudioProcessor chorus;
+ private SoftAudioProcessor agc;
+ private long msec_buffer_len = 0;
+ protected TreeMap midimessages = new TreeMap();
+ double last_volume_left = 1.0;
+ double last_volume_right = 1.0;
+ private double[] co_master_balance = new double[1];
+ private double[] co_master_volume = new double[1];
+ private double[] co_master_coarse_tuning = new double[1];
+ private double[] co_master_fine_tuning = new double[1];
+ private AudioInputStream ais;
+ private Set registeredMixers = null;
+ private Set stoppedMixers = null;
+ private ModelChannelMixer[] cur_registeredMixers = null;
+ protected SoftControl co_master = new SoftControl() {
+
+ double[] balance = co_master_balance;
+ double[] volume = co_master_volume;
+ double[] coarse_tuning = co_master_coarse_tuning;
+ double[] fine_tuning = co_master_fine_tuning;
+
+ public double[] get(int instance, String name) {
+ if (name == null)
+ return null;
+ if (name.equals("balance"))
+ return balance;
+ if (name.equals("volume"))
+ return volume;
+ if (name.equals("coarse_tuning"))
+ return coarse_tuning;
+ if (name.equals("fine_tuning"))
+ return fine_tuning;
+ return null;
+ }
+ };
+
+ private void processSystemExclusiveMessage(byte[] data) {
+ synchronized (synth.control_mutex) {
+ activity();
+
+ // Universal Non-Real-Time SysEx
+ if ((data[1] & 0xFF) == 0x7E) {
+ int deviceID = data[2] & 0xFF;
+ if (deviceID == 0x7F || deviceID == synth.getDeviceID()) {
+ int subid1 = data[3] & 0xFF;
+ int subid2;
+ switch (subid1) {
+ case 0x08: // MIDI Tuning Standard
+ subid2 = data[4] & 0xFF;
+ switch (subid2) {
+ case 0x01: // BULK TUNING DUMP
+ {
+ // http://www.midi.org/about-midi/tuning.shtml
+ SoftTuning tuning = synth.getTuning(new Patch(0,
+ data[5] & 0xFF));
+ tuning.load(data);
+ break;
+ }
+ case 0x04: // KEY-BASED TUNING DUMP
+ case 0x05: // SCALE/OCTAVE TUNING DUMP, 1 byte format
+ case 0x06: // SCALE/OCTAVE TUNING DUMP, 2 byte format
+ case 0x07: // SINGLE NOTE TUNING CHANGE (NON REAL-TIME)
+ // (BANK)
+ {
+ // http://www.midi.org/about-midi/tuning_extens.shtml
+ SoftTuning tuning = synth.getTuning(new Patch(
+ data[5] & 0xFF, data[6] & 0xFF));
+ tuning.load(data);
+ break;
+ }
+ case 0x08: // scale/octave tuning 1-byte form (Non
+ // Real-Time)
+ case 0x09: // scale/octave tuning 2-byte form (Non
+ // Real-Time)
+ {
+ // http://www.midi.org/about-midi/tuning-scale.shtml
+ SoftTuning tuning = new SoftTuning(data);
+ int channelmask = (data[5] & 0xFF) * 16384
+ + (data[6] & 0xFF) * 128 + (data[7] & 0xFF);
+ SoftChannel[] channels = synth.channels;
+ for (int i = 0; i < channels.length; i++)
+ if ((channelmask & (1 << i)) != 0)
+ channels[i].tuning = tuning;
+ break;
+ }
+ default:
+ break;
+ }
+ break;
+ case 0x09: // General Midi Message
+ subid2 = data[4] & 0xFF;
+ switch (subid2) {
+ case 0x01: // General Midi 1 On
+ synth.setGeneralMidiMode(1);
+ reset();
+ break;
+ case 0x02: // General Midi Off
+ synth.setGeneralMidiMode(0);
+ reset();
+ break;
+ case 0x03: // General MidI Level 2 On
+ synth.setGeneralMidiMode(2);
+ reset();
+ break;
+ default:
+ break;
+ }
+ break;
+ case 0x0A: // DLS Message
+ subid2 = data[4] & 0xFF;
+ switch (subid2) {
+ case 0x01: // DLS On
+ if (synth.getGeneralMidiMode() == 0)
+ synth.setGeneralMidiMode(1);
+ synth.voice_allocation_mode = 1;
+ reset();
+ break;
+ case 0x02: // DLS Off
+ synth.setGeneralMidiMode(0);
+ synth.voice_allocation_mode = 0;
+ reset();
+ break;
+ case 0x03: // DLS Static Voice Allocation Off
+ synth.voice_allocation_mode = 0;
+ break;
+ case 0x04: // DLS Static Voice Allocation On
+ synth.voice_allocation_mode = 1;
+ break;
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ // Universal Real-Time SysEx
+ if ((data[1] & 0xFF) == 0x7F) {
+ int deviceID = data[2] & 0xFF;
+ if (deviceID == 0x7F || deviceID == synth.getDeviceID()) {
+ int subid1 = data[3] & 0xFF;
+ int subid2;
+ switch (subid1) {
+ case 0x04: // Device Control
+
+ subid2 = data[4] & 0xFF;
+ switch (subid2) {
+ case 0x01: // Master Volume
+ case 0x02: // Master Balane
+ case 0x03: // Master fine tuning
+ case 0x04: // Master coarse tuning
+ int val = (data[5] & 0x7F)
+ + ((data[6] & 0x7F) * 128);
+ if (subid2 == 0x01)
+ setVolume(val);
+ else if (subid2 == 0x02)
+ setBalance(val);
+ else if (subid2 == 0x03)
+ setFineTuning(val);
+ else if (subid2 == 0x04)
+ setCoarseTuning(val);
+ break;
+ case 0x05: // Global Parameter Control
+ int ix = 5;
+ int slotPathLen = (data[ix++] & 0xFF);
+ int paramWidth = (data[ix++] & 0xFF);
+ int valueWidth = (data[ix++] & 0xFF);
+ int[] slotPath = new int[slotPathLen];
+ for (int i = 0; i < slotPathLen; i++) {
+ int msb = (data[ix++] & 0xFF);
+ int lsb = (data[ix++] & 0xFF);
+ slotPath[i] = msb * 128 + lsb;
+ }
+ int paramCount = (data.length - 1 - ix)
+ / (paramWidth + valueWidth);
+ long[] params = new long[paramCount];
+ long[] values = new long[paramCount];
+ for (int i = 0; i < paramCount; i++) {
+ values[i] = 0;
+ for (int j = 0; j < paramWidth; j++)
+ params[i] = params[i] * 128
+ + (data[ix++] & 0xFF);
+ for (int j = 0; j < valueWidth; j++)
+ values[i] = values[i] * 128
+ + (data[ix++] & 0xFF);
+
+ }
+ globalParameterControlChange(slotPath, params, values);
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case 0x08: // MIDI Tuning Standard
+ subid2 = data[4] & 0xFF;
+ switch (subid2) {
+ case 0x02: // SINGLE NOTE TUNING CHANGE (REAL-TIME)
+ {
+ // http://www.midi.org/about-midi/tuning.shtml
+ SoftTuning tuning = synth.getTuning(new Patch(0,
+ data[5] & 0xFF));
+ tuning.load(data);
+ SoftVoice[] voices = synth.getVoices();
+ for (int i = 0; i < voices.length; i++)
+ if (voices[i].active)
+ if (voices[i].tuning == tuning)
+ voices[i].updateTuning(tuning);
+ break;
+ }
+ case 0x07: // SINGLE NOTE TUNING CHANGE (REAL-TIME)
+ // (BANK)
+ {
+ // http://www.midi.org/about-midi/tuning_extens.shtml
+ SoftTuning tuning = synth.getTuning(new Patch(
+ data[5] & 0xFF, data[6] & 0xFF));
+ tuning.load(data);
+ SoftVoice[] voices = synth.getVoices();
+ for (int i = 0; i < voices.length; i++)
+ if (voices[i].active)
+ if (voices[i].tuning == tuning)
+ voices[i].updateTuning(tuning);
+ break;
+ }
+ case 0x08: // scale/octave tuning 1-byte form
+ //(Real-Time)
+ case 0x09: // scale/octave tuning 2-byte form
+ // (Real-Time)
+ {
+ // http://www.midi.org/about-midi/tuning-scale.shtml
+ SoftTuning tuning = new SoftTuning(data);
+ int channelmask = (data[5] & 0xFF) * 16384
+ + (data[6] & 0xFF) * 128 + (data[7] & 0xFF);
+ SoftChannel[] channels = synth.channels;
+ for (int i = 0; i < channels.length; i++)
+ if ((channelmask & (1 << i)) != 0)
+ channels[i].tuning = tuning;
+ SoftVoice[] voices = synth.getVoices();
+ for (int i = 0; i < voices.length; i++)
+ if (voices[i].active)
+ if ((channelmask & (1 << (voices[i].channel))) != 0)
+ voices[i].updateTuning(tuning);
+ break;
+ }
+ default:
+ break;
+ }
+ break;
+ case 0x09: // Control Destination Settings
+ subid2 = data[4] & 0xFF;
+ switch (subid2) {
+ case 0x01: // Channel Pressure
+ {
+ int[] destinations = new int[(data.length - 7) / 2];
+ int[] ranges = new int[(data.length - 7) / 2];
+ int ix = 0;
+ for (int j = 6; j < data.length - 1; j += 2) {
+ destinations[ix] = data[j] & 0xFF;
+ ranges[ix] = data[j + 1] & 0xFF;
+ ix++;
+ }
+ int channel = data[5] & 0xFF;
+ SoftChannel softchannel = synth.channels[channel];
+ softchannel.mapChannelPressureToDestination(
+ destinations, ranges);
+ break;
+ }
+ case 0x02: // Poly Pressure
+ {
+ int[] destinations = new int[(data.length - 7) / 2];
+ int[] ranges = new int[(data.length - 7) / 2];
+ int ix = 0;
+ for (int j = 6; j < data.length - 1; j += 2) {
+ destinations[ix] = data[j] & 0xFF;
+ ranges[ix] = data[j + 1] & 0xFF;
+ ix++;
+ }
+ int channel = data[5] & 0xFF;
+ SoftChannel softchannel = synth.channels[channel];
+ softchannel.mapPolyPressureToDestination(
+ destinations, ranges);
+ break;
+ }
+ case 0x03: // Control Change
+ {
+ int[] destinations = new int[(data.length - 7) / 2];
+ int[] ranges = new int[(data.length - 7) / 2];
+ int ix = 0;
+ for (int j = 7; j < data.length - 1; j += 2) {
+ destinations[ix] = data[j] & 0xFF;
+ ranges[ix] = data[j + 1] & 0xFF;
+ ix++;
+ }
+ int channel = data[5] & 0xFF;
+ SoftChannel softchannel = synth.channels[channel];
+ int control = data[6] & 0xFF;
+ softchannel.mapControlToDestination(control,
+ destinations, ranges);
+ break;
+ }
+ default:
+ break;
+ }
+ break;
+
+ case 0x0A: // Key Based Instrument Control
+ {
+ subid2 = data[4] & 0xFF;
+ switch (subid2) {
+ case 0x01: // Basic Message
+ int channel = data[5] & 0xFF;
+ int keynumber = data[6] & 0xFF;
+ SoftChannel softchannel = synth.channels[channel];
+ for (int j = 7; j < data.length - 1; j += 2) {
+ int controlnumber = data[j] & 0xFF;
+ int controlvalue = data[j + 1] & 0xFF;
+ softchannel.controlChangePerNote(keynumber,
+ controlnumber, controlvalue);
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+
+ }
+ }
+
+ private void processMessages(long timeStamp) {
+ Iterator> iter = midimessages.entrySet().iterator();
+ while (iter.hasNext()) {
+ Entry entry = iter.next();
+ if (entry.getKey() > (timeStamp + 100))
+ return;
+ processMessage(entry.getValue());
+ iter.remove();
+ }
+ }
+
+ protected void processAudioBuffers() {
+ for (int i = 0; i < buffers.length; i++) {
+ buffers[i].clear();
+ }
+
+ double volume_left;
+ double volume_right;
+
+ ModelChannelMixer[] act_registeredMixers;
+
+ // perform control logic
+ synchronized (control_mutex) {
+
+ processMessages(msec_pos);
+
+ if (active_sensing_on) {
+ // Active Sensing
+ // if no message occurs for max 1000 ms
+ // then do AllSoundOff on all channels
+ if ((msec_pos - msec_last_activity) > 1000000) {
+ active_sensing_on = false;
+ for (SoftChannel c : synth.channels)
+ c.allSoundOff();
+ }
+
+ }
+
+ for (int i = 0; i < voicestatus.length; i++)
+ if (voicestatus[i].active)
+ voicestatus[i].processControlLogic();
+ msec_pos += msec_buffer_len;
+
+ double volume = co_master_volume[0];
+ volume_left = volume;
+ volume_right = volume;
+
+ double balance = co_master_balance[0];
+ if (balance > 0.5)
+ volume_left *= (1 - balance) * 2;
+ else
+ volume_right *= balance * 2;
+
+ chorus.processControlLogic();
+ reverb.processControlLogic();
+ agc.processControlLogic();
+
+ if (cur_registeredMixers == null) {
+ if (registeredMixers != null) {
+ cur_registeredMixers =
+ new ModelChannelMixer[registeredMixers.size()];
+ registeredMixers.toArray(cur_registeredMixers);
+ }
+ }
+
+ act_registeredMixers = cur_registeredMixers;
+ if (act_registeredMixers != null)
+ if (act_registeredMixers.length == 0)
+ act_registeredMixers = null;
+
+ }
+
+ if (act_registeredMixers != null) {
+
+ // Reroute default left,right output
+ // to channelmixer left,right input/output
+ SoftAudioBuffer leftbak = buffers[CHANNEL_LEFT];
+ SoftAudioBuffer rightbak = buffers[CHANNEL_RIGHT];
+ buffers[CHANNEL_LEFT] = buffers[CHANNEL_CHANNELMIXER_LEFT];
+ buffers[CHANNEL_RIGHT] = buffers[CHANNEL_CHANNELMIXER_LEFT];
+
+ int bufferlen = buffers[CHANNEL_LEFT].getSize();
+
+ float[][] cbuffer = new float[nrofchannels][];
+ cbuffer[0] = buffers[CHANNEL_LEFT].array();
+ if (nrofchannels != 1)
+ cbuffer[1] = buffers[CHANNEL_RIGHT].array();
+
+ float[][] obuffer = new float[nrofchannels][];
+ obuffer[0] = leftbak.array();
+ if (nrofchannels != 1)
+ obuffer[1] = rightbak.array();
+
+ for (ModelChannelMixer cmixer : act_registeredMixers) {
+ for (int i = 0; i < cbuffer.length; i++)
+ Arrays.fill(cbuffer[i], 0);
+ boolean hasactivevoices = false;
+ for (int i = 0; i < voicestatus.length; i++)
+ if (voicestatus[i].active)
+ if (voicestatus[i].channelmixer == cmixer) {
+ voicestatus[i].processAudioLogic(buffers);
+ hasactivevoices = true;
+ }
+ if (!cmixer.process(cbuffer, 0, bufferlen)) {
+ synchronized (control_mutex) {
+ registeredMixers.remove(cmixer);
+ cur_registeredMixers = null;
+ }
+ }
+
+ for (int i = 0; i < cbuffer.length; i++) {
+ float[] cbuff = cbuffer[i];
+ float[] obuff = obuffer[i];
+ for (int j = 0; j < bufferlen; j++)
+ obuff[j] += cbuff[j];
+ }
+
+ if (!hasactivevoices) {
+ synchronized (control_mutex) {
+ if (stoppedMixers != null) {
+ if (stoppedMixers.contains(cmixer)) {
+ stoppedMixers.remove(cmixer);
+ cmixer.stop();
+ }
+ }
+ }
+ }
+
+ }
+
+ buffers[CHANNEL_LEFT] = leftbak;
+ buffers[CHANNEL_RIGHT] = rightbak;
+
+ }
+
+ for (int i = 0; i < voicestatus.length; i++)
+ if (voicestatus[i].active)
+ if (voicestatus[i].channelmixer == null)
+ voicestatus[i].processAudioLogic(buffers);
+
+ // Run effects
+ if (synth.chorus_on)
+ chorus.processAudio();
+
+ if (synth.reverb_on)
+ reverb.processAudio();
+
+ if (nrofchannels == 1)
+ volume_left = (volume_left + volume_right) / 2;
+
+ // Set Volume / Balance
+ if (last_volume_left != volume_left || last_volume_right != volume_right) {
+ float[] left = buffers[CHANNEL_LEFT].array();
+ float[] right = buffers[CHANNEL_RIGHT].array();
+ int bufferlen = buffers[CHANNEL_LEFT].getSize();
+
+ float amp;
+ float amp_delta;
+ amp = (float)(last_volume_left * last_volume_left);
+ amp_delta = (float)((volume_left * volume_left - amp) / bufferlen);
+ for (int i = 0; i < bufferlen; i++) {
+ amp += amp_delta;
+ left[i] *= amp;
+ }
+ if (nrofchannels != 1) {
+ amp = (float)(last_volume_right * last_volume_right);
+ amp_delta = (float)((volume_right*volume_right - amp) / bufferlen);
+ for (int i = 0; i < bufferlen; i++) {
+ amp += amp_delta;
+ right[i] *= volume_right;
+ }
+ }
+ last_volume_left = volume_left;
+ last_volume_right = volume_right;
+
+ } else {
+ if (volume_left != 1.0 || volume_right != 1.0) {
+ float[] left = buffers[CHANNEL_LEFT].array();
+ float[] right = buffers[CHANNEL_RIGHT].array();
+ int bufferlen = buffers[CHANNEL_LEFT].getSize();
+ float amp;
+ amp = (float) (volume_left * volume_left);
+ for (int i = 0; i < bufferlen; i++)
+ left[i] *= amp;
+ if (nrofchannels != 1) {
+ amp = (float)(volume_right * volume_right);
+ for (int i = 0; i < bufferlen; i++)
+ right[i] *= amp;
+ }
+
+ }
+ }
+
+ if(buffers[CHANNEL_LEFT].isSilent()
+ && buffers[CHANNEL_RIGHT].isSilent())
+ {
+ pusher_silent_count++;
+ if(pusher_silent_count > 5)
+ {
+ pusher_silent_count = 0;
+ synchronized (control_mutex) {
+ pusher_silent = true;
+ if(synth.weakstream != null)
+ synth.weakstream.setInputStream(null);
+ }
+ }
+ }
+ else
+ pusher_silent_count = 0;
+
+ if (synth.agc_on)
+ agc.processAudio();
+
+ }
+
+ // Must only we called within control_mutex synchronization
+ public void activity()
+ {
+ msec_last_activity = msec_pos;
+ if(pusher_silent)
+ {
+ pusher_silent = false;
+ if(synth.weakstream != null)
+ synth.weakstream.setInputStream(ais);
+ }
+ }
+
+ public void stopMixer(ModelChannelMixer mixer) {
+ if (stoppedMixers == null)
+ stoppedMixers = new HashSet();
+ stoppedMixers.add(mixer);
+ }
+
+ public void registerMixer(ModelChannelMixer mixer) {
+ if (registeredMixers == null)
+ registeredMixers = new HashSet();
+ registeredMixers.add(mixer);
+ cur_registeredMixers = null;
+ }
+
+ public SoftMainMixer(SoftSynthesizer synth) {
+ this.synth = synth;
+
+ msec_pos = 0;
+
+ co_master_balance[0] = 0.5;
+ co_master_volume[0] = 1;
+ co_master_coarse_tuning[0] = 0.5;
+ co_master_fine_tuning[0] = 0.5;
+
+ msec_buffer_len = (long) (1000000.0 / synth.getControlRate());
+
+ nrofchannels = synth.getFormat().getChannels();
+
+ int buffersize = (int) (synth.getFormat().getSampleRate()
+ / synth.getControlRate());
+
+ control_mutex = synth.control_mutex;
+ buffers = new SoftAudioBuffer[16];
+ for (int i = 0; i < buffers.length; i++) {
+ buffers[i] = new SoftAudioBuffer(buffersize, synth.getFormat());
+ }
+ voicestatus = synth.getVoices();
+
+ reverb = new SoftReverb();
+ chorus = new SoftChorus();
+ agc = new SoftLimiter();
+
+ float samplerate = synth.getFormat().getSampleRate();
+ float controlrate = synth.getControlRate();
+ reverb.init(samplerate, controlrate);
+ chorus.init(samplerate, controlrate);
+ agc.init(samplerate, controlrate);
+
+ reverb.setLightMode(synth.reverb_light);
+
+ reverb.setMixMode(true);
+ chorus.setMixMode(true);
+ agc.setMixMode(false);
+
+ chorus.setInput(0, buffers[CHANNEL_EFFECT2]);
+ chorus.setOutput(0, buffers[CHANNEL_LEFT]);
+ if (nrofchannels != 1)
+ chorus.setOutput(1, buffers[CHANNEL_RIGHT]);
+ chorus.setOutput(2, buffers[CHANNEL_EFFECT1]);
+
+ reverb.setInput(0, buffers[CHANNEL_EFFECT1]);
+ reverb.setOutput(0, buffers[CHANNEL_LEFT]);
+ if (nrofchannels != 1)
+ reverb.setOutput(1, buffers[CHANNEL_RIGHT]);
+
+ agc.setInput(0, buffers[CHANNEL_LEFT]);
+ if (nrofchannels != 1)
+ agc.setInput(1, buffers[CHANNEL_RIGHT]);
+ agc.setOutput(0, buffers[CHANNEL_LEFT]);
+ if (nrofchannels != 1)
+ agc.setOutput(1, buffers[CHANNEL_RIGHT]);
+
+ InputStream in = new InputStream() {
+
+ private SoftAudioBuffer[] buffers = SoftMainMixer.this.buffers;
+ private int nrofchannels
+ = SoftMainMixer.this.synth.getFormat().getChannels();
+ private int buffersize = buffers[0].getSize();
+ private byte[] bbuffer = new byte[buffersize
+ * (SoftMainMixer.this.synth.getFormat()
+ .getSampleSizeInBits() / 8)
+ * nrofchannels];
+ private int bbuffer_pos = 0;
+ private byte[] single = new byte[1];
+
+ public void fillBuffer() {
+ /*
+ boolean pusher_silent2;
+ synchronized (control_mutex) {
+ pusher_silent2 = pusher_silent;
+ }
+ if(!pusher_silent2)*/
+ processAudioBuffers();
+ for (int i = 0; i < nrofchannels; i++)
+ buffers[i].get(bbuffer, i);
+ bbuffer_pos = 0;
+ }
+
+ public int read(byte[] b, int off, int len) {
+ int bbuffer_len = bbuffer.length;
+ int offlen = off + len;
+ int orgoff = off;
+ byte[] bbuffer = this.bbuffer;
+ while (off < offlen) {
+ if (available() == 0)
+ fillBuffer();
+ else {
+ int bbuffer_pos = this.bbuffer_pos;
+ while (off < offlen && bbuffer_pos < bbuffer_len)
+ b[off++] = bbuffer[bbuffer_pos++];
+ this.bbuffer_pos = bbuffer_pos;
+ if (!readfully)
+ return off - orgoff;
+ }
+ }
+ return len;
+ }
+
+ public int read() throws IOException {
+ int ret = read(single);
+ if (ret == -1)
+ return -1;
+ return single[0] & 0xFF;
+ }
+
+ public int available() {
+ return bbuffer.length - bbuffer_pos;
+ }
+
+ public void close() {
+ SoftMainMixer.this.synth.close();
+ }
+ };
+
+ ais = new AudioInputStream(in, synth.getFormat(), AudioSystem.NOT_SPECIFIED);
+
+ }
+
+ public AudioInputStream getInputStream() {
+ return ais;
+ }
+
+ public void reset() {
+
+ SoftChannel[] channels = synth.channels;
+ for (int i = 0; i < channels.length; i++) {
+ channels[i].allSoundOff();
+ channels[i].resetAllControllers(true);
+
+ if (synth.getGeneralMidiMode() == 2) {
+ if (i == 9)
+ channels[i].programChange(0, 0x78 * 128);
+ else
+ channels[i].programChange(0, 0x79 * 128);
+ } else
+ channels[i].programChange(0, 0);
+ }
+ setVolume(0x7F * 128 + 0x7F);
+ setBalance(0x40 * 128 + 0x00);
+ setCoarseTuning(0x40 * 128 + 0x00);
+ setFineTuning(0x40 * 128 + 0x00);
+ // Reset Reverb
+ globalParameterControlChange(
+ new int[]{0x01 * 128 + 0x01}, new long[]{0}, new long[]{4});
+ // Reset Chorus
+ globalParameterControlChange(
+ new int[]{0x01 * 128 + 0x02}, new long[]{0}, new long[]{2});
+ }
+
+ public void setVolume(int value) {
+ synchronized (control_mutex) {
+ co_master_volume[0] = value / 16384.0;
+ }
+ }
+
+ public void setBalance(int value) {
+ synchronized (control_mutex) {
+ co_master_balance[0] = value / 16384.0;
+ }
+ }
+
+ public void setFineTuning(int value) {
+ synchronized (control_mutex) {
+ co_master_fine_tuning[0] = value / 16384.0;
+ }
+ }
+
+ public void setCoarseTuning(int value) {
+ synchronized (control_mutex) {
+ co_master_coarse_tuning[0] = value / 16384.0;
+ }
+ }
+
+ public int getVolume() {
+ synchronized (control_mutex) {
+ return (int) (co_master_volume[0] * 16384.0);
+ }
+ }
+
+ public int getBalance() {
+ synchronized (control_mutex) {
+ return (int) (co_master_balance[0] * 16384.0);
+ }
+ }
+
+ public int getFineTuning() {
+ synchronized (control_mutex) {
+ return (int) (co_master_fine_tuning[0] * 16384.0);
+ }
+ }
+
+ public int getCoarseTuning() {
+ synchronized (control_mutex) {
+ return (int) (co_master_coarse_tuning[0] * 16384.0);
+ }
+ }
+
+ public void globalParameterControlChange(int[] slothpath, long[] params,
+ long[] paramsvalue) {
+ if (slothpath.length == 0)
+ return;
+
+ synchronized (control_mutex) {
+
+ // slothpath: 01xx are reserved only for GM2
+
+ if (slothpath[0] == 0x01 * 128 + 0x01) {
+ for (int i = 0; i < paramsvalue.length; i++) {
+ reverb.globalParameterControlChange(slothpath, params[i],
+ paramsvalue[i]);
+ }
+ }
+ if (slothpath[0] == 0x01 * 128 + 0x02) {
+ for (int i = 0; i < paramsvalue.length; i++) {
+ chorus.globalParameterControlChange(slothpath, params[i],
+ paramsvalue[i]);
+ }
+
+ }
+
+ }
+ }
+
+ public void processMessage(Object object) {
+ if (object instanceof byte[])
+ processMessage((byte[]) object);
+ if (object instanceof MidiMessage)
+ processMessage((MidiMessage)object);
+ }
+
+ public void processMessage(MidiMessage message) {
+ if (message instanceof ShortMessage) {
+ ShortMessage sms = (ShortMessage)message;
+ processMessage(sms.getChannel(), sms.getCommand(),
+ sms.getData1(), sms.getData2());
+ return;
+ }
+ processMessage(message.getMessage());
+ }
+
+ public void processMessage(byte[] data) {
+ int status = 0;
+ if (data.length > 0)
+ status = data[0] & 0xFF;
+
+ if (status == 0xF0) {
+ processSystemExclusiveMessage(data);
+ return;
+ }
+
+ int cmd = (status & 0xF0);
+ int ch = (status & 0x0F);
+
+ int data1;
+ int data2;
+ if (data.length > 1)
+ data1 = data[1] & 0xFF;
+ else
+ data1 = 0;
+ if (data.length > 2)
+ data2 = data[2] & 0xFF;
+ else
+ data2 = 0;
+
+ processMessage(ch, cmd, data1, data2);
+
+ }
+
+ public void processMessage(int ch, int cmd, int data1, int data2) {
+ synchronized (synth.control_mutex) {
+ activity();
+ }
+
+ if (cmd == 0xF0) {
+ int status = cmd | ch;
+ switch (status) {
+ case ShortMessage.ACTIVE_SENSING:
+ synchronized (synth.control_mutex) {
+ active_sensing_on = true;
+ }
+ break;
+ default:
+ break;
+ }
+ return;
+ }
+
+ SoftChannel[] channels = synth.channels;
+ if (ch >= channels.length)
+ return;
+ SoftChannel softchannel = channels[ch];
+
+ switch (cmd) {
+ case ShortMessage.NOTE_ON:
+ softchannel.noteOn(data1, data2);
+ break;
+ case ShortMessage.NOTE_OFF:
+ softchannel.noteOff(data1, data2);
+ break;
+ case ShortMessage.POLY_PRESSURE:
+ softchannel.setPolyPressure(data1, data2);
+ break;
+ case ShortMessage.CONTROL_CHANGE:
+ softchannel.controlChange(data1, data2);
+ break;
+ case ShortMessage.PROGRAM_CHANGE:
+ softchannel.programChange(data1);
+ break;
+ case ShortMessage.CHANNEL_PRESSURE:
+ softchannel.setChannelPressure(data1);
+ break;
+ case ShortMessage.PITCH_BEND:
+ softchannel.setPitchBend(data1 + data2 * 128);
+ break;
+ default:
+ break;
+ }
+
+ }
+
+ public long getMicrosecondPosition() {
+ return msec_pos;
+ }
+
+ public void close() {
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SoftMidiAudioFileReader.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SoftMidiAudioFileReader.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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.MetaMessage;
+import javax.sound.midi.MidiEvent;
+import javax.sound.midi.MidiMessage;
+import javax.sound.midi.MidiSystem;
+import javax.sound.midi.MidiUnavailableException;
+import javax.sound.midi.Receiver;
+import javax.sound.midi.Sequence;
+import javax.sound.midi.Track;
+import javax.sound.sampled.AudioFileFormat;
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.AudioInputStream;
+import javax.sound.sampled.UnsupportedAudioFileException;
+import javax.sound.sampled.AudioFileFormat.Type;
+import javax.sound.sampled.spi.AudioFileReader;
+
+/**
+ * MIDI File Audio Renderer/Reader
+ *
+ * @author Karl Helgason
+ */
+public class SoftMidiAudioFileReader extends AudioFileReader {
+
+ public static final Type MIDI = new Type("MIDI", "mid");
+ private static AudioFormat format = new AudioFormat(44100, 16, 2, true, false);
+
+ public AudioFileFormat getAudioFileFormat(Sequence seq)
+ throws UnsupportedAudioFileException, IOException {
+
+ long totallen = seq.getMicrosecondLength() / 1000000;
+ long len = (long) (format.getFrameRate() * (totallen + 4));
+ return new AudioFileFormat(MIDI, format, (int) len);
+ }
+
+ public AudioInputStream getAudioInputStream(Sequence seq)
+ throws UnsupportedAudioFileException, IOException {
+ AudioSynthesizer synth = (AudioSynthesizer) new SoftSynthesizer();
+ AudioInputStream stream;
+ Receiver recv;
+ try {
+ stream = synth.openStream(format, null);
+ recv = synth.getReceiver();
+ } catch (MidiUnavailableException e) {
+ throw new IOException(e.toString());
+ }
+ float divtype = seq.getDivisionType();
+ Track[] tracks = seq.getTracks();
+ int[] trackspos = new int[tracks.length];
+ int mpq = 500000;
+ int seqres = seq.getResolution();
+ long lasttick = 0;
+ long curtime = 0;
+ while (true) {
+ MidiEvent selevent = null;
+ int seltrack = -1;
+ for (int i = 0; i < tracks.length; i++) {
+ int trackpos = trackspos[i];
+ Track track = tracks[i];
+ if (trackpos < track.size()) {
+ MidiEvent event = track.get(trackpos);
+ if (selevent == null || event.getTick() < selevent.getTick()) {
+ selevent = event;
+ seltrack = i;
+ }
+ }
+ }
+ if (seltrack == -1)
+ break;
+ trackspos[seltrack]++;
+ long tick = selevent.getTick();
+ if (divtype == Sequence.PPQ)
+ curtime += ((tick - lasttick) * mpq) / seqres;
+ else
+ curtime = (long) ((tick * 1000000.0 * divtype) / seqres);
+ lasttick = tick;
+ MidiMessage msg = selevent.getMessage();
+ if (msg instanceof MetaMessage) {
+ if (divtype == Sequence.PPQ) {
+ if (((MetaMessage) msg).getType() == 0x51) {
+ byte[] data = ((MetaMessage) msg).getData();
+ mpq = ((data[0] & 0xff) << 16)
+ | ((data[1] & 0xff) << 8) | (data[2] & 0xff);
+ }
+ }
+ } else {
+ recv.send(msg, curtime);
+ }
+ }
+
+ long totallen = curtime / 1000000;
+ long len = (long) (stream.getFormat().getFrameRate() * (totallen + 4));
+ stream = new AudioInputStream(stream, stream.getFormat(), len);
+ return stream;
+ }
+
+ public AudioInputStream getAudioInputStream(InputStream inputstream)
+ throws UnsupportedAudioFileException, IOException {
+
+ inputstream.mark(200);
+ Sequence seq;
+ try {
+ seq = MidiSystem.getSequence(inputstream);
+ } catch (InvalidMidiDataException e) {
+ inputstream.reset();
+ throw new UnsupportedAudioFileException();
+ } catch (IOException e) {
+ inputstream.reset();
+ throw new UnsupportedAudioFileException();
+ }
+ return getAudioInputStream(seq);
+ }
+
+ public AudioFileFormat getAudioFileFormat(URL url)
+ throws UnsupportedAudioFileException, IOException {
+ Sequence seq;
+ try {
+ seq = MidiSystem.getSequence(url);
+ } catch (InvalidMidiDataException e) {
+ throw new UnsupportedAudioFileException();
+ } catch (IOException e) {
+ throw new UnsupportedAudioFileException();
+ }
+ return getAudioFileFormat(seq);
+ }
+
+ public AudioFileFormat getAudioFileFormat(File file)
+ throws UnsupportedAudioFileException, IOException {
+ Sequence seq;
+ try {
+ seq = MidiSystem.getSequence(file);
+ } catch (InvalidMidiDataException e) {
+ throw new UnsupportedAudioFileException();
+ } catch (IOException e) {
+ throw new UnsupportedAudioFileException();
+ }
+ return getAudioFileFormat(seq);
+ }
+
+ public AudioInputStream getAudioInputStream(URL url)
+ throws UnsupportedAudioFileException, IOException {
+ Sequence seq;
+ try {
+ seq = MidiSystem.getSequence(url);
+ } catch (InvalidMidiDataException e) {
+ throw new UnsupportedAudioFileException();
+ } catch (IOException e) {
+ throw new UnsupportedAudioFileException();
+ }
+ return getAudioInputStream(seq);
+ }
+
+ public AudioInputStream getAudioInputStream(File file)
+ throws UnsupportedAudioFileException, IOException {
+ if (!file.getName().toLowerCase().endsWith(".mid"))
+ throw new UnsupportedAudioFileException();
+ Sequence seq;
+ try {
+ seq = MidiSystem.getSequence(file);
+ } catch (InvalidMidiDataException e) {
+ throw new UnsupportedAudioFileException();
+ } catch (IOException e) {
+ throw new UnsupportedAudioFileException();
+ }
+ return getAudioInputStream(seq);
+ }
+
+ public AudioFileFormat getAudioFileFormat(InputStream inputstream)
+ throws UnsupportedAudioFileException, IOException {
+
+ inputstream.mark(200);
+ Sequence seq;
+ try {
+ seq = MidiSystem.getSequence(inputstream);
+ } catch (InvalidMidiDataException e) {
+ inputstream.reset();
+ throw new UnsupportedAudioFileException();
+ } catch (IOException e) {
+ inputstream.reset();
+ throw new UnsupportedAudioFileException();
+ }
+ return getAudioFileFormat(seq);
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SoftMixingClip.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SoftMixingClip.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,539 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.media.sound;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.AudioInputStream;
+import javax.sound.sampled.AudioSystem;
+import javax.sound.sampled.Clip;
+import javax.sound.sampled.DataLine;
+import javax.sound.sampled.LineEvent;
+import javax.sound.sampled.LineUnavailableException;
+
+/**
+ * Clip implemention for the SoftMixingMixer.
+ *
+ * @author Karl Helgason
+ */
+public class SoftMixingClip extends SoftMixingDataLine implements Clip {
+
+ private AudioFormat format;
+
+ private int framesize;
+
+ private byte[] data;
+
+ private InputStream datastream = new InputStream() {
+
+ 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 {
+
+ if (_loopcount != 0) {
+ int bloopend = _loopend * framesize;
+ int bloopstart = _loopstart * framesize;
+ int pos = _frameposition * framesize;
+
+ if (pos + len >= bloopend)
+ if (pos < bloopend) {
+ int offend = off + len;
+ int o = off;
+ while (off != offend) {
+ if (pos == bloopend) {
+ if (_loopcount == 0)
+ break;
+ pos = bloopstart;
+ if (_loopcount != LOOP_CONTINUOUSLY)
+ _loopcount--;
+ }
+ len = offend - off;
+ int left = bloopend - pos;
+ if (len > left)
+ len = left;
+ System.arraycopy(data, pos, b, off, len);
+ off += len;
+ }
+ if (_loopcount == 0) {
+ len = offend - off;
+ int left = bloopend - pos;
+ if (len > left)
+ len = left;
+ System.arraycopy(data, pos, b, off, len);
+ off += len;
+ }
+ _frameposition = pos / framesize;
+ return o - off;
+ }
+ }
+
+ int pos = _frameposition * framesize;
+ int left = bufferSize - pos;
+ if (left == 0)
+ return -1;
+ if (len > left)
+ len = left;
+ System.arraycopy(data, pos, b, off, len);
+ _frameposition += len / framesize;
+ return len;
+ }
+
+ };
+
+ private int offset;
+
+ private int bufferSize;
+
+ private float[] readbuffer;
+
+ private boolean open = false;
+
+ private AudioFormat outputformat;
+
+ private int out_nrofchannels;
+
+ private int in_nrofchannels;
+
+ private int frameposition = 0;
+
+ private boolean frameposition_sg = false;
+
+ private boolean active_sg = false;
+
+ private int loopstart = 0;
+
+ private int loopend = -1;
+
+ private boolean active = false;
+
+ private int loopcount = 0;
+
+ private boolean _active = false;
+
+ private int _frameposition = 0;
+
+ private boolean loop_sg = false;
+
+ private int _loopcount = 0;
+
+ private int _loopstart = 0;
+
+ private int _loopend = -1;
+
+ private float _rightgain;
+
+ private float _leftgain;
+
+ private float _eff1gain;
+
+ private float _eff2gain;
+
+ private AudioFloatInputStream afis;
+
+ protected SoftMixingClip(SoftMixingMixer mixer, DataLine.Info info) {
+ super(mixer, info);
+ }
+
+ protected void processControlLogic() {
+
+ _rightgain = rightgain;
+ _leftgain = leftgain;
+ _eff1gain = eff1gain;
+ _eff2gain = eff2gain;
+
+ if (active_sg) {
+ _active = active;
+ active_sg = false;
+ } else {
+ active = _active;
+ }
+
+ if (frameposition_sg) {
+ _frameposition = frameposition;
+ frameposition_sg = false;
+ afis = null;
+ } else {
+ frameposition = _frameposition;
+ }
+ if (loop_sg) {
+ _loopcount = loopcount;
+ _loopstart = loopstart;
+ _loopend = loopend;
+ }
+
+ if (afis == null) {
+ afis = AudioFloatInputStream.getInputStream(new AudioInputStream(
+ datastream, format, AudioSystem.NOT_SPECIFIED));
+
+ if (Math.abs(format.getSampleRate() - outputformat.getSampleRate()) > 0.000001)
+ afis = new AudioFloatInputStreamResampler(afis, outputformat);
+ }
+
+ }
+
+ protected void processAudioLogic(SoftAudioBuffer[] buffers) {
+ if (_active) {
+ float[] left = buffers[SoftMixingMainMixer.CHANNEL_LEFT].array();
+ float[] right = buffers[SoftMixingMainMixer.CHANNEL_RIGHT].array();
+ int bufferlen = buffers[SoftMixingMainMixer.CHANNEL_LEFT].getSize();
+
+ int readlen = bufferlen * in_nrofchannels;
+ if (readbuffer == null || readbuffer.length < readlen) {
+ readbuffer = new float[readlen];
+ }
+ int ret = 0;
+ try {
+ ret = afis.read(readbuffer);
+ if (ret == -1) {
+ _active = false;
+ return;
+ }
+ if (ret != in_nrofchannels)
+ Arrays.fill(readbuffer, ret, readlen, 0);
+ } catch (IOException e) {
+ }
+
+ int in_c = in_nrofchannels;
+ for (int i = 0, ix = 0; i < bufferlen; i++, ix += in_c) {
+ left[i] += readbuffer[ix] * _leftgain;
+ }
+
+ if (out_nrofchannels != 1) {
+ if (in_nrofchannels == 1) {
+ for (int i = 0, ix = 0; i < bufferlen; i++, ix += in_c) {
+ right[i] += readbuffer[ix] * _rightgain;
+ }
+ } else {
+ for (int i = 0, ix = 1; i < bufferlen; i++, ix += in_c) {
+ right[i] += readbuffer[ix] * _rightgain;
+ }
+ }
+
+ }
+
+ if (_eff1gain > 0.0002) {
+
+ float[] eff1 = buffers[SoftMixingMainMixer.CHANNEL_EFFECT1]
+ .array();
+ for (int i = 0, ix = 0; i < bufferlen; i++, ix += in_c) {
+ eff1[i] += readbuffer[ix] * _eff1gain;
+ }
+ if (in_nrofchannels == 2) {
+ for (int i = 0, ix = 1; i < bufferlen; i++, ix += in_c) {
+ eff1[i] += readbuffer[ix] * _eff1gain;
+ }
+ }
+ }
+
+ if (_eff2gain > 0.0002) {
+ float[] eff2 = buffers[SoftMixingMainMixer.CHANNEL_EFFECT2]
+ .array();
+ for (int i = 0, ix = 0; i < bufferlen; i++, ix += in_c) {
+ eff2[i] += readbuffer[ix] * _eff2gain;
+ }
+ if (in_nrofchannels == 2) {
+ for (int i = 0, ix = 1; i < bufferlen; i++, ix += in_c) {
+ eff2[i] += readbuffer[ix] * _eff2gain;
+ }
+ }
+ }
+
+ }
+ }
+
+ public int getFrameLength() {
+ return bufferSize / format.getFrameSize();
+ }
+
+ public long getMicrosecondLength() {
+ return (long) (getFrameLength() * (1000000.0 / (double) getFormat()
+ .getSampleRate()));
+ }
+
+ public void loop(int count) {
+ LineEvent event = null;
+
+ synchronized (control_mutex) {
+ if (isOpen()) {
+ if (active)
+ return;
+ active = true;
+ active_sg = true;
+ loopcount = count;
+ event = new LineEvent(this, LineEvent.Type.START,
+ getLongFramePosition());
+ }
+ }
+
+ if (event != null)
+ sendEvent(event);
+
+ }
+
+ public void open(AudioInputStream stream) throws LineUnavailableException,
+ IOException {
+ if (isOpen()) {
+ throw new IllegalStateException("Clip is already open with format "
+ + getFormat() + " and frame lengh of " + getFrameLength());
+ }
+ if (AudioFloatConverter.getConverter(stream.getFormat()) == null)
+ throw new IllegalArgumentException("Invalid format : "
+ + stream.getFormat().toString());
+
+ if (stream.getFrameLength() != AudioSystem.NOT_SPECIFIED) {
+ byte[] data = new byte[(int) stream.getFrameLength()
+ * stream.getFormat().getFrameSize()];
+ int readsize = 512 * stream.getFormat().getFrameSize();
+ int len = 0;
+ while (len != data.length) {
+ if (readsize > data.length - len)
+ readsize = data.length - len;
+ int ret = stream.read(data, len, readsize);
+ if (ret == -1)
+ break;
+ if (ret == 0)
+ Thread.yield();
+ len += ret;
+ }
+ open(stream.getFormat(), data, 0, len);
+ } else {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ byte[] b = new byte[512 * stream.getFormat().getFrameSize()];
+ int r = 0;
+ while ((r = stream.read(b)) != -1) {
+ if (r == 0)
+ Thread.yield();
+ baos.write(b, 0, r);
+ }
+ open(stream.getFormat(), baos.toByteArray(), 0, baos.size());
+ }
+
+ }
+
+ public void open(AudioFormat format, byte[] data, int offset, int bufferSize)
+ throws LineUnavailableException {
+ synchronized (control_mutex) {
+ if (isOpen()) {
+ throw new IllegalStateException(
+ "Clip is already open with format " + getFormat()
+ + " and frame lengh of " + getFrameLength());
+ }
+ if (AudioFloatConverter.getConverter(format) == null)
+ throw new IllegalArgumentException("Invalid format : "
+ + format.toString());
+ if (bufferSize % format.getFrameSize() != 0)
+ throw new IllegalArgumentException(
+ "Buffer size does not represent an integral number of sample frames!");
+
+ this.data = data;
+ this.offset = offset;
+ this.bufferSize = bufferSize;
+ this.format = format;
+ this.framesize = format.getFrameSize();
+
+ loopstart = 0;
+ loopend = -1;
+ loop_sg = true;
+
+ if (!mixer.isOpen()) {
+ mixer.open();
+ mixer.implicitOpen = true;
+ }
+
+ outputformat = mixer.getFormat();
+ out_nrofchannels = outputformat.getChannels();
+ in_nrofchannels = format.getChannels();
+
+ open = true;
+
+ mixer.getMainMixer().openLine(this);
+ }
+
+ }
+
+ public void setFramePosition(int frames) {
+ synchronized (control_mutex) {
+ frameposition_sg = true;
+ frameposition = frames;
+ }
+ }
+
+ public void setLoopPoints(int start, int end) {
+ synchronized (control_mutex) {
+ if (end != -1) {
+ if (end < start)
+ throw new IllegalArgumentException("Invalid loop points : "
+ + start + " - " + end);
+ if (end * framesize > bufferSize)
+ throw new IllegalArgumentException("Invalid loop points : "
+ + start + " - " + end);
+ }
+ if (start * framesize > bufferSize)
+ throw new IllegalArgumentException("Invalid loop points : "
+ + start + " - " + end);
+ if (0 < start)
+ throw new IllegalArgumentException("Invalid loop points : "
+ + start + " - " + end);
+ loopstart = start;
+ loopend = end;
+ loop_sg = true;
+ }
+ }
+
+ public void setMicrosecondPosition(long microseconds) {
+ setFramePosition((int) (microseconds * (((double) getFormat()
+ .getSampleRate()) / 1000000.0)));
+ }
+
+ public int available() {
+ return 0;
+ }
+
+ public void drain() {
+ }
+
+ public void flush() {
+ }
+
+ public int getBufferSize() {
+ return bufferSize;
+ }
+
+ public AudioFormat getFormat() {
+ return format;
+ }
+
+ public int getFramePosition() {
+ synchronized (control_mutex) {
+ return frameposition;
+ }
+ }
+
+ public float getLevel() {
+ return AudioSystem.NOT_SPECIFIED;
+ }
+
+ public long getLongFramePosition() {
+ return getFramePosition();
+ }
+
+ public long getMicrosecondPosition() {
+ return (long) (getFramePosition() * (1000000.0 / (double) getFormat()
+ .getSampleRate()));
+ }
+
+ public boolean isActive() {
+ synchronized (control_mutex) {
+ return active;
+ }
+ }
+
+ public boolean isRunning() {
+ synchronized (control_mutex) {
+ return active;
+ }
+ }
+
+ public void start() {
+
+ LineEvent event = null;
+
+ synchronized (control_mutex) {
+ if (isOpen()) {
+ if (active)
+ return;
+ active = true;
+ active_sg = true;
+ loopcount = 0;
+ event = new LineEvent(this, LineEvent.Type.START,
+ getLongFramePosition());
+ }
+ }
+
+ if (event != null)
+ sendEvent(event);
+ }
+
+ public void stop() {
+ LineEvent event = null;
+
+ synchronized (control_mutex) {
+ if (isOpen()) {
+ if (!active)
+ return;
+ active = false;
+ active_sg = true;
+ event = new LineEvent(this, LineEvent.Type.STOP,
+ getLongFramePosition());
+ }
+ }
+
+ if (event != null)
+ sendEvent(event);
+ }
+
+ public void close() {
+ LineEvent event = null;
+
+ synchronized (control_mutex) {
+ if (!isOpen())
+ return;
+ stop();
+
+ event = new LineEvent(this, LineEvent.Type.CLOSE,
+ getLongFramePosition());
+
+ open = false;
+ mixer.getMainMixer().closeLine(this);
+ }
+
+ if (event != null)
+ sendEvent(event);
+
+ }
+
+ public boolean isOpen() {
+ return open;
+ }
+
+ public void open() throws LineUnavailableException {
+ if (data == null) {
+ throw new IllegalArgumentException(
+ "Illegal call to open() in interface Clip");
+ }
+ open(format, data, offset, bufferSize);
+ }
+
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SoftMixingDataLine.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SoftMixingDataLine.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,522 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.media.sound;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.AudioSystem;
+import javax.sound.sampled.BooleanControl;
+import javax.sound.sampled.Control;
+import javax.sound.sampled.DataLine;
+import javax.sound.sampled.FloatControl;
+import javax.sound.sampled.LineEvent;
+import javax.sound.sampled.LineListener;
+import javax.sound.sampled.Control.Type;
+
+/**
+ * General software mixing line.
+ *
+ * @author Karl Helgason
+ */
+public abstract class SoftMixingDataLine implements DataLine {
+
+ public static final FloatControl.Type CHORUS_SEND = new FloatControl.Type(
+ "Chorus Send") {
+ };
+
+ protected static class AudioFloatInputStreamResampler extends
+ AudioFloatInputStream {
+
+ private AudioFloatInputStream ais;
+
+ private AudioFormat targetFormat;
+
+ private float[] skipbuffer;
+
+ private SoftAbstractResampler resampler;
+
+ private float[] pitch = new float[1];
+
+ private float[] ibuffer2;
+
+ private float[][] ibuffer;
+
+ private float ibuffer_index = 0;
+
+ private int ibuffer_len = 0;
+
+ private int nrofchannels = 0;
+
+ private float[][] cbuffer;
+
+ private int buffer_len = 512;
+
+ private int pad;
+
+ private int pad2;
+
+ private float[] ix = new float[1];
+
+ private int[] ox = new int[1];
+
+ private float[][] mark_ibuffer = null;
+
+ private float mark_ibuffer_index = 0;
+
+ private int mark_ibuffer_len = 0;
+
+ public 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 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; i < b.length; 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 class Gain extends FloatControl {
+
+ private Gain() {
+
+ super(FloatControl.Type.MASTER_GAIN, -80f, 6.0206f, 80f / 128.0f,
+ -1, 0.0f, "dB", "Minimum", "", "Maximum");
+ }
+
+ public void setValue(float newValue) {
+ super.setValue(newValue);
+ calcVolume();
+ }
+ }
+
+ private class Mute extends BooleanControl {
+
+ private Mute() {
+ super(BooleanControl.Type.MUTE, false, "True", "False");
+ }
+
+ public void setValue(boolean newValue) {
+ super.setValue(newValue);
+ calcVolume();
+ }
+ }
+
+ private class ApplyReverb extends BooleanControl {
+
+ private ApplyReverb() {
+ super(BooleanControl.Type.APPLY_REVERB, false, "True", "False");
+ }
+
+ public void setValue(boolean newValue) {
+ super.setValue(newValue);
+ calcVolume();
+ }
+
+ }
+
+ private class Balance extends FloatControl {
+
+ private Balance() {
+ super(FloatControl.Type.BALANCE, -1.0f, 1.0f, (1.0f / 128.0f), -1,
+ 0.0f, "", "Left", "Center", "Right");
+ }
+
+ public void setValue(float newValue) {
+ super.setValue(newValue);
+ calcVolume();
+ }
+
+ }
+
+ private class Pan extends FloatControl {
+
+ private Pan() {
+ super(FloatControl.Type.PAN, -1.0f, 1.0f, (1.0f / 128.0f), -1,
+ 0.0f, "", "Left", "Center", "Right");
+ }
+
+ public void setValue(float newValue) {
+ super.setValue(newValue);
+ balance_control.setValue(newValue);
+ }
+
+ public float getValue() {
+ return balance_control.getValue();
+ }
+
+ }
+
+ private class ReverbSend extends FloatControl {
+
+ private ReverbSend() {
+ super(FloatControl.Type.REVERB_SEND, -80f, 6.0206f, 80f / 128.0f,
+ -1, -80f, "dB", "Minimum", "", "Maximum");
+ }
+
+ public void setValue(float newValue) {
+ super.setValue(newValue);
+ balance_control.setValue(newValue);
+ }
+
+ }
+
+ private class ChorusSend extends FloatControl {
+
+ private ChorusSend() {
+ super(CHORUS_SEND, -80f, 6.0206f, 80f / 128.0f, -1, -80f, "dB",
+ "Minimum", "", "Maximum");
+ }
+
+ public void setValue(float newValue) {
+ super.setValue(newValue);
+ balance_control.setValue(newValue);
+ }
+
+ }
+
+ private Gain gain_control = new Gain();
+
+ private Mute mute_control = new Mute();
+
+ private Balance balance_control = new Balance();
+
+ private Pan pan_control = new Pan();
+
+ private ReverbSend reverbsend_control = new ReverbSend();
+
+ private ChorusSend chorussend_control = new ChorusSend();
+
+ private ApplyReverb apply_reverb = new ApplyReverb();
+
+ private Control[] controls;
+
+ protected float leftgain = 1;
+
+ protected float rightgain = 1;
+
+ protected float eff1gain = 0;
+
+ protected float eff2gain = 0;
+
+ protected List listeners = new ArrayList();
+
+ protected Object control_mutex;
+
+ protected SoftMixingMixer mixer;
+
+ protected DataLine.Info info;
+
+ protected abstract void processControlLogic();
+
+ protected abstract void processAudioLogic(SoftAudioBuffer[] buffers);
+
+ protected SoftMixingDataLine(SoftMixingMixer mixer, DataLine.Info info) {
+ this.mixer = mixer;
+ this.info = info;
+ this.control_mutex = mixer.control_mutex;
+
+ controls = new Control[] { gain_control, mute_control, balance_control,
+ pan_control, reverbsend_control, chorussend_control,
+ apply_reverb };
+ calcVolume();
+ }
+
+ protected void calcVolume() {
+ synchronized (control_mutex) {
+ double gain = Math.pow(10.0, gain_control.getValue() / 20.0);
+ if (mute_control.getValue())
+ gain = 0;
+ leftgain = (float) gain;
+ rightgain = (float) gain;
+ if (mixer.getFormat().getChannels() > 1) {
+ // -1 = Left, 0 Center, 1 = Right
+ double balance = balance_control.getValue();
+ if (balance > 0)
+ leftgain *= (1 - balance);
+ else
+ rightgain *= (1 + balance);
+
+ }
+ }
+
+ eff1gain = (float) Math.pow(10.0, reverbsend_control.getValue() / 20.0);
+ eff2gain = (float) Math.pow(10.0, chorussend_control.getValue() / 20.0);
+
+ if (!apply_reverb.getValue()) {
+ eff1gain = 0;
+ }
+ }
+
+ protected void sendEvent(LineEvent event) {
+ if (listeners.size() == 0)
+ return;
+ LineListener[] listener_array = listeners
+ .toArray(new LineListener[listeners.size()]);
+ for (LineListener listener : listener_array) {
+ listener.update(event);
+ }
+ }
+
+ public void addLineListener(LineListener listener) {
+ synchronized (control_mutex) {
+ listeners.add(listener);
+ }
+ }
+
+ public void removeLineListener(LineListener listener) {
+ synchronized (control_mutex) {
+ listeners.add(listener);
+ }
+ }
+
+ public javax.sound.sampled.Line.Info getLineInfo() {
+ return info;
+ }
+
+ public Control getControl(Type control) {
+ if (control != null) {
+ for (int i = 0; i < controls.length; i++) {
+ if (controls[i].getType() == control) {
+ return controls[i];
+ }
+ }
+ }
+ throw new IllegalArgumentException("Unsupported control type : "
+ + control);
+ }
+
+ public Control[] getControls() {
+ return controls;
+ }
+
+ public boolean isControlSupported(Type control) {
+ if (control != null) {
+ for (int i = 0; i < controls.length; i++) {
+ if (controls[i].getType() == control) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SoftMixingMainMixer.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SoftMixingMainMixer.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,259 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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.List;
+
+import javax.sound.sampled.AudioInputStream;
+import javax.sound.sampled.AudioSystem;
+
+/**
+ * Main mixer for SoftMixingMixer.
+ *
+ * @author Karl Helgason
+ */
+public class SoftMixingMainMixer {
+
+ public final static int CHANNEL_LEFT = 0;
+
+ public final static int CHANNEL_RIGHT = 1;
+
+ public final static int CHANNEL_EFFECT1 = 2;
+
+ public final static int CHANNEL_EFFECT2 = 3;
+
+ public final static int CHANNEL_EFFECT3 = 4;
+
+ public final static int CHANNEL_EFFECT4 = 5;
+
+ public final static int CHANNEL_LEFT_DRY = 10;
+
+ public final static int CHANNEL_RIGHT_DRY = 11;
+
+ public final static int CHANNEL_SCRATCH1 = 12;
+
+ public final static int CHANNEL_SCRATCH2 = 13;
+
+ public final static int CHANNEL_CHANNELMIXER_LEFT = 14;
+
+ public final static int CHANNEL_CHANNELMIXER_RIGHT = 15;
+
+ private SoftMixingMixer mixer;
+
+ private AudioInputStream ais;
+
+ private SoftAudioBuffer[] buffers;
+
+ private SoftAudioProcessor reverb;
+
+ private SoftAudioProcessor chorus;
+
+ private SoftAudioProcessor agc;
+
+ private int nrofchannels;
+
+ private Object control_mutex;
+
+ private List openLinesList = new ArrayList();
+
+ private SoftMixingDataLine[] openLines = new SoftMixingDataLine[0];
+
+ public AudioInputStream getInputStream() {
+ return ais;
+ }
+
+ protected void processAudioBuffers() {
+ for (int i = 0; i < buffers.length; i++) {
+ buffers[i].clear();
+ }
+
+ SoftMixingDataLine[] openLines;
+ synchronized (control_mutex) {
+ openLines = this.openLines;
+ for (int i = 0; i < openLines.length; i++) {
+ openLines[i].processControlLogic();
+ }
+ chorus.processControlLogic();
+ reverb.processControlLogic();
+ agc.processControlLogic();
+ }
+ for (int i = 0; i < openLines.length; i++) {
+ openLines[i].processAudioLogic(buffers);
+ }
+
+ chorus.processAudio();
+ reverb.processAudio();
+
+ agc.processAudio();
+
+ }
+
+ public SoftMixingMainMixer(SoftMixingMixer mixer) {
+ this.mixer = mixer;
+
+ nrofchannels = mixer.getFormat().getChannels();
+
+ int buffersize = (int) (mixer.getFormat().getSampleRate() / mixer
+ .getControlRate());
+
+ control_mutex = mixer.control_mutex;
+ buffers = new SoftAudioBuffer[16];
+ for (int i = 0; i < buffers.length; i++) {
+ buffers[i] = new SoftAudioBuffer(buffersize, mixer.getFormat());
+
+ }
+
+ reverb = new SoftReverb();
+ chorus = new SoftChorus();
+ agc = new SoftLimiter();
+
+ float samplerate = mixer.getFormat().getSampleRate();
+ float controlrate = mixer.getControlRate();
+ reverb.init(samplerate, controlrate);
+ chorus.init(samplerate, controlrate);
+ agc.init(samplerate, controlrate);
+
+ reverb.setMixMode(true);
+ chorus.setMixMode(true);
+ agc.setMixMode(false);
+
+ chorus.setInput(0, buffers[CHANNEL_EFFECT2]);
+ chorus.setOutput(0, buffers[CHANNEL_LEFT]);
+ if (nrofchannels != 1)
+ chorus.setOutput(1, buffers[CHANNEL_RIGHT]);
+ chorus.setOutput(2, buffers[CHANNEL_EFFECT1]);
+
+ reverb.setInput(0, buffers[CHANNEL_EFFECT1]);
+ reverb.setOutput(0, buffers[CHANNEL_LEFT]);
+ if (nrofchannels != 1)
+ reverb.setOutput(1, buffers[CHANNEL_RIGHT]);
+
+ agc.setInput(0, buffers[CHANNEL_LEFT]);
+ if (nrofchannels != 1)
+ agc.setInput(1, buffers[CHANNEL_RIGHT]);
+ agc.setOutput(0, buffers[CHANNEL_LEFT]);
+ if (nrofchannels != 1)
+ agc.setOutput(1, buffers[CHANNEL_RIGHT]);
+
+ InputStream in = new InputStream() {
+
+ private SoftAudioBuffer[] buffers = SoftMixingMainMixer.this.buffers;
+
+ private int nrofchannels = SoftMixingMainMixer.this.mixer
+ .getFormat().getChannels();
+
+ private int buffersize = buffers[0].getSize();
+
+ private byte[] bbuffer = new byte[buffersize
+ * (SoftMixingMainMixer.this.mixer.getFormat()
+ .getSampleSizeInBits() / 8) * nrofchannels];
+
+ private int bbuffer_pos = 0;
+
+ private byte[] single = new byte[1];
+
+ public void fillBuffer() {
+ processAudioBuffers();
+ for (int i = 0; i < nrofchannels; i++)
+ buffers[i].get(bbuffer, i);
+ bbuffer_pos = 0;
+ }
+
+ public int read(byte[] b, int off, int len) {
+ int bbuffer_len = bbuffer.length;
+ int offlen = off + len;
+ byte[] bbuffer = this.bbuffer;
+ while (off < offlen)
+ if (available() == 0)
+ fillBuffer();
+ else {
+ int bbuffer_pos = this.bbuffer_pos;
+ while (off < offlen && bbuffer_pos < bbuffer_len)
+ b[off++] = bbuffer[bbuffer_pos++];
+ this.bbuffer_pos = bbuffer_pos;
+ }
+ return len;
+ }
+
+ public int read() throws IOException {
+ int ret = read(single);
+ if (ret == -1)
+ return -1;
+ return single[0] & 0xFF;
+ }
+
+ public int available() {
+ return bbuffer.length - bbuffer_pos;
+ }
+
+ public void close() {
+ SoftMixingMainMixer.this.mixer.close();
+ }
+
+ };
+
+ ais = new AudioInputStream(in, mixer.getFormat(),
+ AudioSystem.NOT_SPECIFIED);
+
+ }
+
+ public void openLine(SoftMixingDataLine line) {
+ synchronized (control_mutex) {
+ openLinesList.add(line);
+ openLines = openLinesList
+ .toArray(new SoftMixingDataLine[openLinesList.size()]);
+ }
+ }
+
+ public void closeLine(SoftMixingDataLine line) {
+ synchronized (control_mutex) {
+ openLinesList.remove(line);
+ openLines = openLinesList
+ .toArray(new SoftMixingDataLine[openLinesList.size()]);
+ if (openLines.length == 0)
+ if (mixer.implicitOpen)
+ mixer.close();
+ }
+
+ }
+
+ public SoftMixingDataLine[] getOpenLines() {
+ synchronized (control_mutex) {
+ return openLines;
+ }
+
+ }
+
+ public void close() {
+ SoftMixingDataLine[] openLines = this.openLines;
+ for (int i = 0; i < openLines.length; i++) {
+ openLines[i].close();
+ }
+ }
+
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SoftMixingMixer.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SoftMixingMixer.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,529 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.media.sound;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.AudioInputStream;
+import javax.sound.sampled.AudioSystem;
+import javax.sound.sampled.Clip;
+import javax.sound.sampled.Control;
+import javax.sound.sampled.DataLine;
+import javax.sound.sampled.Line;
+import javax.sound.sampled.LineEvent;
+import javax.sound.sampled.LineListener;
+import javax.sound.sampled.LineUnavailableException;
+import javax.sound.sampled.Mixer;
+import javax.sound.sampled.SourceDataLine;
+import javax.sound.sampled.AudioFormat.Encoding;
+import javax.sound.sampled.Control.Type;
+
+/**
+ * Software audio mixer
+ *
+ * @author Karl Helgason
+ */
+public class SoftMixingMixer implements Mixer {
+
+ private static class Info extends Mixer.Info {
+ public Info() {
+ super(INFO_NAME, INFO_VENDOR, INFO_DESCRIPTION, INFO_VERSION);
+ }
+ }
+
+ protected static final String INFO_NAME = "Gervill Sound Mixer";
+
+ protected static final String INFO_VENDOR = "OpenJDK Proposal";
+
+ protected static final String INFO_DESCRIPTION = "Software Sound Mixer";
+
+ protected static final String INFO_VERSION = "1.0";
+
+ protected final static Mixer.Info info = new Info();
+
+ protected Object control_mutex = this;
+
+ protected boolean implicitOpen = false;
+
+ private boolean open = false;
+
+ private SoftMixingMainMixer mainmixer = null;
+
+ private AudioFormat format = new AudioFormat(44100, 16, 2, true, false);
+
+ private SourceDataLine sourceDataLine = null;
+
+ private SoftAudioPusher pusher = null;
+
+ private AudioInputStream pusher_stream = null;
+
+ private float controlrate = 147f;
+
+ private long latency = 100000; // 100 msec
+
+ private boolean jitter_correction = false;
+
+ private List listeners = new ArrayList();
+
+ private javax.sound.sampled.Line.Info[] sourceLineInfo;
+
+ public SoftMixingMixer() {
+
+ sourceLineInfo = new javax.sound.sampled.Line.Info[2];
+
+ ArrayList formats = new ArrayList();
+ for (int channels = 1; channels <= 2; channels++) {
+ formats.add(new AudioFormat(Encoding.PCM_SIGNED,
+ AudioSystem.NOT_SPECIFIED, 8, channels, channels,
+ AudioSystem.NOT_SPECIFIED, false));
+ 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) {
+ 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_UNSIGNED,
+ 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));
+ formats.add(new AudioFormat(Encoding.PCM_UNSIGNED,
+ AudioSystem.NOT_SPECIFIED, bits, channels, channels
+ * bits / 8, AudioSystem.NOT_SPECIFIED, true));
+ }
+ formats.add(new AudioFormat(AudioFloatConverter.PCM_FLOAT,
+ AudioSystem.NOT_SPECIFIED, 32, channels, channels * 4,
+ AudioSystem.NOT_SPECIFIED, false));
+ formats.add(new AudioFormat(AudioFloatConverter.PCM_FLOAT,
+ AudioSystem.NOT_SPECIFIED, 32, channels, channels * 4,
+ AudioSystem.NOT_SPECIFIED, true));
+ formats.add(new AudioFormat(AudioFloatConverter.PCM_FLOAT,
+ AudioSystem.NOT_SPECIFIED, 64, channels, channels * 8,
+ AudioSystem.NOT_SPECIFIED, false));
+ formats.add(new AudioFormat(AudioFloatConverter.PCM_FLOAT,
+ AudioSystem.NOT_SPECIFIED, 64, channels, channels * 8,
+ AudioSystem.NOT_SPECIFIED, true));
+ }
+ AudioFormat[] formats_array = formats.toArray(new AudioFormat[formats
+ .size()]);
+ sourceLineInfo[0] = new DataLine.Info(SourceDataLine.class,
+ formats_array, AudioSystem.NOT_SPECIFIED,
+ AudioSystem.NOT_SPECIFIED);
+ sourceLineInfo[1] = new DataLine.Info(Clip.class, formats_array,
+ AudioSystem.NOT_SPECIFIED, AudioSystem.NOT_SPECIFIED);
+ }
+
+ public Line getLine(Line.Info info) throws LineUnavailableException {
+
+ if (!isLineSupported(info))
+ throw new IllegalArgumentException("Line unsupported: " + info);
+
+ if ((info.getLineClass() == SourceDataLine.class)) {
+ return new SoftMixingSourceDataLine(this, (DataLine.Info) info);
+ }
+ if ((info.getLineClass() == Clip.class)) {
+ return new SoftMixingClip(this, (DataLine.Info) info);
+ }
+
+ throw new IllegalArgumentException("Line unsupported: " + info);
+ }
+
+ public int getMaxLines(Line.Info info) {
+ if (info.getLineClass() == SourceDataLine.class)
+ return AudioSystem.NOT_SPECIFIED;
+ if (info.getLineClass() == Clip.class)
+ return AudioSystem.NOT_SPECIFIED;
+ return 0;
+ }
+
+ public javax.sound.sampled.Mixer.Info getMixerInfo() {
+ return info;
+ }
+
+ public javax.sound.sampled.Line.Info[] getSourceLineInfo() {
+ Line.Info[] localArray = new Line.Info[sourceLineInfo.length];
+ System.arraycopy(sourceLineInfo, 0, localArray, 0,
+ sourceLineInfo.length);
+ return localArray;
+ }
+
+ public javax.sound.sampled.Line.Info[] getSourceLineInfo(
+ javax.sound.sampled.Line.Info info) {
+ int i;
+ ArrayList infos = new ArrayList();
+
+ for (i = 0; i < sourceLineInfo.length; i++) {
+ if (info.matches(sourceLineInfo[i])) {
+ infos.add(sourceLineInfo[i]);
+ }
+ }
+ return infos.toArray(new Line.Info[infos.size()]);
+ }
+
+ public Line[] getSourceLines() {
+
+ Line[] localLines;
+
+ synchronized (control_mutex) {
+
+ if (mainmixer == null)
+ return new Line[0];
+ SoftMixingDataLine[] sourceLines = mainmixer.getOpenLines();
+
+ localLines = new Line[sourceLines.length];
+
+ for (int i = 0; i < localLines.length; i++) {
+ localLines[i] = sourceLines[i];
+ }
+ }
+
+ return localLines;
+ }
+
+ public javax.sound.sampled.Line.Info[] getTargetLineInfo() {
+ return new javax.sound.sampled.Line.Info[0];
+ }
+
+ public javax.sound.sampled.Line.Info[] getTargetLineInfo(
+ javax.sound.sampled.Line.Info info) {
+ return new javax.sound.sampled.Line.Info[0];
+ }
+
+ public Line[] getTargetLines() {
+ return new Line[0];
+ }
+
+ public boolean isLineSupported(javax.sound.sampled.Line.Info info) {
+ if (info != null) {
+ for (int i = 0; i < sourceLineInfo.length; i++) {
+ if (info.matches(sourceLineInfo[i])) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public boolean isSynchronizationSupported(Line[] lines, boolean maintainSync) {
+ return false;
+ }
+
+ public void synchronize(Line[] lines, boolean maintainSync) {
+ throw new IllegalArgumentException(
+ "Synchronization not supported by this mixer.");
+ }
+
+ public void unsynchronize(Line[] lines) {
+ throw new IllegalArgumentException(
+ "Synchronization not supported by this mixer.");
+ }
+
+ public void addLineListener(LineListener listener) {
+ synchronized (control_mutex) {
+ listeners.add(listener);
+ }
+ }
+
+ private void sendEvent(LineEvent event) {
+ if (listeners.size() == 0)
+ return;
+ LineListener[] listener_array = listeners
+ .toArray(new LineListener[listeners.size()]);
+ for (LineListener listener : listener_array) {
+ listener.update(event);
+ }
+ }
+
+ public void close() {
+ if (!isOpen())
+ return;
+
+ sendEvent(new LineEvent(this, LineEvent.Type.CLOSE,
+ AudioSystem.NOT_SPECIFIED));
+
+ SoftAudioPusher pusher_to_be_closed = null;
+ AudioInputStream pusher_stream_to_be_closed = null;
+ synchronized (control_mutex) {
+ if (pusher != null) {
+ pusher_to_be_closed = pusher;
+ pusher_stream_to_be_closed = pusher_stream;
+ pusher = null;
+ pusher_stream = null;
+ }
+ }
+
+ if (pusher_to_be_closed != null) {
+ // Pusher must not be closed synchronized against control_mutex
+ // this may result in synchronized conflict between pusher and
+ // current thread.
+ pusher_to_be_closed.stop();
+
+ try {
+ pusher_stream_to_be_closed.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ synchronized (control_mutex) {
+
+ if (mainmixer != null)
+ mainmixer.close();
+ open = false;
+
+ if (sourceDataLine != null) {
+ sourceDataLine.drain();
+ sourceDataLine.close();
+ sourceDataLine = null;
+ }
+
+ }
+
+ }
+
+ public Control getControl(Type control) {
+ throw new IllegalArgumentException("Unsupported control type : "
+ + control);
+ }
+
+ public Control[] getControls() {
+ return new Control[0];
+ }
+
+ public javax.sound.sampled.Line.Info getLineInfo() {
+ return new Line.Info(Mixer.class);
+ }
+
+ public boolean isControlSupported(Type control) {
+ return false;
+ }
+
+ public boolean isOpen() {
+ synchronized (control_mutex) {
+ return open;
+ }
+ }
+
+ public void open() throws LineUnavailableException {
+ if (isOpen()) {
+ implicitOpen = false;
+ return;
+ }
+ open(null);
+ }
+
+ public void open(SourceDataLine line) throws LineUnavailableException {
+ if (isOpen()) {
+ implicitOpen = false;
+ return;
+ }
+ synchronized (control_mutex) {
+
+ try {
+
+ if (line != null)
+ format = line.getFormat();
+
+ AudioInputStream ais = openStream(getFormat());
+
+ if (line == null) {
+ synchronized (SoftMixingMixerProvider.mutex) {
+ SoftMixingMixerProvider.lockthread = Thread
+ .currentThread();
+ }
+
+ try {
+ Mixer defaultmixer = AudioSystem.getMixer(null);
+ if (defaultmixer != null)
+ {
+ // Search for suitable line
+
+ DataLine.Info idealinfo = null;
+ AudioFormat idealformat = null;
+
+ Line.Info[] lineinfos = defaultmixer.getSourceLineInfo();
+ idealFound:
+ for (int i = 0; i < lineinfos.length; i++) {
+ if(lineinfos[i].getLineClass() == SourceDataLine.class)
+ {
+ DataLine.Info info = (DataLine.Info)lineinfos[i];
+ AudioFormat[] formats = info.getFormats();
+ for (int j = 0; j < formats.length; j++) {
+ AudioFormat format = formats[j];
+ if(format.getChannels() == 2 ||
+ format.getChannels() == AudioSystem.NOT_SPECIFIED)
+ if(format.getEncoding().equals(Encoding.PCM_SIGNED) ||
+ format.getEncoding().equals(Encoding.PCM_UNSIGNED))
+ if(format.getSampleRate() == AudioSystem.NOT_SPECIFIED ||
+ format.getSampleRate() == 48000.0)
+ if(format.getSampleSizeInBits() == AudioSystem.NOT_SPECIFIED ||
+ format.getSampleSizeInBits() == 16)
+ {
+ idealinfo = info;
+ int ideal_channels = format.getChannels();
+ boolean ideal_signed = format.getEncoding().equals(Encoding.PCM_SIGNED);
+ float ideal_rate = format.getSampleRate();
+ boolean ideal_endian = format.isBigEndian();
+ int ideal_bits = format.getSampleSizeInBits();
+ if(ideal_bits == AudioSystem.NOT_SPECIFIED) ideal_bits = 16;
+ if(ideal_channels == AudioSystem.NOT_SPECIFIED) ideal_channels = 2;
+ if(ideal_rate == AudioSystem.NOT_SPECIFIED) ideal_rate = 48000;
+ idealformat = new AudioFormat(ideal_rate, ideal_bits,
+ ideal_channels, ideal_signed, ideal_endian);
+ break idealFound;
+ }
+ }
+ }
+ }
+
+ if(idealformat != null)
+ {
+ format = idealformat;
+ line = (SourceDataLine) defaultmixer.getLine(idealinfo);
+ }
+ }
+
+ if(line == null)
+ line = AudioSystem.getSourceDataLine(format);
+ } finally {
+ synchronized (SoftMixingMixerProvider.mutex) {
+ SoftMixingMixerProvider.lockthread = null;
+ }
+ }
+
+ if (line == null)
+ throw new IllegalArgumentException("No line matching "
+ + info.toString() + " is supported.");
+ }
+
+ double latency = this.latency;
+
+ if (!line.isOpen()) {
+ int bufferSize = getFormat().getFrameSize()
+ * (int) (getFormat().getFrameRate() * (latency / 1000000f));
+ line.open(getFormat(), bufferSize);
+
+ // Remember that we opened that line
+ // so we can close again in SoftSynthesizer.close()
+ sourceDataLine = line;
+ }
+ if (!line.isActive())
+ line.start();
+
+ int controlbuffersize = 512;
+ try {
+ controlbuffersize = ais.available();
+ } catch (IOException e) {
+ }
+
+ // Tell mixer not fill read buffers fully.
+ // This lowers latency, and tells DataPusher
+ // to read in smaller amounts.
+ // mainmixer.readfully = false;
+ // pusher = new DataPusher(line, ais);
+
+ int buffersize = line.getBufferSize();
+ buffersize -= buffersize % controlbuffersize;
+
+ if (buffersize < 3 * controlbuffersize)
+ buffersize = 3 * controlbuffersize;
+
+ if (jitter_correction) {
+ ais = new SoftJitterCorrector(ais, buffersize,
+ controlbuffersize);
+ }
+ pusher = new SoftAudioPusher(line, ais, controlbuffersize);
+ pusher_stream = ais;
+ pusher.start();
+
+ } catch (LineUnavailableException e) {
+ if (isOpen())
+ close();
+ throw new LineUnavailableException(e.toString());
+ }
+
+ }
+ }
+
+ public AudioInputStream openStream(AudioFormat targetFormat)
+ throws LineUnavailableException {
+
+ if (isOpen())
+ throw new LineUnavailableException("Mixer is already open");
+
+ synchronized (control_mutex) {
+
+ open = true;
+
+ implicitOpen = false;
+
+ if (targetFormat != null)
+ format = targetFormat;
+
+ mainmixer = new SoftMixingMainMixer(this);
+
+ sendEvent(new LineEvent(this, LineEvent.Type.OPEN,
+ AudioSystem.NOT_SPECIFIED));
+
+ return mainmixer.getInputStream();
+
+ }
+
+ }
+
+ public void removeLineListener(LineListener listener) {
+ synchronized (control_mutex) {
+ listeners.remove(listener);
+ }
+ }
+
+ public long getLatency() {
+ synchronized (control_mutex) {
+ return latency;
+ }
+ }
+
+ public AudioFormat getFormat() {
+ synchronized (control_mutex) {
+ return format;
+ }
+ }
+
+ protected float getControlRate() {
+ return controlrate;
+ }
+
+ protected SoftMixingMainMixer getMainMixer() {
+ if (!isOpen())
+ return null;
+ return mainmixer;
+ }
+
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SoftMixingMixerProvider.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SoftMixingMixerProvider.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.media.sound;
+
+import javax.sound.sampled.Mixer;
+import javax.sound.sampled.Mixer.Info;
+import javax.sound.sampled.spi.MixerProvider;
+
+/**
+ * Provider for software audio mixer
+ *
+ * @author Karl Helgason
+ */
+public class SoftMixingMixerProvider extends MixerProvider {
+
+ static SoftMixingMixer globalmixer = null;
+
+ static Thread lockthread = null;
+
+ protected final static Object mutex = new Object();
+
+ public Mixer getMixer(Info info) {
+ if (!(info == null || info == SoftMixingMixer.info)) {
+ throw new IllegalArgumentException("Mixer " + info.toString()
+ + " not supported by this provider.");
+ }
+ synchronized (mutex) {
+ if (lockthread != null)
+ if (Thread.currentThread() == lockthread)
+ throw new IllegalArgumentException("Mixer "
+ + info.toString()
+ + " not supported by this provider.");
+ if (globalmixer == null)
+ globalmixer = new SoftMixingMixer();
+ return globalmixer;
+ }
+
+ }
+
+ public Info[] getMixerInfo() {
+ return new Info[] { SoftMixingMixer.info };
+ }
+
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SoftMixingSourceDataLine.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SoftMixingSourceDataLine.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,519 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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.Arrays;
+
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.AudioInputStream;
+import javax.sound.sampled.AudioSystem;
+import javax.sound.sampled.DataLine;
+import javax.sound.sampled.LineEvent;
+import javax.sound.sampled.LineUnavailableException;
+import javax.sound.sampled.SourceDataLine;
+
+/**
+ * SourceDataLine implemention for the SoftMixingMixer.
+ *
+ * @author Karl Helgason
+ */
+public class SoftMixingSourceDataLine extends SoftMixingDataLine implements
+ SourceDataLine {
+
+ private boolean open = false;
+
+ private AudioFormat format = new AudioFormat(44100.0f, 16, 2, true, false);
+
+ private int framesize;
+
+ private int bufferSize = -1;
+
+ private float[] readbuffer;
+
+ private boolean active = false;
+
+ private byte[] cycling_buffer;
+
+ private int cycling_read_pos = 0;
+
+ private int cycling_write_pos = 0;
+
+ private int cycling_avail = 0;
+
+ private long cycling_framepos = 0;
+
+ private AudioFloatInputStream afis;
+
+ private static class NonBlockingFloatInputStream extends
+ AudioFloatInputStream {
+ AudioFloatInputStream ais;
+
+ public NonBlockingFloatInputStream(AudioFloatInputStream ais) {
+ this.ais = ais;
+ }
+
+ public int available() throws IOException {
+ return ais.available();
+ }
+
+ public void close() throws IOException {
+ ais.close();
+ }
+
+ public AudioFormat getFormat() {
+ return ais.getFormat();
+ }
+
+ public long getFrameLength() {
+ return ais.getFrameLength();
+ }
+
+ public void mark(int readlimit) {
+ ais.mark(readlimit);
+ }
+
+ public boolean markSupported() {
+ return ais.markSupported();
+ }
+
+ public int read(float[] b, int off, int len) throws IOException {
+ int avail = available();
+ if (len > avail) {
+ int ret = ais.read(b, off, avail);
+ Arrays.fill(b, off + ret, off + len, 0);
+ return len;
+ }
+ return ais.read(b, off, len);
+ }
+
+ public void reset() throws IOException {
+ ais.reset();
+ }
+
+ public long skip(long len) throws IOException {
+ return ais.skip(len);
+ }
+
+ }
+
+ protected SoftMixingSourceDataLine(SoftMixingMixer mixer, DataLine.Info info) {
+ super(mixer, info);
+ }
+
+ public int write(byte[] b, int off, int len) {
+ if (!isOpen())
+ return 0;
+ if (len % framesize != 0)
+ throw new IllegalArgumentException(
+ "Number of bytes does not represent an integral number of sample frames.");
+
+ byte[] buff = cycling_buffer;
+ int buff_len = cycling_buffer.length;
+
+ int l = 0;
+ while (l != len) {
+ int avail;
+ synchronized (cycling_buffer) {
+ int pos = cycling_write_pos;
+ avail = cycling_avail;
+ while (l != len) {
+ if (avail == buff_len)
+ break;
+ buff[pos++] = b[off++];
+ l++;
+ avail++;
+ if (pos == buff_len)
+ pos = 0;
+ }
+ cycling_avail = avail;
+ cycling_write_pos = pos;
+ if (l == len)
+ return l;
+ }
+ if (avail == buff_len) {
+ try {
+ Thread.sleep(1);
+ } catch (InterruptedException e) {
+ return l;
+ }
+ if (!isRunning())
+ return l;
+ }
+ }
+
+ return l;
+ }
+
+ //
+ // BooleanControl.Type.APPLY_REVERB
+ // BooleanControl.Type.MUTE
+ // EnumControl.Type.REVERB
+ //
+ // FloatControl.Type.SAMPLE_RATE
+ // FloatControl.Type.REVERB_SEND
+ // FloatControl.Type.VOLUME
+ // FloatControl.Type.PAN
+ // FloatControl.Type.MASTER_GAIN
+ // FloatControl.Type.BALANCE
+
+ private boolean _active = false;
+
+ private AudioFormat outputformat;
+
+ private int out_nrofchannels;
+
+ private int in_nrofchannels;
+
+ private float _rightgain;
+
+ private float _leftgain;
+
+ private float _eff1gain;
+
+ private float _eff2gain;
+
+ protected void processControlLogic() {
+ _active = active;
+ _rightgain = rightgain;
+ _leftgain = leftgain;
+ _eff1gain = eff1gain;
+ _eff2gain = eff2gain;
+ }
+
+ protected void processAudioLogic(SoftAudioBuffer[] buffers) {
+ if (_active) {
+ float[] left = buffers[SoftMixingMainMixer.CHANNEL_LEFT].array();
+ float[] right = buffers[SoftMixingMainMixer.CHANNEL_RIGHT].array();
+ int bufferlen = buffers[SoftMixingMainMixer.CHANNEL_LEFT].getSize();
+
+ int readlen = bufferlen * in_nrofchannels;
+ if (readbuffer == null || readbuffer.length < readlen) {
+ readbuffer = new float[readlen];
+ }
+ int ret = 0;
+ try {
+ ret = afis.read(readbuffer);
+ if (ret != in_nrofchannels)
+ Arrays.fill(readbuffer, ret, readlen, 0);
+ } catch (IOException e) {
+ }
+
+ int in_c = in_nrofchannels;
+ for (int i = 0, ix = 0; i < bufferlen; i++, ix += in_c) {
+ left[i] += readbuffer[ix] * _leftgain;
+ }
+ if (out_nrofchannels != 1) {
+ if (in_nrofchannels == 1) {
+ for (int i = 0, ix = 0; i < bufferlen; i++, ix += in_c) {
+ right[i] += readbuffer[ix] * _rightgain;
+ }
+ } else {
+ for (int i = 0, ix = 1; i < bufferlen; i++, ix += in_c) {
+ right[i] += readbuffer[ix] * _rightgain;
+ }
+ }
+
+ }
+
+ if (_eff1gain > 0.0001) {
+ float[] eff1 = buffers[SoftMixingMainMixer.CHANNEL_EFFECT1]
+ .array();
+ for (int i = 0, ix = 0; i < bufferlen; i++, ix += in_c) {
+ eff1[i] += readbuffer[ix] * _eff1gain;
+ }
+ if (in_nrofchannels == 2) {
+ for (int i = 0, ix = 1; i < bufferlen; i++, ix += in_c) {
+ eff1[i] += readbuffer[ix] * _eff1gain;
+ }
+ }
+ }
+
+ if (_eff2gain > 0.0001) {
+ float[] eff2 = buffers[SoftMixingMainMixer.CHANNEL_EFFECT2]
+ .array();
+ for (int i = 0, ix = 0; i < bufferlen; i++, ix += in_c) {
+ eff2[i] += readbuffer[ix] * _eff2gain;
+ }
+ if (in_nrofchannels == 2) {
+ for (int i = 0, ix = 1; i < bufferlen; i++, ix += in_c) {
+ eff2[i] += readbuffer[ix] * _eff2gain;
+ }
+ }
+ }
+
+ }
+ }
+
+ public void open() throws LineUnavailableException {
+ open(format);
+ }
+
+ public void open(AudioFormat format) throws LineUnavailableException {
+ if (bufferSize == -1)
+ bufferSize = ((int) (format.getFrameRate() / 2))
+ * format.getFrameSize();
+ open(format, bufferSize);
+ }
+
+ public void open(AudioFormat format, int bufferSize)
+ throws LineUnavailableException {
+
+ LineEvent event = null;
+
+ if (bufferSize < format.getFrameSize() * 32)
+ bufferSize = format.getFrameSize() * 32;
+
+ synchronized (control_mutex) {
+
+ if (!isOpen()) {
+ if (!mixer.isOpen()) {
+ mixer.open();
+ mixer.implicitOpen = true;
+ }
+
+ event = new LineEvent(this, LineEvent.Type.OPEN, 0);
+
+ this.bufferSize = bufferSize - bufferSize
+ % format.getFrameSize();
+ this.format = format;
+ this.framesize = format.getFrameSize();
+ this.outputformat = mixer.getFormat();
+ out_nrofchannels = outputformat.getChannels();
+ in_nrofchannels = format.getChannels();
+
+ open = true;
+
+ mixer.getMainMixer().openLine(this);
+
+ cycling_buffer = new byte[framesize * bufferSize];
+ cycling_read_pos = 0;
+ cycling_write_pos = 0;
+ cycling_avail = 0;
+ cycling_framepos = 0;
+
+ InputStream cycling_inputstream = new InputStream() {
+
+ 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 available() throws IOException {
+ synchronized (cycling_buffer) {
+ return cycling_avail;
+ }
+ }
+
+ public int read(byte[] b, int off, int len)
+ throws IOException {
+
+ synchronized (cycling_buffer) {
+ if (len > cycling_avail)
+ len = cycling_avail;
+ int pos = cycling_read_pos;
+ byte[] buff = cycling_buffer;
+ int buff_len = buff.length;
+ for (int i = 0; i < len; i++) {
+ b[off++] = buff[pos];
+ pos++;
+ if (pos == buff_len)
+ pos = 0;
+ }
+ cycling_read_pos = pos;
+ cycling_avail -= len;
+ cycling_framepos += len / framesize;
+ }
+ return len;
+ }
+
+ };
+
+ afis = AudioFloatInputStream
+ .getInputStream(new AudioInputStream(
+ cycling_inputstream, format,
+ AudioSystem.NOT_SPECIFIED));
+ afis = new NonBlockingFloatInputStream(afis);
+
+ if (Math.abs(format.getSampleRate()
+ - outputformat.getSampleRate()) > 0.000001)
+ afis = new AudioFloatInputStreamResampler(afis,
+ outputformat);
+
+ } else {
+ if (!format.matches(getFormat())) {
+ throw new IllegalStateException(
+ "Line is already open with format " + getFormat()
+ + " and bufferSize " + getBufferSize());
+ }
+ }
+
+ }
+
+ if (event != null)
+ sendEvent(event);
+
+ }
+
+ public int available() {
+ synchronized (cycling_buffer) {
+ return cycling_buffer.length - cycling_avail;
+ }
+ }
+
+ public void drain() {
+ while (true) {
+ int avail;
+ synchronized (cycling_buffer) {
+ avail = cycling_avail;
+ }
+ if (avail != 0)
+ return;
+ try {
+ Thread.sleep(1);
+ } catch (InterruptedException e) {
+ return;
+ }
+ }
+ }
+
+ public void flush() {
+ synchronized (cycling_buffer) {
+ cycling_read_pos = 0;
+ cycling_write_pos = 0;
+ cycling_avail = 0;
+ }
+ }
+
+ public int getBufferSize() {
+ synchronized (control_mutex) {
+ return bufferSize;
+ }
+ }
+
+ public AudioFormat getFormat() {
+ synchronized (control_mutex) {
+ return format;
+ }
+ }
+
+ public int getFramePosition() {
+ return (int) getLongFramePosition();
+ }
+
+ public float getLevel() {
+ return AudioSystem.NOT_SPECIFIED;
+ }
+
+ public long getLongFramePosition() {
+ synchronized (cycling_buffer) {
+ return cycling_framepos;
+ }
+ }
+
+ public long getMicrosecondPosition() {
+ return (long) (getLongFramePosition() * (1000000.0 / (double) getFormat()
+ .getSampleRate()));
+ }
+
+ public boolean isActive() {
+ synchronized (control_mutex) {
+ return active;
+ }
+ }
+
+ public boolean isRunning() {
+ synchronized (control_mutex) {
+ return active;
+ }
+ }
+
+ public void start() {
+
+ LineEvent event = null;
+
+ synchronized (control_mutex) {
+ if (isOpen()) {
+ if (active)
+ return;
+ active = true;
+ event = new LineEvent(this, LineEvent.Type.START,
+ getLongFramePosition());
+ }
+ }
+
+ if (event != null)
+ sendEvent(event);
+ }
+
+ public void stop() {
+ LineEvent event = null;
+
+ synchronized (control_mutex) {
+ if (isOpen()) {
+ if (!active)
+ return;
+ active = false;
+ event = new LineEvent(this, LineEvent.Type.STOP,
+ getLongFramePosition());
+ }
+ }
+
+ if (event != null)
+ sendEvent(event);
+ }
+
+ public void close() {
+
+ LineEvent event = null;
+
+ synchronized (control_mutex) {
+ if (!isOpen())
+ return;
+ stop();
+
+ event = new LineEvent(this, LineEvent.Type.CLOSE,
+ getLongFramePosition());
+
+ open = false;
+ mixer.getMainMixer().closeLine(this);
+ }
+
+ if (event != null)
+ sendEvent(event);
+
+ }
+
+ public boolean isOpen() {
+ synchronized (control_mutex) {
+ return open;
+ }
+ }
+
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SoftPerformer.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SoftPerformer.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,775 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This class decodes information from ModelPeformer for use in SoftVoice.
+ * It also adds default connections if they where missing in ModelPerformer.
+ *
+ * @author Karl Helgason
+ */
+public class SoftPerformer {
+
+ static ModelConnectionBlock[] defaultconnections
+ = new ModelConnectionBlock[42];
+
+ static {
+ int o = 0;
+ defaultconnections[o++] = new ModelConnectionBlock(
+ new ModelSource(
+ new ModelIdentifier("noteon", "on", 0),
+ ModelStandardTransform.DIRECTION_MIN2MAX,
+ ModelStandardTransform.POLARITY_UNIPOLAR,
+ ModelStandardTransform.TRANSFORM_LINEAR),
+ 1, new ModelDestination(new ModelIdentifier("eg", "on", 0)));
+
+ defaultconnections[o++] = new ModelConnectionBlock(
+ new ModelSource(
+ new ModelIdentifier("noteon", "on", 0),
+ ModelStandardTransform.DIRECTION_MIN2MAX,
+ ModelStandardTransform.POLARITY_UNIPOLAR,
+ ModelStandardTransform.TRANSFORM_LINEAR),
+ 1, new ModelDestination(new ModelIdentifier("eg", "on", 1)));
+
+ defaultconnections[o++] = new ModelConnectionBlock(
+ new ModelSource(
+ new ModelIdentifier("eg", "active", 0),
+ ModelStandardTransform.DIRECTION_MIN2MAX,
+ ModelStandardTransform.POLARITY_UNIPOLAR,
+ ModelStandardTransform.TRANSFORM_LINEAR),
+ 1, new ModelDestination(new ModelIdentifier("mixer", "active", 0)));
+
+ defaultconnections[o++] = new ModelConnectionBlock(
+ new ModelSource(
+ new ModelIdentifier("eg", 0),
+ ModelStandardTransform.DIRECTION_MAX2MIN,
+ ModelStandardTransform.POLARITY_UNIPOLAR,
+ ModelStandardTransform.TRANSFORM_LINEAR),
+ -960, new ModelDestination(new ModelIdentifier("mixer", "gain")));
+
+ defaultconnections[o++] = new ModelConnectionBlock(
+ new ModelSource(
+ new ModelIdentifier("noteon", "velocity"),
+ ModelStandardTransform.DIRECTION_MAX2MIN,
+ ModelStandardTransform.POLARITY_UNIPOLAR,
+ ModelStandardTransform.TRANSFORM_CONCAVE),
+ -960, new ModelDestination(new ModelIdentifier("mixer", "gain")));
+
+ defaultconnections[o++] = new ModelConnectionBlock(
+ new ModelSource(
+ new ModelIdentifier("midi", "pitch"),
+ ModelStandardTransform.DIRECTION_MIN2MAX,
+ ModelStandardTransform.POLARITY_BIPOLAR,
+ ModelStandardTransform.TRANSFORM_LINEAR),
+ new ModelSource(new ModelIdentifier("midi_rpn", "0"),
+ new ModelTransform() {
+ public double transform(double value) {
+ int v = (int) (value * 16384.0);
+ int msb = v >> 7;
+ int lsb = v & 127;
+ return msb * 100 + lsb;
+ }
+ }),
+ new ModelDestination(new ModelIdentifier("osc", "pitch")));
+
+ defaultconnections[o++] = new ModelConnectionBlock(
+ new ModelSource(
+ new ModelIdentifier("noteon", "keynumber"),
+ ModelStandardTransform.DIRECTION_MIN2MAX,
+ ModelStandardTransform.POLARITY_UNIPOLAR,
+ ModelStandardTransform.TRANSFORM_LINEAR),
+ 12800, new ModelDestination(new ModelIdentifier("osc", "pitch")));
+
+ defaultconnections[o++] = new ModelConnectionBlock(
+ new ModelSource(
+ new ModelIdentifier("midi_cc", "7"),
+ ModelStandardTransform.DIRECTION_MAX2MIN,
+ ModelStandardTransform.POLARITY_UNIPOLAR,
+ ModelStandardTransform.TRANSFORM_CONCAVE),
+ -960, new ModelDestination(new ModelIdentifier("mixer", "gain")));
+
+ defaultconnections[o++] = new ModelConnectionBlock(
+ new ModelSource(
+ new ModelIdentifier("midi_cc", "8"),
+ ModelStandardTransform.DIRECTION_MIN2MAX,
+ ModelStandardTransform.POLARITY_UNIPOLAR,
+ ModelStandardTransform.TRANSFORM_LINEAR),
+ 1000, new ModelDestination(new ModelIdentifier("mixer", "balance")));
+
+ defaultconnections[o++] = new ModelConnectionBlock(
+ new ModelSource(
+ new ModelIdentifier("midi_cc", "10"),
+ ModelStandardTransform.DIRECTION_MIN2MAX,
+ ModelStandardTransform.POLARITY_UNIPOLAR,
+ ModelStandardTransform.TRANSFORM_LINEAR),
+ 1000, new ModelDestination(new ModelIdentifier("mixer", "pan")));
+
+ defaultconnections[o++] = new ModelConnectionBlock(
+ new ModelSource(
+ new ModelIdentifier("midi_cc", "11"),
+ ModelStandardTransform.DIRECTION_MAX2MIN,
+ ModelStandardTransform.POLARITY_UNIPOLAR,
+ ModelStandardTransform.TRANSFORM_CONCAVE),
+ -960, new ModelDestination(new ModelIdentifier("mixer", "gain")));
+
+ defaultconnections[o++] = new ModelConnectionBlock(
+ new ModelSource(
+ new ModelIdentifier("midi_cc", "91"),
+ ModelStandardTransform.DIRECTION_MIN2MAX,
+ ModelStandardTransform.POLARITY_UNIPOLAR,
+ ModelStandardTransform.TRANSFORM_LINEAR),
+ 1000, new ModelDestination(new ModelIdentifier("mixer", "reverb")));
+
+ defaultconnections[o++] = new ModelConnectionBlock(
+ new ModelSource(
+ new ModelIdentifier("midi_cc", "93"),
+ ModelStandardTransform.DIRECTION_MIN2MAX,
+ ModelStandardTransform.POLARITY_UNIPOLAR,
+ ModelStandardTransform.TRANSFORM_LINEAR),
+ 1000, new ModelDestination(new ModelIdentifier("mixer", "chorus")));
+
+ defaultconnections[o++] = new ModelConnectionBlock(
+ new ModelSource(
+ new ModelIdentifier("midi_cc", "71"),
+ ModelStandardTransform.DIRECTION_MIN2MAX,
+ ModelStandardTransform.POLARITY_BIPOLAR,
+ ModelStandardTransform.TRANSFORM_LINEAR),
+ 200, new ModelDestination(new ModelIdentifier("filter", "q")));
+ defaultconnections[o++] = new ModelConnectionBlock(
+ new ModelSource(
+ new ModelIdentifier("midi_cc", "74"),
+ ModelStandardTransform.DIRECTION_MIN2MAX,
+ ModelStandardTransform.POLARITY_BIPOLAR,
+ ModelStandardTransform.TRANSFORM_LINEAR),
+ 9600, new ModelDestination(new ModelIdentifier("filter", "freq")));
+
+ defaultconnections[o++] = new ModelConnectionBlock(
+ new ModelSource(
+ new ModelIdentifier("midi_cc", "72"),
+ ModelStandardTransform.DIRECTION_MIN2MAX,
+ ModelStandardTransform.POLARITY_BIPOLAR,
+ ModelStandardTransform.TRANSFORM_LINEAR),
+ 6000, new ModelDestination(new ModelIdentifier("eg", "release2")));
+
+ defaultconnections[o++] = new ModelConnectionBlock(
+ new ModelSource(
+ new ModelIdentifier("midi_cc", "73"),
+ ModelStandardTransform.DIRECTION_MIN2MAX,
+ ModelStandardTransform.POLARITY_BIPOLAR,
+ ModelStandardTransform.TRANSFORM_LINEAR),
+ 2000, new ModelDestination(new ModelIdentifier("eg", "attack2")));
+
+ defaultconnections[o++] = new ModelConnectionBlock(
+ new ModelSource(
+ new ModelIdentifier("midi_cc", "75"),
+ ModelStandardTransform.DIRECTION_MIN2MAX,
+ ModelStandardTransform.POLARITY_BIPOLAR,
+ ModelStandardTransform.TRANSFORM_LINEAR),
+ 6000, new ModelDestination(new ModelIdentifier("eg", "decay2")));
+
+ defaultconnections[o++] = new ModelConnectionBlock(
+ new ModelSource(
+ new ModelIdentifier("midi_cc", "67"),
+ ModelStandardTransform.DIRECTION_MIN2MAX,
+ ModelStandardTransform.POLARITY_UNIPOLAR,
+ ModelStandardTransform.TRANSFORM_SWITCH),
+ -50, new ModelDestination(ModelDestination.DESTINATION_GAIN));
+
+ defaultconnections[o++] = new ModelConnectionBlock(
+ new ModelSource(
+ new ModelIdentifier("midi_cc", "67"),
+ ModelStandardTransform.DIRECTION_MIN2MAX,
+ ModelStandardTransform.POLARITY_UNIPOLAR,
+ ModelStandardTransform.TRANSFORM_SWITCH),
+ -2400, new ModelDestination(ModelDestination.DESTINATION_FILTER_FREQ));
+
+ defaultconnections[o++] = new ModelConnectionBlock(
+ new ModelSource(
+ new ModelIdentifier("midi_rpn", "1"),
+ ModelStandardTransform.DIRECTION_MIN2MAX,
+ ModelStandardTransform.POLARITY_BIPOLAR,
+ ModelStandardTransform.TRANSFORM_LINEAR),
+ 100, new ModelDestination(new ModelIdentifier("osc", "pitch")));
+
+ defaultconnections[o++] = new ModelConnectionBlock(
+ new ModelSource(
+ new ModelIdentifier("midi_rpn", "2"),
+ ModelStandardTransform.DIRECTION_MIN2MAX,
+ ModelStandardTransform.POLARITY_BIPOLAR,
+ ModelStandardTransform.TRANSFORM_LINEAR),
+ 12800, new ModelDestination(new ModelIdentifier("osc", "pitch")));
+
+ defaultconnections[o++] = new ModelConnectionBlock(
+ new ModelSource(
+ new ModelIdentifier("master", "fine_tuning"),
+ ModelStandardTransform.DIRECTION_MIN2MAX,
+ ModelStandardTransform.POLARITY_BIPOLAR,
+ ModelStandardTransform.TRANSFORM_LINEAR),
+ 100, new ModelDestination(new ModelIdentifier("osc", "pitch")));
+
+ defaultconnections[o++] = new ModelConnectionBlock(
+ new ModelSource(
+ new ModelIdentifier("master", "coarse_tuning"),
+ ModelStandardTransform.DIRECTION_MIN2MAX,
+ ModelStandardTransform.POLARITY_BIPOLAR,
+ ModelStandardTransform.TRANSFORM_LINEAR),
+ 12800, new ModelDestination(new ModelIdentifier("osc", "pitch")));
+
+ defaultconnections[o++] = new ModelConnectionBlock(13500,
+ new ModelDestination(new ModelIdentifier("filter", "freq", 0)));
+
+ defaultconnections[o++] = new ModelConnectionBlock(
+ Float.NEGATIVE_INFINITY, new ModelDestination(
+ new ModelIdentifier("eg", "delay", 0)));
+ defaultconnections[o++] = new ModelConnectionBlock(
+ Float.NEGATIVE_INFINITY, new ModelDestination(
+ new ModelIdentifier("eg", "attack", 0)));
+ defaultconnections[o++] = new ModelConnectionBlock(
+ Float.NEGATIVE_INFINITY, new ModelDestination(
+ new ModelIdentifier("eg", "hold", 0)));
+ defaultconnections[o++] = new ModelConnectionBlock(
+ Float.NEGATIVE_INFINITY, new ModelDestination(
+ new ModelIdentifier("eg", "decay", 0)));
+ defaultconnections[o++] = new ModelConnectionBlock(1000,
+ new ModelDestination(new ModelIdentifier("eg", "sustain", 0)));
+ defaultconnections[o++] = new ModelConnectionBlock(
+ Float.NEGATIVE_INFINITY, new ModelDestination(
+ new ModelIdentifier("eg", "release", 0)));
+ defaultconnections[o++] = new ModelConnectionBlock(1200.0
+ * Math.log(0.015) / Math.log(2), new ModelDestination(
+ new ModelIdentifier("eg", "shutdown", 0))); // 15 msec default
+
+ defaultconnections[o++] = new ModelConnectionBlock(
+ Float.NEGATIVE_INFINITY, new ModelDestination(
+ new ModelIdentifier("eg", "delay", 1)));
+ defaultconnections[o++] = new ModelConnectionBlock(
+ Float.NEGATIVE_INFINITY, new ModelDestination(
+ new ModelIdentifier("eg", "attack", 1)));
+ defaultconnections[o++] = new ModelConnectionBlock(
+ Float.NEGATIVE_INFINITY, new ModelDestination(
+ new ModelIdentifier("eg", "hold", 1)));
+ defaultconnections[o++] = new ModelConnectionBlock(
+ Float.NEGATIVE_INFINITY, new ModelDestination(
+ new ModelIdentifier("eg", "decay", 1)));
+ defaultconnections[o++] = new ModelConnectionBlock(1000,
+ new ModelDestination(new ModelIdentifier("eg", "sustain", 1)));
+ defaultconnections[o++] = new ModelConnectionBlock(
+ Float.NEGATIVE_INFINITY, new ModelDestination(
+ new ModelIdentifier("eg", "release", 1)));
+
+ defaultconnections[o++] = new ModelConnectionBlock(-8.51318,
+ new ModelDestination(new ModelIdentifier("lfo", "freq", 0)));
+ defaultconnections[o++] = new ModelConnectionBlock(
+ Float.NEGATIVE_INFINITY, new ModelDestination(
+ new ModelIdentifier("lfo", "delay", 0)));
+ defaultconnections[o++] = new ModelConnectionBlock(-8.51318,
+ new ModelDestination(new ModelIdentifier("lfo", "freq", 1)));
+ defaultconnections[o++] = new ModelConnectionBlock(
+ Float.NEGATIVE_INFINITY, new ModelDestination(
+ new ModelIdentifier("lfo", "delay", 1)));
+
+ }
+ public int keyFrom = 0;
+ public int keyTo = 127;
+ public int velFrom = 0;
+ public int velTo = 127;
+ public int exclusiveClass = 0;
+ public boolean selfNonExclusive = false;
+ public boolean forcedVelocity = false;
+ public boolean forcedKeynumber = false;
+ public ModelPerformer performer;
+ public ModelConnectionBlock[] connections;
+ public ModelOscillator[] oscillators;
+ public Map midi_rpn_connections = new HashMap();
+ public Map midi_nrpn_connections = new HashMap();
+ public int[][] midi_ctrl_connections;
+ public int[][] midi_connections;
+ public int[] ctrl_connections;
+ private List ctrl_connections_list = new ArrayList();
+
+ private static class KeySortComparator implements Comparator {
+
+ public int compare(ModelSource o1, ModelSource o2) {
+ return o1.getIdentifier().toString().compareTo(
+ o2.getIdentifier().toString());
+ }
+ }
+ private static KeySortComparator keySortComparator = new KeySortComparator();
+
+ private String extractKeys(ModelConnectionBlock conn) {
+ StringBuffer sb = new StringBuffer();
+ if (conn.getSources() != null) {
+ sb.append("[");
+ ModelSource[] srcs = conn.getSources();
+ ModelSource[] srcs2 = new ModelSource[srcs.length];
+ for (int i = 0; i < srcs.length; i++)
+ srcs2[i] = srcs[i];
+ Arrays.sort(srcs2, keySortComparator);
+ for (int i = 0; i < srcs.length; i++) {
+ sb.append(srcs[i].getIdentifier());
+ sb.append(";");
+ }
+ sb.append("]");
+ }
+ sb.append(";");
+ if (conn.getDestination() != null) {
+ sb.append(conn.getDestination().getIdentifier());
+ }
+ sb.append(";");
+ return sb.toString();
+ }
+
+ private void processSource(ModelSource src, int ix) {
+ ModelIdentifier id = src.getIdentifier();
+ String o = id.getObject();
+ if (o.equals("midi_cc"))
+ processMidiControlSource(src, ix);
+ else if (o.equals("midi_rpn"))
+ processMidiRpnSource(src, ix);
+ else if (o.equals("midi_nrpn"))
+ processMidiNrpnSource(src, ix);
+ else if (o.equals("midi"))
+ processMidiSource(src, ix);
+ else if (o.equals("noteon"))
+ processNoteOnSource(src, ix);
+ else if (o.equals("osc"))
+ return;
+ else if (o.equals("mixer"))
+ return;
+ else
+ ctrl_connections_list.add(ix);
+ }
+
+ private void processMidiControlSource(ModelSource src, int ix) {
+ String v = src.getIdentifier().getVariable();
+ if (v == null)
+ return;
+ int c = Integer.parseInt(v);
+ if (midi_ctrl_connections[c] == null)
+ midi_ctrl_connections[c] = new int[]{ix};
+ else {
+ int[] olda = midi_ctrl_connections[c];
+ int[] newa = new int[olda.length + 1];
+ for (int i = 0; i < olda.length; i++)
+ newa[i] = olda[i];
+ newa[newa.length - 1] = ix;
+ midi_ctrl_connections[c] = newa;
+ }
+ }
+
+ private void processNoteOnSource(ModelSource src, int ix) {
+ String v = src.getIdentifier().getVariable();
+ int c = -1;
+ if (v.equals("on"))
+ c = 3;
+ if (v.equals("keynumber"))
+ c = 4;
+ if (c == -1)
+ return;
+ if (midi_connections[c] == null)
+ midi_connections[c] = new int[]{ix};
+ else {
+ int[] olda = midi_connections[c];
+ int[] newa = new int[olda.length + 1];
+ for (int i = 0; i < olda.length; i++)
+ newa[i] = olda[i];
+ newa[newa.length - 1] = ix;
+ midi_connections[c] = newa;
+ }
+ }
+
+ private void processMidiSource(ModelSource src, int ix) {
+ String v = src.getIdentifier().getVariable();
+ int c = -1;
+ if (v.equals("pitch"))
+ c = 0;
+ if (v.equals("channel_pressure"))
+ c = 1;
+ if (v.equals("poly_pressure"))
+ c = 2;
+ if (c == -1)
+ return;
+ if (midi_connections[c] == null)
+ midi_connections[c] = new int[]{ix};
+ else {
+ int[] olda = midi_connections[c];
+ int[] newa = new int[olda.length + 1];
+ for (int i = 0; i < olda.length; i++)
+ newa[i] = olda[i];
+ newa[newa.length - 1] = ix;
+ midi_connections[c] = newa;
+ }
+ }
+
+ private void processMidiRpnSource(ModelSource src, int ix) {
+ String v = src.getIdentifier().getVariable();
+ if (v == null)
+ return;
+ int c = Integer.parseInt(v);
+ if (midi_rpn_connections.get(c) == null)
+ midi_rpn_connections.put(c, new int[]{ix});
+ else {
+ int[] olda = midi_rpn_connections.get(c);
+ int[] newa = new int[olda.length + 1];
+ for (int i = 0; i < olda.length; i++)
+ newa[i] = olda[i];
+ newa[newa.length - 1] = ix;
+ midi_rpn_connections.put(c, newa);
+ }
+ }
+
+ private void processMidiNrpnSource(ModelSource src, int ix) {
+ String v = src.getIdentifier().getVariable();
+ if (v == null)
+ return;
+ int c = Integer.parseInt(v);
+ if (midi_nrpn_connections.get(c) == null)
+ midi_nrpn_connections.put(c, new int[]{ix});
+ else {
+ int[] olda = midi_nrpn_connections.get(c);
+ int[] newa = new int[olda.length + 1];
+ for (int i = 0; i < olda.length; i++)
+ newa[i] = olda[i];
+ newa[newa.length - 1] = ix;
+ midi_nrpn_connections.put(c, newa);
+ }
+ }
+
+ public SoftPerformer(ModelPerformer performer) {
+ this.performer = performer;
+
+ keyFrom = performer.getKeyFrom();
+ keyTo = performer.getKeyTo();
+ velFrom = performer.getVelFrom();
+ velTo = performer.getVelTo();
+ exclusiveClass = performer.getExclusiveClass();
+ selfNonExclusive = performer.isSelfNonExclusive();
+
+ Map connmap = new HashMap();
+
+ List performer_connections = new ArrayList();
+ performer_connections.addAll(performer.getConnectionBlocks());
+
+ if (performer.isDefaultConnectionsEnabled()) {
+
+ // Add modulation depth range (RPN 5) to the modulation wheel (cc#1)
+
+ boolean isModulationWheelConectionFound = false;
+ for (int j = 0; j < performer_connections.size(); j++) {
+ ModelConnectionBlock connection = performer_connections.get(j);
+ ModelSource[] sources = connection.getSources();
+ ModelDestination dest = connection.getDestination();
+ boolean isModulationWheelConection = false;
+ if (dest != null && sources != null && sources.length > 1) {
+ for (int i = 0; i < sources.length; i++) {
+ // check if connection block has the source "modulation
+ // wheel cc#1"
+ if (sources[i].getIdentifier().getObject().equals(
+ "midi_cc")) {
+ if (sources[i].getIdentifier().getVariable()
+ .equals("1")) {
+ isModulationWheelConection = true;
+ isModulationWheelConectionFound = true;
+ break;
+ }
+ }
+ }
+ }
+ if (isModulationWheelConection) {
+
+ ModelConnectionBlock newconnection = new ModelConnectionBlock();
+ newconnection.setSources(connection.getSources());
+ newconnection.setDestination(connection.getDestination());
+ newconnection.addSource(new ModelSource(
+ new ModelIdentifier("midi_rpn", "5")));
+ newconnection.setScale(connection.getScale() * 256.0);
+ performer_connections.set(j, newconnection);
+ }
+ }
+
+ if (!isModulationWheelConectionFound) {
+ ModelConnectionBlock conn = new ModelConnectionBlock(
+ new ModelSource(ModelSource.SOURCE_LFO1,
+ 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));
+ conn.addSource(new ModelSource(new ModelIdentifier("midi_rpn",
+ "5")));
+ conn.setScale(conn.getScale() * 256.0);
+ performer_connections.add(conn);
+
+ }
+
+ // Let Aftertouch to behave just like modulation wheel (cc#1)
+ boolean channel_pressure_set = false;
+ boolean poly_pressure = false;
+ ModelConnectionBlock mod_cc_1_connection = null;
+ int mod_cc_1_connection_src_ix = 0;
+
+ for (ModelConnectionBlock connection : performer_connections) {
+ ModelSource[] sources = connection.getSources();
+ ModelDestination dest = connection.getDestination();
+ // if(dest != null && sources != null)
+ if (dest != null && sources != null) {
+ for (int i = 0; i < sources.length; i++) {
+ ModelIdentifier srcid = sources[i].getIdentifier();
+ // check if connection block has the source "modulation
+ // wheel cc#1"
+ if (srcid.getObject().equals("midi_cc")) {
+ if (srcid.getVariable().equals("1")) {
+ mod_cc_1_connection = connection;
+ mod_cc_1_connection_src_ix = i;
+ }
+ }
+ // check if channel or poly pressure are already
+ // connected
+ if (srcid.getObject().equals("midi")) {
+ if (srcid.getVariable().equals("channel_pressure"))
+ channel_pressure_set = true;
+ if (srcid.getVariable().equals("poly_pressure"))
+ poly_pressure = true;
+ }
+ }
+ }
+
+ }
+
+ if (mod_cc_1_connection != null) {
+ if (!channel_pressure_set) {
+ ModelConnectionBlock mc = new ModelConnectionBlock();
+ mc.setDestination(mod_cc_1_connection.getDestination());
+ mc.setScale(mod_cc_1_connection.getScale());
+ ModelSource[] src_list = mod_cc_1_connection.getSources();
+ ModelSource[] src_list_new = new ModelSource[src_list.length];
+ for (int i = 0; i < src_list_new.length; i++)
+ src_list_new[i] = src_list[i];
+ src_list_new[mod_cc_1_connection_src_ix] = new ModelSource(
+ new ModelIdentifier("midi", "channel_pressure"));
+ mc.setSources(src_list_new);
+ connmap.put(extractKeys(mc), mc);
+ }
+ if (!poly_pressure) {
+ ModelConnectionBlock mc = new ModelConnectionBlock();
+ mc.setDestination(mod_cc_1_connection.getDestination());
+ mc.setScale(mod_cc_1_connection.getScale());
+ ModelSource[] src_list = mod_cc_1_connection.getSources();
+ ModelSource[] src_list_new = new ModelSource[src_list.length];
+ for (int i = 0; i < src_list_new.length; i++)
+ src_list_new[i] = src_list[i];
+ src_list_new[mod_cc_1_connection_src_ix] = new ModelSource(
+ new ModelIdentifier("midi", "poly_pressure"));
+ mc.setSources(src_list_new);
+ connmap.put(extractKeys(mc), mc);
+ }
+ }
+
+ // Enable Vibration Sound Controllers : 76, 77, 78
+ ModelConnectionBlock found_vib_connection = null;
+ for (ModelConnectionBlock connection : performer_connections) {
+ ModelSource[] sources = connection.getSources();
+ if (sources.length != 0
+ && sources[0].getIdentifier().getObject().equals("lfo")) {
+ if (connection.getDestination().getIdentifier().equals(
+ ModelDestination.DESTINATION_PITCH)) {
+ if (found_vib_connection == null)
+ found_vib_connection = connection;
+ else {
+ if (found_vib_connection.getSources().length > sources.length)
+ found_vib_connection = connection;
+ else if (found_vib_connection.getSources()[0]
+ .getIdentifier().getInstance() < 1) {
+ if (found_vib_connection.getSources()[0]
+ .getIdentifier().getInstance() >
+ sources[0].getIdentifier().getInstance()) {
+ found_vib_connection = connection;
+ }
+ }
+ }
+
+ }
+ }
+ }
+
+ int instance = 1;
+
+ if (found_vib_connection != null) {
+ instance = found_vib_connection.getSources()[0].getIdentifier()
+ .getInstance();
+ }
+ ModelConnectionBlock connection;
+
+ connection = new ModelConnectionBlock(
+ new ModelSource(new ModelIdentifier("midi_cc", "78"),
+ ModelStandardTransform.DIRECTION_MIN2MAX,
+ ModelStandardTransform.POLARITY_BIPOLAR,
+ ModelStandardTransform.TRANSFORM_LINEAR),
+ 2000, new ModelDestination(
+ new ModelIdentifier("lfo", "delay2", instance)));
+ connmap.put(extractKeys(connection), connection);
+
+ final double scale = found_vib_connection == null ? 0
+ : found_vib_connection.getScale();
+ connection = new ModelConnectionBlock(
+ new ModelSource(new ModelIdentifier("lfo", instance)),
+ new ModelSource(new ModelIdentifier("midi_cc", "77"),
+ new ModelTransform() {
+ double s = scale;
+ public double transform(double value) {
+ value = value * 2 - 1;
+ value *= 600;
+ if (s == 0) {
+ return value;
+ } else if (s > 0) {
+ if (value < -s)
+ value = -s;
+ return value;
+ } else {
+ if (value < s)
+ value = -s;
+ return -value;
+ }
+ }
+ }), new ModelDestination(ModelDestination.DESTINATION_PITCH));
+ connmap.put(extractKeys(connection), connection);
+
+ connection = new ModelConnectionBlock(
+ new ModelSource(new ModelIdentifier("midi_cc", "76"),
+ ModelStandardTransform.DIRECTION_MIN2MAX,
+ ModelStandardTransform.POLARITY_BIPOLAR,
+ ModelStandardTransform.TRANSFORM_LINEAR),
+ 2400, new ModelDestination(
+ new ModelIdentifier("lfo", "freq", instance)));
+ connmap.put(extractKeys(connection), connection);
+
+ }
+
+ // Add default connection blocks
+ if (performer.isDefaultConnectionsEnabled())
+ for (ModelConnectionBlock connection : defaultconnections)
+ connmap.put(extractKeys(connection), connection);
+ // Add connection blocks from modelperformer
+ for (ModelConnectionBlock connection : performer_connections)
+ connmap.put(extractKeys(connection), connection);
+ // seperate connection blocks : Init time, Midi Time, Midi/Control Time,
+ // Control Time
+ List connections = new ArrayList();
+
+ midi_ctrl_connections = new int[128][];
+ for (int i = 0; i < midi_ctrl_connections.length; i++) {
+ midi_ctrl_connections[i] = null;
+ }
+ midi_connections = new int[5][];
+ for (int i = 0; i < midi_connections.length; i++) {
+ midi_connections[i] = null;
+ }
+
+ int ix = 0;
+ boolean mustBeOnTop = false;
+
+ for (ModelConnectionBlock connection : connmap.values()) {
+ if (connection.getDestination() != null) {
+ ModelDestination dest = connection.getDestination();
+ ModelIdentifier id = dest.getIdentifier();
+ if (id.getObject().equals("noteon")) {
+ mustBeOnTop = true;
+ if (id.getVariable().equals("keynumber"))
+ forcedKeynumber = true;
+ if (id.getVariable().equals("velocity"))
+ forcedVelocity = true;
+ }
+ }
+ if (mustBeOnTop) {
+ connections.add(0, connection);
+ mustBeOnTop = false;
+ } else
+ connections.add(connection);
+ }
+
+ for (ModelConnectionBlock connection : connections) {
+ if (connection.getSources() != null) {
+ ModelSource[] srcs = connection.getSources();
+ for (int i = 0; i < srcs.length; i++) {
+ processSource(srcs[i], ix);
+ }
+ }
+ ix++;
+ }
+
+ this.connections = new ModelConnectionBlock[connections.size()];
+ connections.toArray(this.connections);
+
+ this.ctrl_connections = new int[ctrl_connections_list.size()];
+
+ for (int i = 0; i < this.ctrl_connections.length; i++)
+ this.ctrl_connections[i] = ctrl_connections_list.get(i);
+
+ oscillators = new ModelOscillator[performer.getOscillators().size()];
+ performer.getOscillators().toArray(oscillators);
+
+ for (ModelConnectionBlock conn : connections) {
+ if (conn.getDestination() != null) {
+ if (isUnnecessaryTransform(conn.getDestination().getTransform())) {
+ conn.getDestination().setTransform(null);
+ }
+ }
+ if (conn.getSources() != null) {
+ for (ModelSource src : conn.getSources()) {
+ if (isUnnecessaryTransform(src.getTransform())) {
+ src.setTransform(null);
+ }
+ }
+ }
+ }
+
+ }
+
+ private static boolean isUnnecessaryTransform(ModelTransform transform) {
+ if (transform == null)
+ return false;
+ if (!(transform instanceof ModelStandardTransform))
+ return false;
+ ModelStandardTransform stransform = (ModelStandardTransform)transform;
+ if (stransform.getDirection() != ModelStandardTransform.DIRECTION_MIN2MAX)
+ return false;
+ if (stransform.getPolarity() != ModelStandardTransform.POLARITY_UNIPOLAR)
+ return false;
+ if (stransform.getTransform() != ModelStandardTransform.TRANSFORM_LINEAR)
+ return false;
+ return false;
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SoftPointResampler.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SoftPointResampler.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.media.sound;
+
+/**
+ * A resampler that uses 0-order (nearest-neighbor) interpolation.
+ *
+ * @author Karl Helgason
+ */
+public class SoftPointResampler extends SoftAbstractResampler {
+
+ public int getPadding() {
+ return 100;
+ }
+
+ public void interpolate(float[] in, float[] in_offset, float in_end,
+ float[] startpitch, float pitchstep, float[] out, int[] out_offset,
+ int out_end) {
+ float pitch = startpitch[0];
+ float ix = in_offset[0];
+ int ox = out_offset[0];
+ float ix_end = in_end;
+ float ox_end = out_end;
+ if (pitchstep == 0) {
+ while (ix < ix_end && ox < ox_end) {
+ out[ox++] = in[(int) ix];
+ ix += pitch;
+ }
+ } else {
+ while (ix < ix_end && ox < ox_end) {
+ out[ox++] = in[(int) ix];
+ ix += pitch;
+ pitch += pitchstep;
+ }
+ }
+ in_offset[0] = ix;
+ out_offset[0] = ox;
+ startpitch[0] = pitch;
+
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SoftProcess.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SoftProcess.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.media.sound;
+
+/**
+ * Control signal processor interface
+ *
+ * @author Karl Helgason
+ */
+public interface SoftProcess extends SoftControl {
+
+ public void init(SoftSynthesizer synth);
+
+ public double[] get(int instance, String name);
+
+ public void processControlLogic();
+
+ public void reset();
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SoftProvider.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SoftProvider.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.media.sound;
+
+import javax.sound.midi.MidiDevice;
+import javax.sound.midi.MidiDevice.Info;
+import javax.sound.midi.spi.MidiDeviceProvider;
+
+/**
+ * Software synthesizer provider class.
+ *
+ * @author Karl Helgason
+ */
+public class SoftProvider extends MidiDeviceProvider {
+
+ protected final static Info softinfo = SoftSynthesizer.info;
+ private static Info[] softinfos = {softinfo};
+
+ public MidiDevice.Info[] getDeviceInfo() {
+ return softinfos;
+ }
+
+ public MidiDevice getDevice(MidiDevice.Info info) {
+ if (info == softinfo) {
+ return new SoftSynthesizer();
+ }
+ return null;
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SoftReceiver.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SoftReceiver.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.media.sound;
+
+import java.util.TreeMap;
+
+import javax.sound.midi.MidiMessage;
+import javax.sound.midi.Receiver;
+import javax.sound.midi.ShortMessage;
+
+/**
+ * Software synthesizer MIDI receiver class.
+ *
+ * @author Karl Helgason
+ */
+public class SoftReceiver implements Receiver {
+
+ protected boolean open = true;
+ private Object control_mutex;
+ private SoftSynthesizer synth;
+ protected TreeMap midimessages;
+ protected SoftMainMixer mainmixer;
+
+ public SoftReceiver(SoftSynthesizer synth) {
+ this.control_mutex = synth.control_mutex;
+ this.synth = synth;
+ this.mainmixer = synth.getMainMixer();
+ if (mainmixer != null)
+ this.midimessages = mainmixer.midimessages;
+ }
+
+ public void send(MidiMessage message, long timeStamp) {
+
+ synchronized (control_mutex) {
+ if (!open)
+ throw new IllegalStateException("Receiver is not open");
+ }
+
+ if (timeStamp != -1) {
+ synchronized (control_mutex) {
+ while (midimessages.get(timeStamp) != null)
+ timeStamp++;
+ if (message instanceof ShortMessage
+ && (((ShortMessage)message).getChannel() > 0xF)) {
+ midimessages.put(timeStamp, message.clone());
+ } else {
+ midimessages.put(timeStamp, message.getMessage());
+ }
+ }
+ } else {
+ mainmixer.processMessage(message);
+ }
+ }
+
+ public void close() {
+ synchronized (control_mutex) {
+ open = false;
+ }
+ synth.removeReceiver(this);
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SoftResampler.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SoftResampler.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.media.sound;
+
+/**
+ * Basic resampler interface.
+ *
+ * @author Karl Helgason
+ */
+public interface SoftResampler {
+
+ public SoftResamplerStreamer openStreamer();
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SoftResamplerStreamer.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SoftResamplerStreamer.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.media.sound;
+
+import java.io.IOException;
+
+/**
+ * Resampler stream interface.
+ *
+ * @author Karl Helgason
+ */
+public interface SoftResamplerStreamer extends ModelOscillatorStream {
+
+ public void open(ModelWavetable osc, float outputsamplerate)
+ throws IOException;
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SoftReverb.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SoftReverb.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,515 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.media.sound;
+
+import java.util.Arrays;
+
+/**
+ * Reverb effect based on allpass/comb filters. First audio is send to 8
+ * parelled comb filters and then mixed together and then finally send thru 3
+ * different allpass filters.
+ *
+ * @author Karl Helgason
+ */
+public class SoftReverb implements SoftAudioProcessor {
+
+ private final static class Delay {
+
+ private float[] delaybuffer;
+ private int rovepos = 0;
+
+ public Delay() {
+ delaybuffer = null;
+ }
+
+ public void setDelay(int delay) {
+ if (delay == 0)
+ delaybuffer = null;
+ else
+ delaybuffer = new float[delay];
+ rovepos = 0;
+ }
+
+ public void processReplace(float[] inout) {
+ if (delaybuffer == null)
+ return;
+ int len = inout.length;
+ int rnlen = delaybuffer.length;
+ int rovepos = this.rovepos;
+
+ for (int i = 0; i < len; i++) {
+ float x = inout[i];
+ inout[i] = delaybuffer[rovepos];
+ delaybuffer[rovepos] = x;
+ if (++rovepos == rnlen)
+ rovepos = 0;
+ }
+ this.rovepos = rovepos;
+ }
+ }
+
+ private final static class AllPass {
+
+ private final float[] delaybuffer;
+ private final int delaybuffersize;
+ private int rovepos = 0;
+ private float feedback;
+
+ public AllPass(int size) {
+ delaybuffer = new float[size];
+ delaybuffersize = size;
+ }
+
+ public void setFeedBack(float feedback) {
+ this.feedback = feedback;
+ }
+
+ public void processReplace(float inout[]) {
+ int len = inout.length;
+ int delaybuffersize = this.delaybuffersize;
+ int rovepos = this.rovepos;
+ for (int i = 0; i < len; i++) {
+ float delayout = delaybuffer[rovepos];
+ float input = inout[i];
+ inout[i] = delayout - input;
+ delaybuffer[rovepos] = input + delayout * feedback;
+ if (++rovepos == delaybuffersize)
+ rovepos = 0;
+ }
+ this.rovepos = rovepos;
+ }
+
+ public void processReplace(float in[], float out[]) {
+ int len = in.length;
+ int delaybuffersize = this.delaybuffersize;
+ int rovepos = this.rovepos;
+ for (int i = 0; i < len; i++) {
+ float delayout = delaybuffer[rovepos];
+ float input = in[i];
+ out[i] = delayout - input;
+ delaybuffer[rovepos] = input + delayout * feedback;
+ if (++rovepos == delaybuffersize)
+ rovepos = 0;
+ }
+ this.rovepos = rovepos;
+ }
+ }
+
+ private final static class Comb {
+
+ private final float[] delaybuffer;
+ private final int delaybuffersize;
+ private int rovepos = 0;
+ private float feedback;
+ private float filtertemp = 0;
+ private float filtercoeff1 = 0;
+ private float filtercoeff2 = 1;
+
+ public Comb(int size) {
+ delaybuffer = new float[size];
+ delaybuffersize = size;
+ }
+
+ public void setFeedBack(float feedback) {
+ this.feedback = feedback;
+ filtercoeff2 = (1 - filtercoeff1)* feedback;
+ }
+
+ public void processMix(float in[], float out[]) {
+ int len = in.length;
+ int delaybuffersize = this.delaybuffersize;
+ int rovepos = this.rovepos;
+ float filtertemp = this.filtertemp;
+ float filtercoeff1 = this.filtercoeff1;
+ float filtercoeff2 = this.filtercoeff2;
+ for (int i = 0; i < len; i++) {
+ float delayout = delaybuffer[rovepos];
+ // One Pole Lowpass Filter
+ filtertemp = (delayout * filtercoeff2)
+ + (filtertemp * filtercoeff1);
+ out[i] += delayout;
+ delaybuffer[rovepos] = in[i] + filtertemp;
+ if (++rovepos == delaybuffersize)
+ rovepos = 0;
+ }
+ this.filtertemp = filtertemp;
+ this.rovepos = rovepos;
+ }
+
+ public void processReplace(float in[], float out[]) {
+ int len = in.length;
+ int delaybuffersize = this.delaybuffersize;
+ int rovepos = this.rovepos;
+ float filtertemp = this.filtertemp;
+ float filtercoeff1 = this.filtercoeff1;
+ float filtercoeff2 = this.filtercoeff2;
+ for (int i = 0; i < len; i++) {
+ float delayout = delaybuffer[rovepos];
+ // One Pole Lowpass Filter
+ filtertemp = (delayout * filtercoeff2)
+ + (filtertemp * filtercoeff1);
+ out[i] = delayout;
+ delaybuffer[rovepos] = in[i] + filtertemp;
+ if (++rovepos == delaybuffersize)
+ rovepos = 0;
+ }
+ this.filtertemp = filtertemp;
+ this.rovepos = rovepos;
+ }
+
+ public void setDamp(float val) {
+ filtercoeff1 = val;
+ filtercoeff2 = (1 - filtercoeff1)* feedback;
+ }
+ }
+ private float roomsize;
+ private float damp;
+ private float gain = 1;
+ private Delay delay;
+ private Comb[] combL;
+ private Comb[] combR;
+ private AllPass[] allpassL;
+ private AllPass[] allpassR;
+ private float[] input;
+ private float[] out;
+ private float[] pre1;
+ private float[] pre2;
+ private float[] pre3;
+ private boolean denormal_flip = false;
+ private boolean mix = true;
+ private SoftAudioBuffer inputA;
+ private SoftAudioBuffer left;
+ private SoftAudioBuffer right;
+ private boolean dirty = true;
+ private float dirty_roomsize;
+ private float dirty_damp;
+ private float dirty_predelay;
+ private float dirty_gain;
+ private float samplerate;
+ private boolean light = true;
+
+ public void init(float samplerate, float controlrate) {
+ this.samplerate = samplerate;
+
+ double freqscale = ((double) samplerate) / 44100.0;
+ // freqscale = 1.0/ freqscale;
+
+ int stereospread = 23;
+
+ delay = new Delay();
+
+ combL = new Comb[8];
+ combR = new Comb[8];
+ combL[0] = new Comb((int) (freqscale * (1116)));
+ combR[0] = new Comb((int) (freqscale * (1116 + stereospread)));
+ combL[1] = new Comb((int) (freqscale * (1188)));
+ combR[1] = new Comb((int) (freqscale * (1188 + stereospread)));
+ combL[2] = new Comb((int) (freqscale * (1277)));
+ combR[2] = new Comb((int) (freqscale * (1277 + stereospread)));
+ combL[3] = new Comb((int) (freqscale * (1356)));
+ combR[3] = new Comb((int) (freqscale * (1356 + stereospread)));
+ combL[4] = new Comb((int) (freqscale * (1422)));
+ combR[4] = new Comb((int) (freqscale * (1422 + stereospread)));
+ combL[5] = new Comb((int) (freqscale * (1491)));
+ combR[5] = new Comb((int) (freqscale * (1491 + stereospread)));
+ combL[6] = new Comb((int) (freqscale * (1557)));
+ combR[6] = new Comb((int) (freqscale * (1557 + stereospread)));
+ combL[7] = new Comb((int) (freqscale * (1617)));
+ combR[7] = new Comb((int) (freqscale * (1617 + stereospread)));
+
+ allpassL = new AllPass[4];
+ allpassR = new AllPass[4];
+ allpassL[0] = new AllPass((int) (freqscale * (556)));
+ allpassR[0] = new AllPass((int) (freqscale * (556 + stereospread)));
+ allpassL[1] = new AllPass((int) (freqscale * (441)));
+ allpassR[1] = new AllPass((int) (freqscale * (441 + stereospread)));
+ allpassL[2] = new AllPass((int) (freqscale * (341)));
+ allpassR[2] = new AllPass((int) (freqscale * (341 + stereospread)));
+ allpassL[3] = new AllPass((int) (freqscale * (225)));
+ allpassR[3] = new AllPass((int) (freqscale * (225 + stereospread)));
+
+ for (int i = 0; i < allpassL.length; i++) {
+ allpassL[i].setFeedBack(0.5f);
+ allpassR[i].setFeedBack(0.5f);
+ }
+
+ /* Init other settings */
+ globalParameterControlChange(new int[]{0x01 * 128 + 0x01}, 0, 4);
+
+ }
+
+ public void setInput(int pin, SoftAudioBuffer input) {
+ if (pin == 0)
+ inputA = input;
+ }
+
+ public void setOutput(int pin, SoftAudioBuffer output) {
+ if (pin == 0)
+ left = output;
+ if (pin == 1)
+ right = output;
+ }
+
+ public void setMixMode(boolean mix) {
+ this.mix = mix;
+ }
+
+ private boolean silent = true;
+
+ public void processAudio() {
+ boolean silent_input = this.inputA.isSilent();
+ if(!silent_input)
+ silent = false;
+ if(silent)
+ {
+ if (!mix) {
+ left.clear();
+ right.clear();
+ }
+ return;
+ }
+
+ float[] inputA = this.inputA.array();
+ float[] left = this.left.array();
+ float[] right = this.right == null ? null : this.right.array();
+
+ int numsamples = inputA.length;
+ if (input == null || input.length < numsamples)
+ input = new float[numsamples];
+
+ float again = gain * 0.018f / 2;
+
+ denormal_flip = !denormal_flip;
+ if(denormal_flip)
+ for (int i = 0; i < numsamples; i++)
+ input[i] = inputA[i] * again + 1E-20f;
+ else
+ for (int i = 0; i < numsamples; i++)
+ input[i] = inputA[i] * again - 1E-20f;
+
+ delay.processReplace(input);
+
+ if(light && (right != null))
+ {
+ if (pre1 == null || pre1.length < numsamples)
+ {
+ pre1 = new float[numsamples];
+ pre2 = new float[numsamples];
+ pre3 = new float[numsamples];
+ }
+
+ for (int i = 0; i < allpassL.length; i++)
+ allpassL[i].processReplace(input);
+
+ combL[0].processReplace(input, pre3);
+ combL[1].processReplace(input, pre3);
+
+ combL[2].processReplace(input, pre1);
+ for (int i = 4; i < combL.length-2; i+=2)
+ combL[i].processMix(input, pre1);
+
+ combL[3].processReplace(input, pre2);;
+ for (int i = 5; i < combL.length-2; i+=2)
+ combL[i].processMix(input, pre2);
+
+ if (!mix)
+ {
+ Arrays.fill(right, 0);
+ Arrays.fill(left, 0);
+ }
+ for (int i = combR.length-2; i < combR.length; i++)
+ combR[i].processMix(input, right);
+ for (int i = combL.length-2; i < combL.length; i++)
+ combL[i].processMix(input, left);
+
+ for (int i = 0; i < numsamples; i++)
+ {
+ float p = pre1[i] - pre2[i];
+ float m = pre3[i];
+ left[i] += m + p;
+ right[i] += m - p;
+ }
+ }
+ else
+ {
+ if (out == null || out.length < numsamples)
+ out = new float[numsamples];
+
+ if (right != null) {
+ if (!mix)
+ Arrays.fill(right, 0);
+ allpassR[0].processReplace(input, out);
+ for (int i = 1; i < allpassR.length; i++)
+ allpassR[i].processReplace(out);
+ for (int i = 0; i < combR.length; i++)
+ combR[i].processMix(out, right);
+ }
+
+ if (!mix)
+ Arrays.fill(left, 0);
+ allpassL[0].processReplace(input, out);
+ for (int i = 1; i < allpassL.length; i++)
+ allpassL[i].processReplace(out);
+ for (int i = 0; i < combL.length; i++)
+ combL[i].processMix(out, left);
+ }
+
+
+
+
+
+
+ if (silent_input) {
+ silent = true;
+ for (int i = 0; i < numsamples; i++)
+ {
+ float v = left[i];
+ if(v > 1E-10 || v < -1E-10)
+ {
+ silent = false;
+ break;
+ }
+ }
+ }
+
+ }
+
+ public void globalParameterControlChange(int[] slothpath, long param,
+ long value) {
+ if (slothpath.length == 1) {
+ if (slothpath[0] == 0x01 * 128 + 0x01) {
+
+ if (param == 0) {
+ if (value == 0) {
+ // Small Room A small size room with a length
+ // of 5m or so.
+ dirty_roomsize = (1.1f);
+ dirty_damp = (5000);
+ dirty_predelay = (0);
+ dirty_gain = (4);
+ dirty = true;
+ }
+ if (value == 1) {
+ // Medium Room A medium size room with a length
+ // of 10m or so.
+ dirty_roomsize = (1.3f);
+ dirty_damp = (5000);
+ dirty_predelay = (0);
+ dirty_gain = (3);
+ dirty = true;
+ }
+ if (value == 2) {
+ // Large Room A large size room suitable for
+ // live performances.
+ dirty_roomsize = (1.5f);
+ dirty_damp = (5000);
+ dirty_predelay = (0);
+ dirty_gain = (2);
+ dirty = true;
+ }
+ if (value == 3) {
+ // Medium Hall A medium size concert hall.
+ dirty_roomsize = (1.8f);
+ dirty_damp = (24000);
+ dirty_predelay = (0.02f);
+ dirty_gain = (1.5f);
+ dirty = true;
+ }
+ if (value == 4) {
+ // Large Hall A large size concert hall
+ // suitable for a full orchestra.
+ dirty_roomsize = (1.8f);
+ dirty_damp = (24000);
+ dirty_predelay = (0.03f);
+ dirty_gain = (1.5f);
+ dirty = true;
+ }
+ if (value == 8) {
+ // Plate A plate reverb simulation.
+ dirty_roomsize = (1.3f);
+ dirty_damp = (2500);
+ dirty_predelay = (0);
+ dirty_gain = (6);
+ dirty = true;
+ }
+ } else if (param == 1) {
+ dirty_roomsize = ((float) (Math.exp((value - 40) * 0.025)));
+ dirty = true;
+ }
+
+ }
+ }
+ }
+
+ public void processControlLogic() {
+ if (dirty) {
+ dirty = false;
+ setRoomSize(dirty_roomsize);
+ setDamp(dirty_damp);
+ setPreDelay(dirty_predelay);
+ setGain(dirty_gain);
+ }
+ }
+
+ public void setRoomSize(float value) {
+ roomsize = 1 - (0.17f / value);
+
+ for (int i = 0; i < combL.length; i++) {
+ combL[i].feedback = roomsize;
+ combR[i].feedback = roomsize;
+ }
+ }
+
+ public void setPreDelay(float value) {
+ delay.setDelay((int)(value * samplerate));
+ }
+
+ public void setGain(float gain) {
+ this.gain = gain;
+ }
+
+ public void setDamp(float value) {
+ double x = (value / samplerate) * (2 * Math.PI);
+ double cx = 2 - Math.cos(x);
+ damp = (float)(cx - Math.sqrt(cx * cx - 1));
+ if (damp > 1)
+ damp = 1;
+ if (damp < 0)
+ damp = 0;
+
+ // damp = value * 0.4f;
+ for (int i = 0; i < combL.length; i++) {
+ combL[i].setDamp(damp);
+ combR[i].setDamp(damp);
+ }
+
+ }
+
+ public void setLightMode(boolean light)
+ {
+ this.light = light;
+ }
+}
+
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SoftShortMessage.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SoftShortMessage.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.media.sound;
+
+import javax.sound.midi.InvalidMidiDataException;
+import javax.sound.midi.ShortMessage;
+
+/**
+ * A short message class that support for than 16 midi channels.
+ *
+ * @author Karl Helgason
+ */
+public class SoftShortMessage extends ShortMessage {
+
+ int channel = 0;
+
+ public int getChannel() {
+ return channel;
+ }
+
+ public void setMessage(int command, int channel, int data1, int data2)
+ throws InvalidMidiDataException {
+ this.channel = channel;
+ super.setMessage(command, channel & 0xF, data1, data2);
+ }
+
+ public Object clone() {
+ SoftShortMessage clone = new SoftShortMessage();
+ try {
+ clone.setMessage(getCommand(), getChannel(), getData1(), getData2());
+ } catch (InvalidMidiDataException e) {
+ throw new IllegalArgumentException(e);
+ }
+ return clone;
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SoftSincResampler.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SoftSincResampler.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.media.sound;
+
+/**
+ * Hann windowed sinc interpolation resampler with anti-alias filtering.
+ *
+ * Using 30 points for the interpolation.
+ *
+ * @author Karl Helgason
+ */
+public class SoftSincResampler extends SoftAbstractResampler {
+
+ float[][][] sinc_table;
+ int sinc_scale_size = 100;
+ int sinc_table_fsize = 800;
+ int sinc_table_size = 30;
+ int sinc_table_center = sinc_table_size / 2;
+
+ public SoftSincResampler() {
+ super();
+ sinc_table = new float[sinc_scale_size][sinc_table_fsize][];
+ for (int s = 0; s < sinc_scale_size; s++) {
+ float scale = (float) (1.0 / (1.0 + Math.pow(s, 1.1) / 10.0));
+ for (int i = 0; i < sinc_table_fsize; i++) {
+ sinc_table[s][i] = sincTable(sinc_table_size,
+ -i / ((float)sinc_table_fsize), scale);
+ }
+ }
+ }
+
+ // Normalized sinc function
+ public static double sinc(double x) {
+ return (x == 0.0) ? 1.0 : Math.sin(Math.PI * x) / (Math.PI * x);
+ }
+
+ // Generate hann window suitable for windowing sinc
+ public static float[] wHanning(int size, float offset) {
+ float[] window_table = new float[size];
+ for (int k = 0; k < size; k++) {
+ window_table[k] = (float)(-0.5
+ * Math.cos(2.0 * Math.PI * (double)(k + offset)
+ / (double) size) + 0.5);
+ }
+ return window_table;
+ }
+
+ // Generate sinc table
+ public static float[] sincTable(int size, float offset, float scale) {
+ int center = size / 2;
+ float[] w = wHanning(size, offset);
+ for (int k = 0; k < size; k++)
+ w[k] *= sinc((-center + k + offset) * scale) * scale;
+ return w;
+ }
+
+ public int getPadding() // must be at least half of sinc_table_size
+ {
+ return sinc_table_size / 2 + 2;
+ }
+
+ public void interpolate(float[] in, float[] in_offset, float in_end,
+ float[] startpitch, float pitchstep, float[] out, int[] out_offset,
+ int out_end) {
+ float pitch = startpitch[0];
+ float ix = in_offset[0];
+ int ox = out_offset[0];
+ float ix_end = in_end;
+ int ox_end = out_end;
+ int max_p = sinc_scale_size - 1;
+ if (pitchstep == 0) {
+
+ int p = (int) ((pitch - 1) * 10.0f);
+ if (p < 0)
+ p = 0;
+ else if (p > max_p)
+ p = max_p;
+ float[][] sinc_table_f = this.sinc_table[p];
+ while (ix < ix_end && ox < ox_end) {
+ int iix = (int) ix;
+ float[] sinc_table =
+ sinc_table_f[(int)((ix - iix) * sinc_table_fsize)];
+ int xx = iix - sinc_table_center;
+ float y = 0;
+ for (int i = 0; i < sinc_table_size; i++, xx++)
+ y += in[xx] * sinc_table[i];
+ out[ox++] = y;
+ ix += pitch;
+ }
+ } else {
+ while (ix < ix_end && ox < ox_end) {
+ int iix = (int) ix;
+ int p = (int) ((pitch - 1) * 10.0f);
+ if (p < 0)
+ p = 0;
+ else if (p > max_p)
+ p = max_p;
+ float[][] sinc_table_f = this.sinc_table[p];
+
+ float[] sinc_table =
+ sinc_table_f[(int)((ix - iix) * sinc_table_fsize)];
+ int xx = iix - sinc_table_center;
+ float y = 0;
+ for (int i = 0; i < sinc_table_size; i++, xx++)
+ y += in[xx] * sinc_table[i];
+ out[ox++] = y;
+
+ ix += pitch;
+ pitch += pitchstep;
+ }
+ }
+ in_offset[0] = ix;
+ out_offset[0] = ox;
+ startpitch[0] = pitch;
+
+ }
+}
diff -r 7e90efb5bee6 -r 3a1f36b2dd3b jdk/src/share/classes/com/sun/media/sound/SoftSynthesizer.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/SoftSynthesizer.java Tue Feb 03 22:02:55 2009 -0800
@@ -0,0 +1,1179 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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.lang.ref.WeakReference;
+import java.security.AccessControlException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.sound.midi.Instrument;
+import javax.sound.midi.MidiChannel;
+import javax.sound.midi.MidiDevice;
+import javax.sound.midi.MidiSystem;
+import javax.sound.midi.MidiUnavailableException;
+import javax.sound.midi.Patch;
+import javax.sound.midi.Receiver;
+import javax.sound.midi.Soundbank;
+import javax.sound.midi.Transmitter;
+import javax.sound.midi.VoiceStatus;
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.AudioInputStream;
+import javax.sound.sampled.AudioSystem;
+import javax.sound.sampled.LineUnavailableException;
+import javax.sound.sampled.SourceDataLine;
+
+/**
+ * The software synthesizer class.
+ *
+ * @author Karl Helgason
+ */
+public class SoftSynthesizer implements AudioSynthesizer,
+ ReferenceCountingDevice {
+
+ protected static class WeakAudioStream extends InputStream
+ {
+ private volatile AudioInputStream stream;
+ public SoftAudioPusher pusher = null;
+ public AudioInputStream jitter_stream = null;
+ public SourceDataLine sourceDataLine = null;
+ private WeakReference weak_stream_link;
+ private AudioFloatConverter converter;
+ private float[] silentbuffer = null;
+ private int samplesize;
+
+ public void setInputStream(AudioInputStream stream)
+ {
+ this.stream = stream;
+ }
+
+ public int available() throws IOException {
+ AudioInputStream local_stream = stream;
+ if(local_stream != null)
+ return local_stream.available();
+ return 0;
+ }
+
+ public int read() throws IOException {
+ byte[] b = new byte[1];
+ if (read(b) == -1)
+ return -1;
+ return b[0] & 0xFF;
+ }
+
+ public int read(byte[] b, int off, int len) throws IOException {
+ AudioInputStream local_stream = stream;
+ if(local_stream != null)
+ return local_stream.read(b, off, len);
+ else
+ {
+ int flen = len / samplesize;
+ if(silentbuffer == null || silentbuffer.length < flen)
+ silentbuffer = new float[flen];
+ converter.toByteArray(silentbuffer, flen, b, off);
+
+ if(pusher != null)
+ if(weak_stream_link.get() == null)
+ {
+ Runnable runnable = new Runnable()
+ {
+ SoftAudioPusher _pusher = pusher;
+ AudioInputStream _jitter_stream = jitter_stream;
+ SourceDataLine _sourceDataLine = sourceDataLine;
+ public void run()
+ {
+ _pusher.stop();
+ if(_jitter_stream != null)
+ try {
+ _jitter_stream.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ if(_sourceDataLine != null)
+ _sourceDataLine.close();
+ }
+ };
+ pusher = null;
+ jitter_stream = null;
+ sourceDataLine = null;
+ new Thread(runnable).start();
+ }
+ return len;
+ }
+ }
+
+ public WeakAudioStream(AudioInputStream stream) {
+ this.stream = stream;
+ weak_stream_link = new WeakReference(stream);
+ converter = AudioFloatConverter.getConverter(stream.getFormat());
+ samplesize = stream.getFormat().getFrameSize() / stream.getFormat().getChannels();
+ }
+
+ public AudioInputStream getAudioInputStream()
+ {
+ return new AudioInputStream(this, stream.getFormat(), AudioSystem.NOT_SPECIFIED);
+ }
+
+ public void close() throws IOException
+ {
+ AudioInputStream astream = weak_stream_link.get();
+ if(astream != null)
+ astream.close();
+ }
+ }
+
+ private static class Info extends MidiDevice.Info {
+ public Info() {
+ super(INFO_NAME, INFO_VENDOR, INFO_DESCRIPTION, INFO_VERSION);
+ }
+ }
+
+ protected static final String INFO_NAME = "Gervill";
+ protected static final String INFO_VENDOR = "OpenJDK";
+ protected static final String INFO_DESCRIPTION = "Software MIDI Synthesizer";
+ protected static final String INFO_VERSION = "1.0";
+ protected final static MidiDevice.Info info = new Info();
+
+ private static SourceDataLine testline = null;
+
+ private static Soundbank defaultSoundBank = null;
+
+ protected WeakAudioStream weakstream = null;
+
+ protected Object control_mutex = this;
+
+ protected int voiceIDCounter = 0;
+
+ // 0: default
+ // 1: DLS Voice Allocation
+ protected int voice_allocation_mode = 0;
+
+ protected boolean reverb_light = true;
+ protected boolean reverb_on = true;
+ protected boolean chorus_on = true;
+ protected boolean agc_on = true;
+
+ protected SoftChannel[] channels;
+ protected SoftChannelProxy[] external_channels = null;
+
+ private boolean largemode = false;
+
+ // 0: GM Mode off (default)
+ // 1: GM Level 1
+ // 2: GM Level 2
+ private int gmmode = 0;
+
+ private int deviceid = 0;
+
+ private AudioFormat format = new AudioFormat(44100, 16, 2, true, false);
+
+ private SourceDataLine sourceDataLine = null;
+
+ private SoftAudioPusher pusher = null;
+ private AudioInputStream pusher_stream = null;
+
+ private float controlrate = 147f;
+
+ private boolean open = false;
+ private boolean implicitOpen = false;
+
+ private String resamplerType = "linear";
+ private SoftResampler resampler = new SoftLinearResampler();
+
+ private int number_of_midi_channels = 16;
+ private int maxpoly = 64;
+ private long latency = 200000; // 200 msec
+ private boolean jitter_correction = false;
+
+ private SoftMainMixer mainmixer;
+ private SoftVoice[] voices;
+
+ private Map tunings
+ = new HashMap();
+ private Map inslist
+ = new HashMap();
+ private Map availlist
+ = new HashMap();
+ private Map loadedlist
+ = new HashMap();
+
+ private ArrayList recvslist = new ArrayList();
+
+ private void getBuffers(ModelInstrument instrument,
+ List buffers) {
+ for (ModelPerformer performer : instrument.getPerformers()) {
+ if (performer.getOscillators() != null) {
+ for (ModelOscillator osc : performer.getOscillators()) {
+ if (osc instanceof ModelByteBufferWavetable) {
+ ModelByteBufferWavetable w = (ModelByteBufferWavetable)osc;
+ ModelByteBuffer buff = w.getBuffer();
+ if (buff != null)
+ buffers.add(buff);
+ buff = w.get8BitExtensionBuffer();
+ if (buff != null)
+ buffers.add(buff);
+ }
+ }
+ }
+ }
+ }
+
+ private boolean loadSamples(List instruments) {
+ if (largemode)
+ return true;
+ List buffers = new ArrayList();
+ for (ModelInstrument instrument : instruments)
+ getBuffers(instrument, buffers);
+ try {
+ ModelByteBuffer.loadAll(buffers);
+ } catch (IOException e) {
+ return false;
+ }
+ return true;
+ }
+
+ private boolean loadInstruments(List instruments) {
+ if (!isOpen())
+ return false;
+ if (!loadSamples(instruments))
+ return false;
+
+ synchronized (control_mutex) {
+ if (channels != null)
+ for (SoftChannel c : channels)
+ c.current_instrument = null;
+ for (Instrument instrument : instruments) {
+ String pat = patchToString(instrument.getPatch());
+ availlist.remove(pat);
+ SoftInstrument softins
+ = new SoftInstrument((ModelInstrument) instrument);
+ inslist.put(pat, softins);
+ loadedlist.put(pat, (ModelInstrument) instrument);
+ }
+ }
+
+ return true;
+ }
+
+ private void processPropertyInfo(Map info) {
+ AudioSynthesizerPropertyInfo[] items = getPropertyInfo(info);
+
+ String resamplerType = (String)items[0].value;
+ if (resamplerType.equalsIgnoreCase("point"))
+ {
+ this.resampler = new SoftPointResampler();
+ this.resamplerType = "point";
+ }
+ else if (resamplerType.equalsIgnoreCase("linear"))
+ {
+ this.resampler = new SoftLinearResampler2();
+ this.resamplerType = "linear";
+ }
+ else if (resamplerType.equalsIgnoreCase("linear1"))
+ {
+ this.resampler = new SoftLinearResampler();
+ this.resamplerType = "linear1";
+ }
+ else if (resamplerType.equalsIgnoreCase("linear2"))
+ {
+ this.resampler = new SoftLinearResampler2();
+ this.resamplerType = "linear2";
+ }
+ else if (resamplerType.equalsIgnoreCase("cubic"))
+ {
+ this.resampler = new SoftCubicResampler();
+ this.resamplerType = "cubic";
+ }
+ else if (resamplerType.equalsIgnoreCase("lanczos"))
+ {
+ this.resampler = new SoftLanczosResampler();
+ this.resamplerType = "lanczos";
+ }
+ else if (resamplerType.equalsIgnoreCase("sinc"))
+ {
+ this.resampler = new SoftSincResampler();
+ this.resamplerType = "sinc";
+ }
+
+ setFormat((AudioFormat)items[2].value);
+ controlrate = (Float)items[1].value;
+ latency = (Long)items[3].value;
+ deviceid = (Integer)items[4].value;
+ maxpoly = (Integer)items[5].value;
+ reverb_on = (Boolean)items[6].value;
+ chorus_on = (Boolean)items[7].value;
+ agc_on = (Boolean)items[8].value;
+ largemode = (Boolean)items[9].value;
+ number_of_midi_channels = (Integer)items[10].value;
+ jitter_correction = (Boolean)items[11].value;
+ reverb_light = (Boolean)items[12].value;
+ }
+
+ private String patchToString(Patch patch) {
+ if (patch instanceof ModelPatch && ((ModelPatch) patch).isPercussion())
+ return "p." + patch.getProgram() + "." + patch.getBank();
+ else
+ return patch.getProgram() + "." + patch.getBank();
+ }
+
+ private void setFormat(AudioFormat format) {
+ if (format.getChannels() > 2) {
+ throw new IllegalArgumentException(
+ "Only mono and stereo audio supported.");
+ }
+ if (AudioFloatConverter.getConverter(format) == null)
+ throw new IllegalArgumentException("Audio format not supported.");
+ this.format = format;
+ }
+
+ protected void removeReceiver(Receiver recv) {
+ boolean perform_close = false;
+ synchronized (control_mutex) {
+ if (recvslist.remove(recv)) {
+ if (implicitOpen && recvslist.isEmpty())
+ perform_close = true;
+ }
+ }
+ if (perform_close)
+ close();
+ }
+
+ protected SoftMainMixer getMainMixer() {
+ if (!isOpen())
+ return null;
+ return mainmixer;
+ }
+
+ protected SoftInstrument findInstrument(int program, int bank, int channel) {
+
+ // Add support for GM2 banks 0x78 and 0x79
+ // as specified in DLS 2.2 in Section 1.4.6
+ // which allows using percussion and melodic instruments
+ // on all channels
+ if (bank >> 7 == 0x78 || bank >> 7 == 0x79) {
+ SoftInstrument current_instrument
+ = inslist.get(program + "." + bank);
+ if (current_instrument != null)
+ return current_instrument;
+
+ String p_plaf;
+ if (bank >> 7 == 0x78)
+ p_plaf = "p.";
+ else
+ p_plaf = "";
+
+ // Instrument not found fallback to MSB:bank, LSB:0
+ current_instrument = inslist.get(p_plaf + program + "."
+ + ((bank & 128) << 7));
+ if (current_instrument != null)
+ return current_instrument;
+ // Instrument not found fallback to MSB:0, LSB:bank
+ current_instrument = inslist.get(p_plaf + program + "."
+ + (bank & 128));
+ if (current_instrument != null)
+ return current_instrument;
+ // Instrument not found fallback to MSB:0, LSB:0
+ current_instrument = inslist.get(p_plaf + program + ".0");
+ if (current_instrument != null)
+ return current_instrument;
+ // Instrument not found fallback to MSB:0, LSB:0, program=0
+ current_instrument = inslist.get(p_plaf + program + "0.0");
+ if (current_instrument != null)
+ return current_instrument;
+ return null;
+ }
+
+ // Channel 10 uses percussion instruments
+ String p_plaf;
+ if (channel == 9)
+ p_plaf = "p.";
+ else
+ p_plaf = "";
+
+ SoftInstrument current_instrument
+ = inslist.get(p_plaf + program + "." + bank);
+ if (current_instrument != null)
+ return current_instrument;
+ // Instrument not found fallback to MSB:0, LSB:0
+ current_instrument = inslist.get(p_plaf + program + ".0");
+ if (current_instrument != null)
+ return current_instrument;
+ // Instrument not found fallback to MSB:0, LSB:0, program=0
+ current_instrument = inslist.get(p_plaf + "0.0");
+ if (current_instrument != null)
+ return current_instrument;
+ return null;
+ }
+
+ protected int getVoiceAllocationMode() {
+ return voice_allocation_mode;
+ }
+
+ protected int getGeneralMidiMode() {
+ return gmmode;
+ }
+
+ protected void setGeneralMidiMode(int gmmode) {
+ this.gmmode = gmmode;
+ }
+
+ protected int getDeviceID() {
+ return deviceid;
+ }
+
+ protected float getControlRate() {
+ return controlrate;
+ }
+
+ protected SoftVoice[] getVoices() {
+ return voices;
+ }
+
+ protected SoftTuning getTuning(Patch patch) {
+ String t_id = patchToString(patch);
+ SoftTuning tuning = tunings.get(t_id);
+ if (tuning == null) {
+ tuning = new SoftTuning(patch);
+ tunings.put(t_id, tuning);
+ }
+ return tuning;
+ }
+
+ public long getLatency() {
+ synchronized (control_mutex) {
+ return latency;
+ }
+ }
+
+ public AudioFormat getFormat() {
+ synchronized (control_mutex) {
+ return format;
+ }
+ }
+
+ public int getMaxPolyphony() {
+ synchronized (control_mutex) {
+ return maxpoly;
+ }
+ }
+
+ public MidiChannel[] getChannels() {
+
+ synchronized (control_mutex) {
+ // if (external_channels == null) => the synthesizer is not open,
+ // create 16 proxy channels
+ // otherwise external_channels has the same length as channels array
+ if (external_channels == null) {
+ external_channels = new SoftChannelProxy[16];
+ for (int i = 0; i < external_channels.length; i++)
+ external_channels[i] = new SoftChannelProxy();
+ }
+ MidiChannel[] ret;
+ if (isOpen())
+ ret = new MidiChannel[channels.length];
+ else
+ ret = new MidiChannel[16];
+ for (int i = 0; i < ret.length; i++)
+ ret[i] = external_channels[i];
+ return ret;
+ }
+ }
+
+ public VoiceStatus[] getVoiceStatus() {
+ if (!isOpen()) {
+ VoiceStatus[] tempVoiceStatusArray
+ = new VoiceStatus[getMaxPolyphony()];
+ for (int i = 0; i < tempVoiceStatusArray.length; i++) {
+ VoiceStatus b = new VoiceStatus();
+ b.active = false;
+ b.bank = 0;
+ b.channel = 0;
+ b.note = 0;
+ b.program = 0;
+ b.volume = 0;
+ tempVoiceStatusArray[i] = b;
+ }
+ return tempVoiceStatusArray;
+ }
+
+ synchronized (control_mutex) {
+ VoiceStatus[] tempVoiceStatusArray = new VoiceStatus[voices.length];
+ for (int i = 0; i < voices.length; i++) {
+ VoiceStatus a = voices[i];
+ VoiceStatus b = new VoiceStatus();
+ b.active = a.active;
+ b.bank = a.bank;
+ b.channel = a.channel;
+ b.note = a.note;
+ b.program = a.program;
+ b.volume = a.volume;
+ tempVoiceStatusArray[i] = b;
+ }
+ return tempVoiceStatusArray;
+ }
+ }
+
+ public boolean isSoundbankSupported(Soundbank soundbank) {
+ for (Instrument ins: soundbank.getInstruments())
+ if (!(ins instanceof ModelInstrument))
+ return false;
+ return true;
+ }
+
+ public boolean loadInstrument(Instrument instrument) {
+ if (instrument == null || (!(instrument instanceof ModelInstrument))) {
+ throw new IllegalArgumentException("Unsupported instrument: " +
+ instrument);
+ }
+ List instruments = new ArrayList();
+ instruments.add((ModelInstrument)instrument);
+ return loadInstruments(instruments);
+ }
+
+ public void unloadInstrument(Instrument instrument) {
+ if (instrument == null || (!(instrument instanceof ModelInstrument))) {
+ throw new IllegalArgumentException("Unsupported instrument: " +
+ instrument);
+ }
+ if (!isOpen())
+ return;
+
+ String pat = patchToString(instrument.getPatch());
+ synchronized (control_mutex) {
+ for (SoftChannel c: channels)
+ c.current_instrument = null;
+ inslist.remove(pat);
+ loadedlist.remove(pat);
+ availlist.remove(pat);
+ }
+ }
+
+ public boolean remapInstrument(Instrument from, Instrument to) {
+
+ if (from == null)
+ throw new NullPointerException();
+ if (to == null)
+ throw new NullPointerException();
+ if (!(from instanceof ModelInstrument)) {
+ throw new IllegalArgumentException("Unsupported instrument: " +
+ from.toString());
+ }
+ if (!(to instanceof ModelInstrument)) {
+ throw new IllegalArgumentException("Unsupported instrument: " +
+ to.toString());
+ }
+ if (!isOpen())
+ return false;
+
+ synchronized (control_mutex) {
+ if (!loadedlist.containsValue(to) && !availlist.containsValue(to))
+ throw new IllegalArgumentException("Instrument to is not loaded.");
+ unloadInstrument(from);
+ ModelMappedInstrument mfrom = new ModelMappedInstrument(
+ (ModelInstrument)to, from.getPatch());
+ return loadInstrument(mfrom);
+ }
+ }
+
+ public synchronized Soundbank getDefaultSoundbank() {
+ if (defaultSoundBank == null) {
+ try {
+ File javahome = new File(System.getProperties().getProperty(
+ "java.home"));
+ File libaudio = new File(new File(javahome, "lib"), "audio");
+
+ if (libaudio.exists()) {
+ File foundfile = null;
+ File[] files = libaudio.listFiles();
+ if (files != null) {
+ for (int i = 0; i < files.length; i++) {
+ File file = files[i];
+ if (file.isFile()) {
+ String lname = file.getName().toLowerCase();
+ if (lname.endsWith(".sf2") ||
+ lname.endsWith(".dls")) {
+ if (foundfile == null || (file.length() >
+ foundfile.length())) {
+ foundfile = file;
+ }
+ }
+ }
+ }
+ }
+ if (foundfile != null) {
+ try {
+ Soundbank sbk = MidiSystem.getSoundbank(foundfile);
+ defaultSoundBank = sbk;
+ return defaultSoundBank;
+ } catch (Exception e) {
+ //e.printStackTrace();
+ }
+ }
+ }
+
+ if (System.getProperties().getProperty("os.name")
+ .startsWith("Windows")) {
+ File gm_dls = new File(System.getenv("SystemRoot")
+ + "\\system32\\drivers\\gm.dls");
+ if (gm_dls.exists()) {
+ try {
+ Soundbank sbk = MidiSystem.getSoundbank(gm_dls);
+ defaultSoundBank = sbk;
+ return defaultSoundBank;
+ } catch (Exception e) {
+ //e.printStackTrace();
+ }
+ }
+ }
+ } catch (AccessControlException e) {
+ } catch (Exception e) {
+ //e.printStackTrace();
+ }
+
+ File userhome = null;
+ File emg_soundbank_file = null;
+
+ /*
+ * Try to load saved generated soundbank
+ */
+ try {
+ userhome = new File(System.getProperty("user.home"),
+ ".gervill");
+ emg_soundbank_file = new File(userhome, "soundbank-emg.sf2");
+ Soundbank sbk = MidiSystem.getSoundbank(emg_soundbank_file);
+ defaultSoundBank = sbk;
+ return defaultSoundBank;
+ } catch (AccessControlException e) {
+ } catch (Exception e) {
+ //e.printStackTrace();
+ }
+
+ try {
+
+ /*
+ * Generate emergency soundbank
+ */
+ defaultSoundBank = EmergencySoundbank.createSoundbank();
+
+ /*
+ * Save generated soundbank to disk for faster future use.
+ */
+ if(defaultSoundBank != null)
+ {
+ if(!userhome.exists()) userhome.mkdirs();
+ if(!emg_soundbank_file.exists())
+ ((SF2Soundbank)defaultSoundBank).save(emg_soundbank_file);
+ }
+ } catch (Exception e) {
+ //e.printStackTrace();
+ }
+
+ }
+ return defaultSoundBank;
+ }
+
+ public Instrument[] getAvailableInstruments() {
+ if (!isOpen()) {
+ Soundbank defsbk = getDefaultSoundbank();
+ if (defsbk == null)
+ return new Instrument[0];
+ return defsbk.getInstruments();
+ }
+
+ synchronized (control_mutex) {
+ ModelInstrument[] inslist_array =
+ new ModelInstrument[availlist.values().size()];
+ availlist.values().toArray(inslist_array);
+ Arrays.sort(inslist_array, new ModelInstrumentComparator());
+ return inslist_array;
+ }
+ }
+
+ public Instrument[] getLoadedInstruments() {
+ if (!isOpen())
+ return new Instrument[0];
+
+ synchronized (control_mutex) {
+ ModelInstrument[] inslist_array =
+ new ModelInstrument[loadedlist.values().size()];
+ loadedlist.values().toArray(inslist_array);
+ Arrays.sort(inslist_array, new ModelInstrumentComparator());
+ return inslist_array;
+ }
+ }
+
+ public boolean loadAllInstruments(Soundbank soundbank) {
+ List instruments = new ArrayList();
+ for (Instrument ins: soundbank.getInstruments()) {
+ if (ins == null || !(ins instanceof ModelInstrument)) {
+ throw new IllegalArgumentException(
+ "Unsupported instrument: " + ins);
+ }
+ instruments.add((ModelInstrument)ins);
+ }
+ return loadInstruments(instruments);
+ }
+
+ public void unloadAllInstruments(Soundbank soundbank) {
+ if (soundbank == null || !isSoundbankSupported(soundbank))
+ throw new IllegalArgumentException("Unsupported soundbank: " + soundbank);
+
+ if (!isOpen())
+ return;
+
+ for (Instrument ins: soundbank.getInstruments()) {
+ if (ins instanceof ModelInstrument) {
+ unloadInstrument(ins);
+ }
+ }
+ }
+
+ public boolean loadInstruments(Soundbank soundbank, Patch[] patchList) {
+ List instruments = new ArrayList();
+ for (Patch patch: patchList) {
+ Instrument ins = soundbank.getInstrument(patch);
+ if (ins == null || !(ins instanceof ModelInstrument)) {
+ throw new IllegalArgumentException(
+ "Unsupported instrument: " + ins);
+ }
+ instruments.add((ModelInstrument)ins);
+ }
+ return loadInstruments(instruments);
+ }
+
+ public void unloadInstruments(Soundbank soundbank, Patch[] patchList) {
+ if (soundbank == null || !isSoundbankSupported(soundbank))
+ throw new IllegalArgumentException("Unsupported soundbank: " + soundbank);
+
+ if (!isOpen())
+ return;
+
+ for (Patch pat: patchList) {
+ Instrument ins = soundbank.getInstrument(pat);
+ if (ins instanceof ModelInstrument) {
+ unloadInstrument(ins);
+ }
+ }
+ }
+
+ public MidiDevice.Info getDeviceInfo() {
+ return info;
+ }
+
+ public AudioSynthesizerPropertyInfo[] getPropertyInfo(Map