Mercurial > hg > release > icedtea6-1.2
changeset 851:4706d355d973
Import new Gervill CVS.
2008-05-04 Mark Wielaard <mark@klomp.org>
* overlays/openjdk/jdk/src/share/classes/com/sun/media/sound:
Import new Gervill CVS. See CHANGES.txt. Changed:
AudioFloatConverter.java, DLSSoundbank.java, SoftChannel.java,
WaveFloatFileReader.java. Added: AudioFloatFormatConverter.java,
WaveExtensibleFileReader.java, WaveFloatFileWriter.java. Deleted:
PATInstrument.java, PATSample.java, PATSoundbankReader.java.
line wrap: on
line diff
--- a/ChangeLog Sun May 04 23:35:04 2008 +0200 +++ b/ChangeLog Mon May 05 00:31:45 2008 +0200 @@ -1,3 +1,12 @@ +2008-05-04 Mark Wielaard <mark@klomp.org> + + * overlays/openjdk/jdk/src/share/classes/com/sun/media/sound: + Import new Gervill CVS. See CHANGES.txt. Changed: + AudioFloatConverter.java, DLSSoundbank.java, SoftChannel.java, + WaveFloatFileReader.java. Added: AudioFloatFormatConverter.java, + WaveExtensibleFileReader.java, WaveFloatFileWriter.java. Deleted: + PATInstrument.java, PATSample.java, PATSoundbankReader.java. + 2008-05-04 Mark Wielaard <mark@klomp.org> * Makefile.am (EXTRA_DIST): Add patches/icedtea-hat-spl-gpl.patch.
--- a/overlays/openjdk/jdk/src/share/classes/com/sun/media/sound/AudioFloatConverter.java Sun May 04 23:35:04 2008 +0200 +++ b/overlays/openjdk/jdk/src/share/classes/com/sun/media/sound/AudioFloatConverter.java Mon May 05 00:31:45 2008 +0200 @@ -27,13 +27,14 @@ 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 bit signed/unsigned + * 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. * * @version %I%, %E% @@ -43,6 +44,173 @@ 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; + } + } /*************************************************************************** * @@ -549,14 +717,196 @@ } } + /*************************************************************************** + * + * 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 / 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); + 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 / 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); + 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 -= 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; + 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() != (format.getSampleSizeInBits() / 8) + 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) + if (format.getSampleSizeInBits() <= 8) conv = new AudioFloatConversion8S(); else if (format.getSampleSizeInBits() > 8 && format.getSampleSizeInBits() <= 16) @@ -567,8 +917,10 @@ 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) + if (format.getSampleSizeInBits() <= 8) conv = new AudioFloatConversion8S(); else if (format.getSampleSizeInBits() > 8 & format.getSampleSizeInBits() <= 16) @@ -579,10 +931,12 @@ 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) + if (format.getSampleSizeInBits() <= 8) conv = new AudioFloatConversion8U(); else if (format.getSampleSizeInBits() > 8 && format.getSampleSizeInBits() <= 16) @@ -593,8 +947,10 @@ 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) + if (format.getSampleSizeInBits() <= 8) conv = new AudioFloatConversion8U(); else if (format.getSampleSizeInBits() > 8 && format.getSampleSizeInBits() <= 16) @@ -605,6 +961,8 @@ 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) { @@ -613,6 +971,20 @@ 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)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/overlays/openjdk/jdk/src/share/classes/com/sun/media/sound/AudioFloatFormatConverter.java Mon May 05 00:31:45 2008 +0200 @@ -0,0 +1,523 @@ +/* + * 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. + * + * @version %I%, %E% + * @author Karl Helgason + */ + +public class AudioFloatFormatConverter extends FormatConversionProvider { + + private 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 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 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) + { + in_end = pad2; + if(ibuffer_index > in_end) break; + } + else + { + if(ibuffer_index >= (ibuffer_len+pad)) + readNextBuffer(); + in_end = ibuffer_len+pad; + } + 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 formats; + } + + public Encoding[] getTargetEncodings() { + return formats; + } + + public Encoding[] getTargetEncodings(AudioFormat sourceFormat) { + if(AudioFloatConverter.getConverter(sourceFormat) == null) return new Encoding[0]; + return formats; + } + + public AudioFormat[] getTargetFormats(Encoding targetEncoding, AudioFormat sourceFormat) { + if(AudioFloatConverter.getConverter(sourceFormat) == null) return new AudioFormat[0]; + int channels = sourceFormat.getChannels(); + ArrayList<AudioFormat> formats = new ArrayList<AudioFormat>(); + 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)); + 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; + } + +}
--- a/overlays/openjdk/jdk/src/share/classes/com/sun/media/sound/CHANGES.txt Sun May 04 23:35:04 2008 +0200 +++ b/overlays/openjdk/jdk/src/share/classes/com/sun/media/sound/CHANGES.txt Mon May 05 00:31:45 2008 +0200 @@ -1,3 +1,22 @@ + - Removed: PATSoundBankReader removed because no format license is available. + It is also undocumented format. + - Added: AudioFloatFormatConverter, used to convert + between PCM_SIGNED, PCM_UNSIGNED, PCM_FLOAT in 8/16/24/32 bit (big/little endian), + and resample using (linear/cubic/sinc...) if needed. + - Added: WaveExtensibleReader, used to read WAV files using WAVE_FORMAT_EXTENSIBLE format. + - Added: WaveFloatFileWriter, used to writing WAV files with PCM_FLOAT encoding. + - Fix: AudioFloatConverter tests incorrectly AudioFormat frameSize against SampleSizeInBits + Support for 64-byte float added, and support for 32+ bit PCM samples. + SampleSizeInBits not dividable by 8 are now handled correctly. + - Fix: DLSID(GUID) values incorrectly read from files in DLSSoundBank. + - Fix: WaveFloatFileReader incorrectly sets framrate. + - Fix: DLSSoundbank writes avgBytesPerSec incorrectly if SampleSizeInBits is not dividable by 8. + - Fix: SoftChannel didn't reset concept of LSB control to 0 when MSB control value is set + (according to MIDI 1.0 Detailed Spec. page 12) + - Fix: SoftChannel, added check for illegal noteNumbers. + If illegal notenumber was used in NoteOn/NoteOff + a ArrayOutOfIndex exception was thrown. + - Fix: Default tempo in SoftMidiFileReader was supposed to be 500000 mpq or 120 bpm - Fix: Change type of info variable in SoftSynthesize into MidiDevice.Info - Fix: Fix instanceof check of p1 variable in ModelInstrumentComparator
--- a/overlays/openjdk/jdk/src/share/classes/com/sun/media/sound/DLSSoundbank.java Sun May 04 23:35:04 2008 +0200 +++ b/overlays/openjdk/jdk/src/share/classes/com/sun/media/sound/DLSSoundbank.java Mon May 05 00:31:45 2008 +0200 @@ -100,14 +100,14 @@ d.i1 = riff.readUnsignedInt(); d.s1 = riff.readUnsignedShort(); d.s2 = riff.readUnsignedShort(); - d.x1 = riff.readByte(); - d.x2 = riff.readByte(); - d.x3 = riff.readByte(); - d.x4 = riff.readByte(); - d.x5 = riff.readByte(); - d.x6 = riff.readByte(); - d.x7 = riff.readByte(); - d.x8 = riff.readByte(); + 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; } @@ -1006,11 +1006,13 @@ fmt_chunk.writeUnsignedShort(sampleformat); fmt_chunk.writeUnsignedShort(audioformat.getChannels()); fmt_chunk.writeUnsignedInt((long)audioformat.getSampleRate()); + /* long srate = (long)audioformat.getSampleRate(); srate *= audioformat.getChannels(); srate *= audioformat.getSampleSizeInBits() / 8; //fmt_chunk.writeUnsignedInt((long)audioformat.getFrameRate()); - fmt_chunk.writeUnsignedInt(srate); + fmt_chunk.writeUnsignedInt(srate);*/ + fmt_chunk.writeUnsignedInt(((long)audioformat.getFrameRate())*audioformat.getFrameSize()); fmt_chunk.writeUnsignedShort(audioformat.getFrameSize()); fmt_chunk.writeUnsignedShort(audioformat.getSampleSizeInBits()); fmt_chunk.write(0);
--- a/overlays/openjdk/jdk/src/share/classes/com/sun/media/sound/PATInstrument.java Sun May 04 23:35:04 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,536 +0,0 @@ -/* - * 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.net.URL; - -import javax.sound.midi.Patch; -import javax.sound.sampled.AudioFormat; - -/** - * GUS Instrument. - * - * @version %I%, %E% - * @author Karl Helgason - */ - -public class PATInstrument extends ModelInstrument { - - private class OffsetInputStream extends InputStream - { - - private InputStream is; - private int filepointer = 0; - - public OffsetInputStream(InputStream is) - { - this.is = is; - } - - public long getFilePointer() throws IOException { - return filepointer; - } - - public void close() throws IOException { - is.close(); - } - - public int read(byte[] b, int off, int len) throws IOException { - int ret = is.read(b, off, len); - if(ret != -1) filepointer+=ret; - return ret; - } - - public long skip(long n) throws IOException { - long ret = is.skip(n); - if(ret != -1) filepointer+=ret; - return ret; - } - - public int read() throws IOException { - int ret = is.read(); - if(ret != -1) filepointer++; - return ret; - } - - } - - protected int preset = 0; - - protected int bank = 0; - - protected boolean percussion = false; - - protected String name = ""; - - protected String description = ""; - - protected String format = "GF1PATCH110"; - - protected String vendor = "ID#000002"; - - protected PATSample[] samples = null; - - protected int volume; - - private boolean largeFormat = false; - private File sampleFile; - private OffsetInputStream ois; - - public PATInstrument() { - super(null, null, null, null); - } - - public PATInstrument(URL url) throws IOException { - super(null, null, null, null); - - InputStream is = url.openStream(); - try { - readPatch(is); - } finally { - is.close(); - } - } - - public PATInstrument(File file) throws IOException { - super(null, null, null, null); - largeFormat = true; - sampleFile = file; - InputStream is = new FileInputStream(file); - ois = new OffsetInputStream(is); - is = ois; - try { - readPatch(is); - } finally { - is.close(); - } - } - - public PATInstrument(InputStream inputstream) throws IOException { - super(null, null, null, null); - readPatch(inputstream); - } - - private String readString(InputStream is, int len) throws IOException { - byte[] buffer = new byte[len]; - is.read(buffer); - for (int i = 0; i < buffer.length; i++) { - if (buffer[i] == (byte) 0) { - return new String(buffer, 0, i, "ASCII"); - } - } - return new String(buffer, "ASCII"); - } - - private void readPatch(InputStream inputstream) throws IOException { - format = readString(inputstream, 12); - vendor = readString(inputstream, 10); - if (!(format.equals("GF1PATCH110") || format.equals("GF1PATCH100"))) - throw new InvalidFormatException(); - if (!(vendor.equals("ID#000002"))) - throw new InvalidFormatException(); - description = readString(inputstream, 60); - - int instrument_count = inputstream.read(); - if (instrument_count > 1) - throw new InvalidDataException("Invalid instrument count."); - @SuppressWarnings("unused") - int voices = inputstream.read(); - int channels = inputstream.read(); - if (channels > 1) - throw new InvalidDataException("Invalid channels count."); - @SuppressWarnings("unused") - int waveforms = inputstream.read() + (inputstream.read() << 8); - volume = inputstream.read() + (inputstream.read() << 8); - @SuppressWarnings("unused") - int datasize = inputstream.read() + (inputstream.read() << 8) - + (inputstream.read() << 16) + (inputstream.read() << 24); - byte[] reserve1 = new byte[36]; - inputstream.read(reserve1); - @SuppressWarnings("unused") - int instrumentid = inputstream.read() + (inputstream.read() << 8); - name = readString(inputstream, 16); - @SuppressWarnings("unused") - int instrumentsize = inputstream.read() + (inputstream.read() << 8) - + (inputstream.read() << 16) + (inputstream.read() << 24); - int layers = inputstream.read(); - if (layers > 1) - throw new InvalidDataException("Invalid layers count."); - byte[] reserve2 = new byte[40]; - inputstream.read(reserve2); - @SuppressWarnings("unused") - int layerdupl = inputstream.read(); - @SuppressWarnings("unused") - int layer = inputstream.read(); - @SuppressWarnings("unused") - int layersize = inputstream.read() + (inputstream.read() << 8) - + (inputstream.read() << 16) + (inputstream.read() << 24); - int samples = inputstream.read(); - byte[] reserve3 = new byte[40]; - inputstream.read(reserve3); - - this.samples = new PATSample[samples]; - for (int i = 0; i < samples; i++) { - this.samples[i] = readSample(inputstream); - } - } - - private PATSample readSample(InputStream inputstream) throws IOException { - PATSample patsample = new PATSample(); - - patsample.wavename = readString(inputstream, 7); - patsample.fractions = inputstream.read(); - int sampledatasize = inputstream.read() + (inputstream.read() << 8) - + (inputstream.read() << 16) + (inputstream.read() << 24); - patsample.loopstart = inputstream.read() + (inputstream.read() << 8) - + (inputstream.read() << 16) + (inputstream.read() << 24); - patsample.loopend = inputstream.read() + (inputstream.read() << 8) - + (inputstream.read() << 16) + (inputstream.read() << 24); - patsample.samplerate = inputstream.read() + (inputstream.read() << 8); - patsample.lowfreq = inputstream.read() + (inputstream.read() << 8) - + (inputstream.read() << 16) + (inputstream.read() << 24); - patsample.hifreq = inputstream.read() + (inputstream.read() << 8) - + (inputstream.read() << 16) + (inputstream.read() << 24); - patsample.rootfreq = inputstream.read() + (inputstream.read() << 8) - + (inputstream.read() << 16) + (inputstream.read() << 24); - patsample.tune = inputstream.read() + (inputstream.read() << 8); - patsample.pan = inputstream.read(); - - patsample.env_attack_rate = inputstream.read(); - patsample.env_decay_rate = inputstream.read(); - patsample.env_sustain_rate = inputstream.read(); - patsample.env_release1_rate = inputstream.read(); - patsample.env_release2_rate = inputstream.read(); - patsample.env_release3_rate = inputstream.read(); - - patsample.env_attack_offset = inputstream.read(); - patsample.env_decay_offset = inputstream.read(); - patsample.env_sustain_offset = inputstream.read(); - patsample.env_release1_offset = inputstream.read(); - patsample.env_release2_offset = inputstream.read(); - patsample.env_release3_offset = inputstream.read(); - - patsample.tremolo_sweep = inputstream.read(); - patsample.tremolo_rate = inputstream.read(); - patsample.tremolo_depth = inputstream.read(); - patsample.vibrato_sweep = inputstream.read(); - patsample.vibrato_rate = inputstream.read(); - patsample.vibrato_depth = inputstream.read(); - patsample.sampling_mode = inputstream.read(); - patsample.scalefreq = inputstream.read() + (inputstream.read() << 8); - patsample.scalefactor = inputstream.read() + (inputstream.read() << 8); - byte[] reserve1 = new byte[36]; - inputstream.read(reserve1); - - if(largeFormat) - { - long offset = ois.getFilePointer(); - inputstream.skip(sampledatasize); - patsample.sampledata = new ModelByteBuffer(sampleFile, offset, sampledatasize); - } - else - { - byte[] buff = new byte[sampledatasize]; - inputstream.read(buff); - patsample.sampledata = new ModelByteBuffer(buff); - } - - return patsample; - - } - - 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(); - } - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getFormat() { - return format; - } - - public void setFormat(String format) { - this.format = format; - } - - public String getVendor() { - return vendor; - } - - public void setVendor(String vendor) { - this.vendor = vendor; - } - - private double convertRate(int rate) { - return (rate & 63) * Math.pow(1.0 / 2.0, 3 * ((rate >> 6) & 3)); - } - - public ModelPerformer[] getPerformers() { - - ModelPerformer[] performers = new ModelPerformer[samples.length]; - for (int i = 0; i < performers.length; i++) { - ModelPerformer performer = new ModelPerformer(); - PATSample patsample = samples[i]; - performer.setName(samples[i].wavename); - - double keyfrom = 69 + 12 - * Math.log((patsample.lowfreq / 1000.0) / 440.0) - / Math.log(2.0); - double keyto = 69 + 12 - * Math.log((patsample.hifreq / 1000.0) / 440.0) - / Math.log(2.0); - - performer.setKeyFrom((int)Math.ceil(keyfrom)); - performer.setKeyTo((int)Math.floor(keyto)); - - ModelByteBuffer buffer = patsample.sampledata; - - boolean is16bit = (patsample.sampling_mode & 1) != 0; - boolean isUnsigned = (patsample.sampling_mode & 2) != 0; - boolean isLooping = (patsample.sampling_mode & 4) != 0; - boolean isPingPongLoop = (patsample.sampling_mode & 8) != 0; - boolean isReverseLoop = (patsample.sampling_mode & 16) != 0; - //boolean isSustain = (patsample.sampling_mode & 32) != 0; - boolean isEnv = (patsample.sampling_mode & 64) != 0; - //boolean isClampedRelease = (patsample.sampling_mode & 128) != 0; - - - AudioFormat audioformat = null; - if (is16bit) - audioformat = new AudioFormat(patsample.samplerate, 16, 1, - !isUnsigned, false); - else - audioformat = new AudioFormat(patsample.samplerate, 8, 1, - !isUnsigned, false); - - float pitchcorrection = -(float) (69 + 12 - * Math.log((patsample.rootfreq / 1000.0) / 440.0) - / Math.log(2.0)); - pitchcorrection *= 100; - - ModelByteBufferWavetable osc = new ModelByteBufferWavetable(buffer, - audioformat, pitchcorrection); - - float loopstart = patsample.loopstart + ((patsample.fractions&0xF)/16f); - float loopend = patsample.loopend + ((patsample.fractions>>4)/16f); - - if (isLooping) { - if (is16bit) { - osc.setLoopStart(loopstart / 2f); - osc.setLoopLength(loopend / 2f - - loopstart / 2f); - } else { - osc.setLoopStart(loopstart); - osc.setLoopLength(loopend - loopstart); - } - osc.setLoopType(ModelWavetable.LOOP_TYPE_FORWARD); - if(isPingPongLoop) - osc.setLoopType(ModelWavetable.LOOP_TYPE_PINGPONG); - if(isReverseLoop) - osc.setLoopType(ModelWavetable.LOOP_TYPE_REVERSE); - } - performer.getOscillators().add(osc); - - double lfo_vib_rate = patsample.vibrato_rate / 42.0; - double lfo_vol_rate = patsample.tremolo_rate / 42.0; - double lfo_vib_depth = 400.0 * patsample.vibrato_depth / 256.0; - - performer.getConnectionBlocks().add( - new ModelConnectionBlock(6900 + 1200.0 - * Math.log(lfo_vol_rate / 440.0) / Math.log(2), - new ModelDestination( - ModelDestination.DESTINATION_LFO1_FREQ))); - if(lfo_vib_depth > 0) - performer.getConnectionBlocks().add( - new ModelConnectionBlock(6900 + 1200.0 - * Math.log(lfo_vib_rate / 440.0) / Math.log(2), - new ModelDestination( - ModelDestination.DESTINATION_LFO2_FREQ))); - - - if (lfo_vib_depth > 0) { - ModelIdentifier src = ModelSource.SOURCE_LFO2; - ModelIdentifier dest = ModelDestination.DESTINATION_PITCH; - performer.getConnectionBlocks().add( - new ModelConnectionBlock(new ModelSource(src, - ModelStandardTransform.DIRECTION_MIN2MAX, - ModelStandardTransform.POLARITY_BIPOLAR), - lfo_vib_depth, new ModelDestination(dest))); - } - - double lfo_vol_depth = -200 - * Math.log(1.0 - patsample.tremolo_depth / 256.0) - / Math.log(10); - if (lfo_vol_depth > 960) - lfo_vol_depth = 960; - if (lfo_vol_depth > 0) { - ModelIdentifier src = ModelSource.SOURCE_LFO1; - ModelIdentifier dest = ModelDestination.DESTINATION_GAIN; - performer.getConnectionBlocks().add( - new ModelConnectionBlock(new ModelSource(src, - ModelStandardTransform.DIRECTION_MIN2MAX, - ModelStandardTransform.POLARITY_BIPOLAR), - lfo_vol_depth, new ModelDestination(dest))); - } - - double volume = this.volume / 128.0; - if (isEnv) { - double env_attack_msec = patsample.env_attack_offset - / convertRate(patsample.env_attack_rate); - double env_decay_msec = 0.5*(patsample.env_attack_offset - patsample.env_decay_offset) - / convertRate(patsample.env_decay_rate); - env_decay_msec += 0.5*(patsample.env_decay_offset - patsample.env_sustain_offset) - / convertRate(patsample.env_sustain_rate); - double env_release_msec = 0.5*(patsample.env_attack_offset - 0) - / convertRate(patsample.env_release1_rate); - /* patsample.env_release1_offset - env_release_msec += (patsample.env_release1_offset - patsample.env_release2_offset) - / convertRate(patsample.env_release2_rate); - env_release_msec += (patsample.env_release2_offset - patsample.env_release3_offset) - / convertRate(patsample.env_release3_rate); - */ - double env_volume_level = patsample.env_attack_offset / 256.0; - double env_sustain_level = patsample.env_sustain_offset / 256.0; - if (env_attack_msec < 0) - env_attack_msec = 0; - if (env_decay_msec < 0) - env_decay_msec = 0; - if (env_release_msec < 0) - env_release_msec = 0; - volume *= env_volume_level; - performer - .getConnectionBlocks() - .add( - new ModelConnectionBlock( - env_sustain_level * 1000.0, - new ModelDestination( - ModelDestination.DESTINATION_EG1_SUSTAIN))); - performer.getConnectionBlocks().add( - new ModelConnectionBlock(1200.0 - * Math.log(env_attack_msec / 1000.0) - / Math.log(2), new ModelDestination( - ModelDestination.DESTINATION_EG1_ATTACK))); - performer.getConnectionBlocks().add( - new ModelConnectionBlock(1200.0 - * Math.log(env_decay_msec / 1000.0) - / Math.log(2), new ModelDestination( - ModelDestination.DESTINATION_EG1_DECAY))); - performer.getConnectionBlocks().add( - new ModelConnectionBlock(1200.0 - * Math.log(env_release_msec / 1000.0) - / Math.log(2), new ModelDestination( - ModelDestination.DESTINATION_EG1_RELEASE))); - } else { - if (!isLooping) - performer - .getConnectionBlocks() - .add( - new ModelConnectionBlock( - 12000.0, - new ModelDestination( - ModelDestination.DESTINATION_EG1_RELEASE))); - } - - // Linear gain to dB - double gain = ((20.0) / Math.log(10)) * Math.log(volume); - performer.getConnectionBlocks().add( - new ModelConnectionBlock(gain, new ModelDestination( - ModelDestination.DESTINATION_GAIN))); - - double panning = 500; - if (patsample.pan < 7) - panning = (patsample.pan / 7.0) * 500.0; - if (patsample.pan > 8) - panning += ((patsample.pan - 8) / 7.0) * 500.0; - performer.getConnectionBlocks().add( - new ModelConnectionBlock(panning - 500.0, - new ModelDestination( - ModelDestination.DESTINATION_PAN))); - - // Modulation wheel should use SOURCE_LFO2 (vib) - 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))); - - performers[i] = performer; - } - - return performers; - } - - public PATSample[] getSamples() { - return samples; - } - - public void setSamples(PATSample[] samples) { - this.samples = samples; - } - -}
--- a/overlays/openjdk/jdk/src/share/classes/com/sun/media/sound/PATSample.java Sun May 04 23:35:04 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,113 +0,0 @@ -/* - * 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; - -/** - * GUS Sample storage. - * - * @version %I%, %E% - * @author Karl Helgason - */ - -public class PATSample { - - public String wavename = ""; - - public int fractions; - - // bit 0..3: Loop offset start fractions [0/16 .. 15/16] - // bit 4..7: Loop offset end fractions [0/16 .. 15/16] - - public int loopstart; - - public int loopend; - - public int samplerate; - - public int lowfreq; - - public int hifreq; - - public int rootfreq; - - public int tune; // not used - - public int pan; // 0..15, 7 and 8 are center - - public int env_attack_rate; - - public int env_decay_rate; - - public int env_sustain_rate; - - public int env_release1_rate; - - public int env_release2_rate; // ignored - - public int env_release3_rate; // ignored - - public int env_attack_offset; - - public int env_decay_offset; - - public int env_sustain_offset; - - public int env_release1_offset; - - public int env_release2_offset; // ignored - - public int env_release3_offset; // ignored - - public int tremolo_sweep; // ignored - - public int tremolo_rate; - - public int tremolo_depth; - - public int vibrato_sweep; // ignored - - public int vibrato_rate; - - public int vibrato_depth; - - public int sampling_mode; - - // bit 0: 16-bit (versus 8-bit) - // bit 1: Unsigned (versus signed) - // bit 2: Looped - // bit 3: Pingpong Loop - // bit 4: Reverse - // bit 5: Sustain <- Ignored - // bit 6: Envelope - // bit 7: Clamped release (6th point of envelope) <- Ignored - - public int scalefreq; // ignored - - public int scalefactor; // ignored - - public ModelByteBuffer sampledata; - -}
--- a/overlays/openjdk/jdk/src/share/classes/com/sun/media/sound/PATSoundbankReader.java Sun May 04 23:35:04 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,296 +0,0 @@ -/* - * 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.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.net.URL; -import java.util.HashMap; -import java.util.Map; -import java.util.StringTokenizer; - -import javax.sound.midi.InvalidMidiDataException; -import javax.sound.midi.Patch; -import javax.sound.midi.Soundbank; -import javax.sound.midi.spi.SoundbankReader; - -/** - * GUS-compatible GF1 Patch reader. - * - * @version %I%, %E% - * @author Karl Helgason - */ - -public class PATSoundbankReader extends SoundbankReader { - - public Soundbank getSoundbank(URL url) throws InvalidMidiDataException, - IOException { - try { - PATInstrument ins = new PATInstrument(url); - SimpleSoundbank snk = new SimpleSoundbank(); - snk.addInstrument(ins); - return snk; - } catch (InvalidFormatException e) { - return null; - } catch (IOException ioe) { - return null; - } - } - - public Soundbank getSoundbank(InputStream stream) - throws InvalidMidiDataException, IOException { - try { - stream.mark(512); - PATInstrument ins = new PATInstrument(stream); - SimpleSoundbank snk = new SimpleSoundbank(); - snk.addInstrument(ins); - return snk; - } catch (InvalidFormatException e) { - stream.reset(); - return null; - } - } - - - public Soundbank getSoundbank(File file) throws InvalidMidiDataException, IOException { - if (file.getPath().toLowerCase().endsWith(".cfg")) - return readConfigFile(file); - if (!file.getPath().toLowerCase().endsWith(".pat")) - return null; - try { - PATInstrument ins = new PATInstrument(file); - SimpleSoundbank snk = new SimpleSoundbank(); - snk.addInstrument(ins); - return snk; - } catch (InvalidFormatException e) { - return null; - } - } - - private ModelPerformer[] processDrumKit(PATInstrument ins) - { - ModelPerformer[] performers = ins.getPerformers(); - - for (ModelPerformer performer : performers) { - double pc = -((ModelWavetable) performer - .getOscillators().get(0)) - .getPitchcorrection() / 100.0; - performer - .getConnectionBlocks() - .add( - new ModelConnectionBlock( - pc / 128.0, - new ModelDestination( - ModelDestination.DESTINATION_KEYNUMBER))); - - if(((ModelWavetable) performer.getOscillators().get(0)).getLoopType() == ModelWavetable.LOOP_TYPE_OFF) - { - performer - .getConnectionBlocks() - .add( - new ModelConnectionBlock( - 12000, - new ModelDestination( - ModelDestination.DESTINATION_EG1_RELEASE))); - - } - } - return performers; - } - - private Soundbank readConfigFile(File file) - throws InvalidMidiDataException, IOException { - File root = file.getParentFile(); - SimpleSoundbank soundbank = new SimpleSoundbank(); - FileInputStream in = new FileInputStream(file); - try { - try { - - int bank = -2; - int drumset = -1; - SimpleInstrument drumsetins = null; - - HashMap<Integer, HashMap<Integer, ModelPerformer[]>> multipatchmaps - = new HashMap<Integer, HashMap<Integer, ModelPerformer[]>>(); - - Reader r = new InputStreamReader(in, "ASCII"); - BufferedReader br = new BufferedReader(r); - String line = null; - while ((line = br.readLine()) != null) { - int li = line.indexOf('#'); - if (li != -1) - line = line.substring(0, li); - line = line.trim(); - if (line.length() == 0) - continue; - StringTokenizer st = new StringTokenizer(line, " "); - if (!st.hasMoreTokens()) - continue; - String token = st.nextToken(); - if (token.equalsIgnoreCase("drumset")) { - if (!st.hasMoreTokens()) - continue; - token = st.nextToken(); - drumset = Integer.parseInt(token); - bank = -1; - drumsetins = new SimpleInstrument(); - drumsetins.setPatch(new ModelPatch(0, drumset, true)); - soundbank.addInstrument(drumsetins); - } else if (token.equalsIgnoreCase("bank")) { - if (!st.hasMoreTokens()) - continue; - token = st.nextToken(); - drumset = -1; - bank = Integer.parseInt(token); - } else - if(bank == -2) - { - int prg_from = 0; - int prg_to = 0; - int li2 = token.indexOf('-'); - if(li2 == -1) - { - prg_from = Integer.parseInt(token)-1; - prg_to = Integer.parseInt(token)-1; - } - else - { - prg_from = Integer.parseInt(token.substring(0, li2))-1; - prg_to = Integer.parseInt(token.substring(li2+1))-1; - } - if(prg_to < 0) continue; - if(prg_to < prg_from) continue; - if(prg_from < 0) prg_from = 0; - - if(!st.hasMoreTokens()) continue; - token = st.nextToken(); - if(token.equals("begin_multipatch") || token.equals("override_patch")) - { - - HashMap<Integer, ModelPerformer[]> multipatchmap = new HashMap<Integer, ModelPerformer[]>(); - if(token.equals("override_patch")) - { - HashMap<Integer, ModelPerformer[]> omap = multipatchmaps.get(prg_from); - if(omap != null) - multipatchmap.putAll(omap); - } - for (int prg = prg_from; prg <= prg_to; prg++) - multipatchmaps.put(prg, multipatchmap); - - - while ((line = br.readLine()) != null) { - if(line.equals("end_multipatch")) break; - - StringTokenizer st2 = new StringTokenizer(line, " "); - if(!st2.hasMoreTokens()) continue; - int key = Integer.parseInt(st2.nextToken().trim()); - if(!st2.hasMoreTokens()) continue; - token = st2.nextToken(); - File patfile = new File(root, token); - if (!patfile.exists()) - patfile = new File(root, token + ".pat"); - - multipatchmap.put(key, processDrumKit(new PATInstrument(patfile))); - } - } - else - { - File patfile = new File(root, token); - if (!patfile.exists()) - patfile = new File(root, token + ".pat"); - - for (int prg = prg_from; prg <= prg_to; prg++) { - PATInstrument ins = new PATInstrument(patfile); - if(prg != 0) - { - if(prg >= 128) - ins.setPatch(new ModelPatch(0, prg-128, true)); - else - ins.setPatch(new Patch(0, prg)); - } - soundbank.addInstrument(ins); - } - - } - } - else - { - int id = Integer.parseInt(token); - if (!st.hasMoreTokens()) - continue; - token = st.nextToken(); - File patfile = new File(root, token); - if (!patfile.exists()) { - patfile = new File(root, token + ".pat"); - } - PATInstrument ins = new PATInstrument(patfile); - - if (bank != -1) { - ins.setPatch(new Patch(bank, id)); - soundbank.addInstrument(ins); - } else if (drumset != -1) { - drumsetins.add(processDrumKit(ins), id, id); - } - } - - } - - for(Map.Entry<Integer, HashMap<Integer, ModelPerformer[]>> entry : - multipatchmaps.entrySet()) - { - - int prg = entry.getKey(); - drumsetins = new SimpleInstrument(); - if(prg >= 128) - drumsetins.setPatch(new ModelPatch(0, prg-128, true)); - else - drumsetins.setPatch(new Patch(0, prg)); - - drumsetins.add(entry.getValue().get(36)); - for(Map.Entry<Integer, ModelPerformer[]> entry2 : entry.getValue().entrySet()) - drumsetins.add(entry2.getValue(), entry2.getKey(), entry2.getKey()); - - soundbank.addInstrument(drumsetins); - - } - - } finally { - in.close(); - } - } catch (Exception e) { - e.printStackTrace(); - return null; - } - return soundbank; - } - - -}
--- a/overlays/openjdk/jdk/src/share/classes/com/sun/media/sound/SoftChannel.java Sun May 04 23:35:04 2008 +0200 +++ b/overlays/openjdk/jdk/src/share/classes/com/sun/media/sound/SoftChannel.java Mon May 05 00:31:45 2008 +0200 @@ -423,6 +423,7 @@ public void noteOn(int noteNumber, int velocity) { + if(noteNumber < 0 || noteNumber > 127) return; noteOn_internal(noteNumber, velocity); if(current_mixer != null) current_mixer.noteOn(noteNumber, velocity); } @@ -551,6 +552,7 @@ public void noteOff(int noteNumber, int velocity) { + if(noteNumber < 0 || noteNumber > 127) return; noteOff_internal(noteNumber, velocity); if(current_mixer != null) current_mixer.noteOff(noteNumber, velocity); @@ -644,6 +646,7 @@ } public void noteOff(int noteNumber) { + if(noteNumber < 0 || noteNumber > 127) return; noteOff_internal(noteNumber, 64); } @@ -1044,7 +1047,7 @@ } if(controller == 6) - val = (val & 127) + (value << 7); + val = /*(val & 127) +*/ (value << 7); else if(controller == 38) val = (val & (127 << 7)) + value; else if(controller == 96 || controller == 97) @@ -1161,7 +1164,7 @@ if (controller == 0x00) { - bank = (bank & 127) + (value << 7); + bank = /*(bank & 127) +*/ (value << 7); return; } @@ -1170,13 +1173,9 @@ return; } - // Keep track of values (capped to 7 bit). - // Reset least significant (32 through 63) - // controller value when most significant - // (0 through 31) is set. - this.controller[controller] = value & 127; - if (controller < 32) - this.controller[controller + 32] = 0; + this.controller[controller] = value; + if(controller < 0x20) + this.controller[controller + 0x20] = 0; for (int i = 0; i < voices.length; i++) if (voices[i].active) @@ -1188,7 +1187,9 @@ public int getController(int controller) { synchronized (control_mutex) { - return this.controller[controller]; + // Should only return lower 7 bits, + // even when controller is "boosted" higher. + return this.controller[controller] & 127; } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/overlays/openjdk/jdk/src/share/classes/com/sun/media/sound/WaveExtensibleFileReader.java Mon May 05 00:31:45 2008 +0200 @@ -0,0 +1,331 @@ +/* + * 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.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; + +import javax.sound.sampled.AudioFileFormat; +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.UnsupportedAudioFileException; +import javax.sound.sampled.AudioFormat.Encoding; +import javax.sound.sampled.spi.AudioFileReader; + +/** + * WAVE file reader for files using format WAVE_FORMAT_EXTENSIBLE (0xFFFE). + * + * @version %I%, %E% + * @author Karl Helgason + */ + +public class WaveExtensibleFileReader extends AudioFileReader { + + + static private class GUID + { + long i1; + int s1; + int s2; + int x1; + int x2; + int x3; + int x4; + int x5; + int x6; + int x7; + int x8; + + private GUID() + { + } + public GUID(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 GUID read(RIFFReader riff) throws IOException + { + GUID d = new GUID(); + 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 boolean equals(Object obj) { + if(!(obj instanceof GUID)) return false; + GUID t = (GUID)obj; + if(i1 != t.i1) return false; + if(s1 != t.s1) return false; + if(s2 != t.s2) return false; + if(x1 != t.x1) return false; + if(x2 != t.x2) return false; + if(x3 != t.x3) return false; + if(x4 != t.x4) return false; + if(x5 != t.x5) return false; + if(x6 != t.x6) return false; + if(x7 != t.x7) return false; + if(x8 != t.x8) return false; + return true; + } + + + } + + private static String[] channelnames = + { "FL", "FR", "FC", "LF", "BL", "BR", // 5.1 + "FLC", "FLR", "BC", "SL", "SR", + "TC", "TFL", "TFC", "TFR", "TBL", "TBC", "TBR"}; + + private static String[] allchannelnames = + { "w1", "w2", "w3", "w4", "w5", "w6", "w7", "w8", "w9", "w10", + "w11", "w12", "w13", "w14", "w15", "w16", "w17", "w18", "w19", "w20", + "w21", "w22", "w23", "w24", "w25", "w26", "w27", "w28", "w29", "w30", + "w31", "w32", "w33", "w34", "w35", "w36", "w37", "w38", "w39", "w40", + "w41", "w42", "w43", "w44", "w45", "w46", "w47", "w48", "w49", "w50", + "w51", "w52", "w53", "w54", "w55", "w56", "w57", "w58", "w59", "w60", + "w61", "w62", "w63", "w64"}; + + private static GUID SUBTYPE_PCM = new GUID(0x00000001,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71); + private static GUID SUBTYPE_IEEE_FLOAT = new GUID(0x00000003,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71); + + private String decodeChannelMask(long channelmask) + { + StringBuffer sb = new StringBuffer(); + long m = 1; + for (int i = 0; i < allchannelnames.length; i++) { + if((channelmask & m) != 0L) + { + if(i < channelnames.length) + { + sb.append(channelnames[i] + " "); + } + else + { + sb.append(allchannelnames[i] + " "); + } + } + m *= 2L; + } + if(sb.length() == 0) return null; + return sb.substring(0, sb.length() - 1); + + } + + public AudioFileFormat getAudioFileFormat(InputStream stream) + throws UnsupportedAudioFileException, IOException { + + stream.mark(200); + AudioFileFormat format; + try { + format = internal_getAudioFileFormat(stream); + } finally { + stream.reset(); + } + return format; + } + + private AudioFileFormat internal_getAudioFileFormat(InputStream stream) + throws UnsupportedAudioFileException, IOException { + + RIFFReader riffiterator = new RIFFReader(stream); + if (!riffiterator.getFormat().equals("RIFF")) + throw new UnsupportedAudioFileException(); + if (!riffiterator.getType().equals("WAVE")) + throw new UnsupportedAudioFileException(); + + boolean fmt_found = false; + boolean data_found = false; + + int channels = 1; + long samplerate = 1; + //long framerate = 1; + int framesize = 1; + int bits = 1; + int validBitsPerSample = 1; + long channelMask = 0; + GUID subFormat = null; + + while (riffiterator.hasNextChunk()) { + RIFFReader chunk = riffiterator.nextChunk(); + + if (chunk.getFormat().equals("fmt ")) { + fmt_found = true; + + int format = chunk.readUnsignedShort(); + if (format != 0xFFFE) + throw new UnsupportedAudioFileException(); // WAVE_FORMAT_EXTENSIBLE + // only + channels = chunk.readUnsignedShort(); + samplerate = chunk.readUnsignedInt(); + /*framerate =*/ chunk.readUnsignedInt(); + framesize = chunk.readUnsignedShort(); + bits = chunk.readUnsignedShort(); + int cbSize = chunk.readUnsignedShort(); + if (cbSize != 22) + throw new UnsupportedAudioFileException(); + validBitsPerSample = chunk.readUnsignedShort(); + if(validBitsPerSample > bits) + throw new UnsupportedAudioFileException(); + channelMask = chunk.readUnsignedInt(); + subFormat = GUID.read(chunk); + + } + if (chunk.getFormat().equals("data")) { + data_found = true; + break; + } + } + + if (!fmt_found) + throw new UnsupportedAudioFileException(); + if (!data_found) + throw new UnsupportedAudioFileException(); + + Map<String, Object> p = new HashMap<String, Object>(); + String s_channelmask = decodeChannelMask(channelMask); + if(s_channelmask != null) + p.put("channelOrder", s_channelmask); + if(channelMask != 0) + p.put("channelMask", channelMask); + // validBitsPerSample is only informational for PCM data, + // data is still encode according to SampleSizeInBits. + p.put("validBitsPerSample", validBitsPerSample); + + AudioFormat audioformat = null; + if(subFormat.equals(SUBTYPE_PCM)) + { + if(bits == 8) + { + audioformat = new AudioFormat( + Encoding.PCM_UNSIGNED, samplerate, bits, channels, + framesize, samplerate, false, p ); + } + else + { + audioformat = new AudioFormat( + Encoding.PCM_SIGNED, samplerate, bits, channels, + framesize, samplerate, false, p ); + } + } + else + if(subFormat.equals(SUBTYPE_IEEE_FLOAT)) + { + audioformat = new AudioFormat( + AudioFloatConverter.PCM_FLOAT, samplerate, bits, channels, + framesize, samplerate, false, p ); + } + else + throw new UnsupportedAudioFileException(); + + + AudioFileFormat fileformat = new AudioFileFormat( + AudioFileFormat.Type.WAVE, audioformat, + AudioSystem.NOT_SPECIFIED); + return fileformat; + } + + public AudioInputStream getAudioInputStream(InputStream stream) + throws UnsupportedAudioFileException, IOException { + + AudioFileFormat format = getAudioFileFormat(stream); + RIFFReader riffiterator = new RIFFReader(stream); + if (!riffiterator.getFormat().equals("RIFF")) + throw new UnsupportedAudioFileException(); + if (!riffiterator.getType().equals("WAVE")) + throw new UnsupportedAudioFileException(); + while (riffiterator.hasNextChunk()) { + RIFFReader chunk = riffiterator.nextChunk(); + if (chunk.getFormat().equals("data")) { + return new AudioInputStream(chunk, format.getFormat(), chunk + .getSize()); + } + } + throw new UnsupportedAudioFileException(); + } + + public AudioFileFormat getAudioFileFormat(URL url) + throws UnsupportedAudioFileException, IOException { + InputStream stream = url.openStream(); + AudioFileFormat format; + try { + format = getAudioFileFormat(new BufferedInputStream(stream)); + } finally { + stream.close(); + } + return format; + } + + public AudioFileFormat getAudioFileFormat(File file) + throws UnsupportedAudioFileException, IOException { + InputStream stream = new FileInputStream(file); + AudioFileFormat format; + try { + format = getAudioFileFormat(new BufferedInputStream(stream)); + } finally { + stream.close(); + } + return format; + } + + public AudioInputStream getAudioInputStream(URL url) + throws UnsupportedAudioFileException, IOException { + return getAudioInputStream(new BufferedInputStream(url.openStream())); + } + + public AudioInputStream getAudioInputStream(File file) + throws UnsupportedAudioFileException, IOException { + return getAudioInputStream(new BufferedInputStream(new FileInputStream( + file))); + } + +}
--- a/overlays/openjdk/jdk/src/share/classes/com/sun/media/sound/WaveFloatFileReader.java Sun May 04 23:35:04 2008 +0200 +++ b/overlays/openjdk/jdk/src/share/classes/com/sun/media/sound/WaveFloatFileReader.java Mon May 05 00:31:45 2008 +0200 @@ -75,7 +75,7 @@ int channels = 1; long samplerate = 1; - long framerate = 1; + //long framerate = 1; int framesize = 1; int bits = 1; @@ -91,7 +91,7 @@ // only channels = chunk.readUnsignedShort(); samplerate = chunk.readUnsignedInt(); - framerate = chunk.readUnsignedInt(); + /*framerate =*/ chunk.readUnsignedInt(); framesize = chunk.readUnsignedShort(); bits = chunk.readUnsignedShort(); @@ -109,7 +109,7 @@ AudioFormat audioformat = new AudioFormat( AudioFloatConverter.PCM_FLOAT, samplerate, bits, channels, - framesize, framerate, false); + framesize, samplerate, false); AudioFileFormat fileformat = new AudioFileFormat( AudioFileFormat.Type.WAVE, audioformat, AudioSystem.NOT_SPECIFIED);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/overlays/openjdk/jdk/src/share/classes/com/sun/media/sound/WaveFloatFileWriter.java Mon May 05 00:31:45 2008 +0200 @@ -0,0 +1,141 @@ +/* + * 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.OutputStream; + +import javax.sound.sampled.AudioFileFormat; +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.AudioFileFormat.Type; +import javax.sound.sampled.spi.AudioFileWriter; + +/** + * Floating-point encoded (format 3) WAVE file writer. + * + * @version %I%, %E% + * @author Karl Helgason + */ + +public class WaveFloatFileWriter extends AudioFileWriter { + + private Type[] filetypes = {Type.WAVE}; + + public Type[] getAudioFileTypes() { + return filetypes; + } + + public Type[] getAudioFileTypes(AudioInputStream stream) { + + if(!stream.getFormat().getEncoding().equals(AudioFloatConverter.PCM_FLOAT)) return new Type[0]; + return filetypes; + } + + private void checkFormat(AudioFileFormat.Type type, AudioInputStream stream) + { + if (!Type.WAVE.equals(type)) + throw new IllegalArgumentException("File type " + type + " not supported."); + if(!stream.getFormat().getEncoding().equals(AudioFloatConverter.PCM_FLOAT)) + throw new IllegalArgumentException("File format " + stream.getFormat() + " not supported."); + } + + public void write(AudioInputStream stream, RIFFWriter writer) throws IOException { + + RIFFWriter fmt_chunk = writer.writeChunk("fmt "); + + AudioFormat format = stream.getFormat(); + fmt_chunk.writeUnsignedShort(3); // WAVE_FORMAT_IEEE_FLOAT + fmt_chunk.writeUnsignedShort(format.getChannels()); + fmt_chunk.writeUnsignedInt((int)format.getSampleRate()); + fmt_chunk.writeUnsignedInt(((int)format.getFrameRate())*format.getFrameSize()); + fmt_chunk.writeUnsignedShort(format.getFrameSize()); + fmt_chunk.writeUnsignedShort(format.getSampleSizeInBits()); + fmt_chunk.close(); + RIFFWriter data_chunk = writer.writeChunk("data"); + byte[] buff = new byte[1024]; + int len; + while((len = stream.read(buff, 0, buff.length)) != -1) + data_chunk.write(buff, 0, len); + data_chunk.close(); + } + + private class NoCloseOutputStream extends OutputStream + { + OutputStream out; + public NoCloseOutputStream(OutputStream out) + { + this.out = out; + } + public void write(int b) throws IOException { + out.write(b); + } + public void flush() throws IOException { + out.flush(); + } + public void write(byte[] b, int off, int len) throws IOException { + out.write(b, off, len); + } + public void write(byte[] b) throws IOException { + out.write(b); + } + } + + private AudioInputStream toLittleEndian(AudioInputStream ais) + { + AudioFormat format = ais.getFormat(); + AudioFormat targetFormat = new AudioFormat( + format.getEncoding(), format.getSampleRate(), format.getSampleSizeInBits(), + format.getChannels(), format.getFrameSize(), format.getFrameRate(), false); + return AudioSystem.getAudioInputStream(targetFormat, ais); + } + + public int write(AudioInputStream stream, Type fileType, OutputStream out) throws IOException { + + checkFormat(fileType, stream); + if(stream.getFormat().isBigEndian()) + stream = toLittleEndian(stream); + RIFFWriter writer = new RIFFWriter(new NoCloseOutputStream(out), "WAVE"); + write(stream, writer); + int fpointer = (int)writer.getFilePointer(); + writer.close(); + return fpointer; + } + + public int write(AudioInputStream stream, Type fileType, File out) throws IOException { + checkFormat(fileType, stream); + if(stream.getFormat().isBigEndian()) + stream = toLittleEndian(stream); + RIFFWriter writer = new RIFFWriter(out, "WAVE"); + write(stream, writer); + int fpointer = (int)writer.getFilePointer(); + writer.close(); + return fpointer; + } + +}