/* * TCircularBuffer.java * * This file is part of Tritonus: http://www.tritonus.org/ */ /* * Copyright (c) 1999 by Matthias Pfisterer * Copyright (c) 2012 by fireandfuel from Cuina Team (http://www.cuina.byethost12.com/) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as published * by the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ package sound.tritonus; public class TCircularBuffer { private boolean m_bBlockingRead; private boolean m_bBlockingWrite; private byte[] m_abData; private int m_nSize; private long m_lReadPos; private long m_lWritePos; private Trigger m_trigger; private boolean m_bOpen; public TCircularBuffer(int nSize, boolean bBlockingRead, boolean bBlockingWrite, Trigger trigger) { m_bBlockingRead = bBlockingRead; m_bBlockingWrite = bBlockingWrite; m_nSize = nSize; m_abData = new byte[m_nSize]; m_lReadPos = 0; m_lWritePos = 0; m_trigger = trigger; m_bOpen = true; } public void close() { m_bOpen = false; // TODO: call notify() ? } private boolean isOpen() { return m_bOpen; } public int availableRead() { return (int) (m_lWritePos - m_lReadPos); } public int availableWrite() { return m_nSize - availableRead(); } private int getReadPos() { return (int) (m_lReadPos % m_nSize); } private int getWritePos() { return (int) (m_lWritePos % m_nSize); } public int read(byte[] abData) { return read(abData, 0, abData.length); } public int read(byte[] abData, int nOffset, int nLength) { if(!isOpen()) { if(availableRead() > 0) { nLength = Math.min(nLength, availableRead()); } else { return -1; } } synchronized(this) { if(m_trigger != null && availableRead() < nLength) { m_trigger.execute(); } if(!m_bBlockingRead) { nLength = Math.min(availableRead(), nLength); } int nRemainingBytes = nLength; while(nRemainingBytes > 0) { while(availableRead() == 0) { try { wait(); } catch (InterruptedException e) { } } int nAvailable = Math.min(availableRead(), nRemainingBytes); while(nAvailable > 0) { int nToRead = Math.min(nAvailable, m_nSize - getReadPos()); System.arraycopy(m_abData, getReadPos(), abData, nOffset, nToRead); m_lReadPos += nToRead; nOffset += nToRead; nAvailable -= nToRead; nRemainingBytes -= nToRead; } notifyAll(); } return nLength; } } public int write(byte[] abData) { return write(abData, 0, abData.length); } public int write(byte[] abData, int nOffset, int nLength) { synchronized(this) { if(!m_bBlockingWrite) { nLength = Math.min(availableWrite(), nLength); } int nRemainingBytes = nLength; while(nRemainingBytes > 0) { while(availableWrite() == 0) { try { wait(); } catch (InterruptedException e) { } } int nAvailable = Math.min(availableWrite(), nRemainingBytes); while(nAvailable > 0) { int nToWrite = Math.min(nAvailable, m_nSize - getWritePos()); // TDebug.out("src buf size= " + abData.length + // ", offset = " + nOffset + ", dst buf size=" + // m_abData.length + " write pos=" + getWritePos() + " len=" // + nToWrite); System.arraycopy(abData, nOffset, m_abData, getWritePos(), nToWrite); m_lWritePos += nToWrite; nOffset += nToWrite; nAvailable -= nToWrite; nRemainingBytes -= nToWrite; } notifyAll(); } return nLength; } } public static interface Trigger { public void execute(); } } /*** TCircularBuffer.java ***/