/*
* Created on 29 Dec 2007
*
* Copyright (c) 2004-2007 Paul John Leonard
*
* http://www.frinika.com
*
* This file is part of Frinika.
*
* Frinika is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* Frinika 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 for more details.
* You should have received a copy of the GNU General Public License
* along with Frinika; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.frinika.audio.analysis;
import com.frinika.audio.analysis.dft.AudioFlags;
import uk.org.toot.audio.core.AudioBuffer;
import uk.org.toot.audio.core.AudioProcess;
/**
*
* Implementation of a cyclic buffer.
*
* This buffer is fed using the in.processAudio(buff);
* this returns OVERFLOW if the buffer is full
*
* You read the buffer using out.processAudio(buff);
* this will block if no data is ready
*
*
* @author pjl
*/
public class CycliclyBufferedAudio {
public final static int OVERFLOW = -1;
float buff[];
int cacheSize;
long inPtr = 0;
long outPtr = 0;
Thread outBlockingThread = null;
public final AudioProcess in = new In();
public final AudioProcess out = new Out();
private int required;
private boolean itWasMe = false;
// private boolean disconnected = false;
int overflowCount=0;
private boolean blocking=false;
private float Fs;
public CycliclyBufferedAudio(int cacheSize,float Fs) {
this.cacheSize = cacheSize;
this.Fs=Fs;
buff = new float[cacheSize];
}
public float getSampleRate() {
return Fs;
}
class In implements AudioProcess {
int cnt;
public void close() throws Exception {
// TODO Auto-generated method stub
}
public void open() throws Exception {
// TODO Auto-generated method stub
}
public int processAudio(AudioBuffer buffer) {
int n = buffer.getSampleCount();
if (inPtr + n - outPtr > cacheSize) {
System.out.println(" OVERFLOW " + overflowCount++);
return OVERFLOW;
}
// float a[] = buffer.getChannel(0);
// for (int i = 0; i < n; i++) {
// a[i] = (float) Math.sin(cnt++ * 2500.0 / 44100.0);
// }
int inCy0 = (int) (inPtr % cacheSize);
int inCy1 = (int) ((inPtr + n) % cacheSize);
if (inCy1 > inCy0) {
System.arraycopy(buffer.getChannel(0), 0, buff, inCy0, n);
} else {
System.arraycopy(buffer.getChannel(0), 0, buff, inCy0, n
- inCy1);
System.arraycopy(buffer.getChannel(0), n - inCy1, buff, 0,
inCy1);
}
inPtr += n;
if (blocking) {
if (inPtr - outPtr > required) {
itWasMe = true;
outBlockingThread.interrupt(); // Ha ha this can be null !!!!
}
}
return AUDIO_OK;
}
}
class Out implements AudioProcess {
synchronized public int processAudio(AudioBuffer buffer) {
required = buffer.getSampleCount();
if (inPtr - outPtr < required) {
outBlockingThread = Thread.currentThread();
try {
// clear any pending interupts
while(Thread.interrupted()){}
blocking=true;
wait();
} catch (InterruptedException e) {
blocking=false;
if (itWasMe) {
// outBlockingThread = null;
itWasMe = false;
} else {
e.printStackTrace();
e.getCause().printStackTrace();
// outBlockingThread = null;
inPtr=0;
outPtr=0;
itWasMe=false;
return AudioFlags.INTERRUPTED;
}
// System.out.println(" Buffer unblocked ");
}
assert (inPtr - outPtr >= required);
}
int outCy0 = (int) (outPtr % cacheSize);
int outCy1 = (int) ((outPtr + required) % cacheSize);
if (outCy1 > outCy0) {
System.arraycopy(buff, outCy0, buffer.getChannel(0), 0,
required);
// buffer.getChannel(0), 0, buff, inCy0, n);
} else {
System.arraycopy(buff, outCy0, buffer.getChannel(0), 0,
required - outCy1);
System.arraycopy(buff, 0, buffer.getChannel(0), required
- outCy1, outCy1);
//
// System.arraycopy(buffer.getChannel(0), 0, buff, inCy0,
// n-inCy1);
// System.arraycopy(buffer.getChannel(0), n-inCy1, buff, 0,
// inCy1);
}
outPtr += required;
return AUDIO_OK;
}
public void close() throws Exception {
// TODO Auto-generated method stub
}
public void open() throws Exception {
// TODO Auto-generated method stub
}
}
class OverflowException extends Exception {
@Override
public String toString() {
return " BufferedAuioProcess: Overflow ";
}
}
public int getLag() {
return (int) (inPtr-outPtr);
}
}