390 lines · 13.3 KB · Java
RawDownload
/* * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */package com.sun.media.sound; import java.io.IOException;import 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();    }}