/*
 * 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;

/**
 * Abstract resampler class.
 *
 * @author Karl Helgason
 */

/*
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();
	}
}
*/

interface SoftAbstractResampler implements SoftResampler {

	public function getPadding() : Int;

	public function interpolate(inp : Array<Float>, in_offset : Array<Float>,
			in_end : Float, pitch : Array<Float>, pitchstep : Float, out : Array<Float>,
			out_offset : Array<Int>, out_end : Int) : Void;

	/*public SoftResamplerStreamer openStreamer() {
		return new ModelAbstractResamplerStream();
	}*/
}
