/* * Copyright (c) 2007 by Damien Di Fede <ddf@compartmental.net> * * 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 ddf.minim; import javax.sound.sampled.AudioFormat; import javax.sound.sampled.DataLine; import javax.sound.sampled.TargetDataLine; import org.tritonus.share.sampled.FloatSampleBuffer; // now, if I make an interface that is the aggregate of // Recordable and Effectable, or maybe have one extend the other, // AudioInput can keep a reference to an interface, instead // of a concrete class. with that in place, I could make the // constructor public, opening up the possibility that someone // would write their own line reader construct. // It also means that this concrete class could be the // reader thread, thereby eliminating one level of callback. final class MAudioInput extends Thread implements AudioStream { private SignalSplitter splitter; private EffectsChain effects; // line reading variables private TargetDataLine line; private FloatSampleBuffer buffer; private boolean finished; private boolean mono; private byte[] rawBytes; MAudioInput(TargetDataLine tdl, int bufferSize) { splitter = new SignalSplitter(tdl.getFormat(), bufferSize); effects = new EffectsChain(); line = tdl; buffer = new FloatSampleBuffer(tdl.getFormat().getChannels(), bufferSize, tdl.getFormat().getSampleRate()); finished = false; mono = ( buffer.getChannelCount() == 1 ); int byteBufferSize = buffer.getByteArrayBufferSize(line.getFormat()); Minim.debug("byteBufferSize is " + byteBufferSize); rawBytes = new byte[byteBufferSize]; } public void run() { line.start(); while ( !finished ) { // read from the line line.read(rawBytes, 0, rawBytes.length); // convert to float samples buffer.setSamplesFromBytes(rawBytes, 0, line.getFormat(), 0, buffer.getSampleCount()); // apply effects, if any, and broadcast the result // to all listeners if ( mono ) { float[] samp = buffer.getChannel(0); if ( effects.hasEnabled() ) { float[] tmp = new float[samp.length]; System.arraycopy(samp, 0, tmp, 0, tmp.length); effects.process(tmp); samp = tmp; } splitter.samples(samp); } else { float[] sampL = buffer.getChannel(0); float[] sampR = buffer.getChannel(1); if ( effects.hasEnabled() ) { float[] tl = new float[sampL.length]; float[] tr = new float[sampR.length]; System.arraycopy(sampL, 0, tl, 0, tl.length); System.arraycopy(sampR, 0, tr, 0, tr.length); effects.process(tl, tr); sampL = tl; sampR = tr; } splitter.samples(sampL, sampR); } } // we are done, clean up the line line.flush(); line.stop(); line.close(); line = null; } public void open() { start(); } public void close() { finished = true; } public void addListener(AudioListener listener) { splitter.addListener(listener); } public void removeListener(AudioListener listener) { splitter.addListener(listener); } public int bufferSize() { return splitter.bufferSize(); } public AudioFormat getFormat() { return splitter.getFormat(); } public int type() { return splitter.type(); } public void addEffect(AudioEffect effect) { effects.add(effect); } public void clearEffects() { effects.clear(); } public void disableEffect(int i) { effects.disable(i); } public int effectCount() { return effects.size(); } public void effects() { effects.enableAll(); } public void enableEffect(int i) { effects.enable(i); } public AudioEffect getEffect(int i) { return effects.get(i); } public boolean isEffected() { return effects.hasEnabled(); } public void noEffects() { effects.disableAll(); } public void removeEffect(AudioEffect effect) { effects.remove(effect); } public AudioEffect removeEffect(int i) { return effects.remove(i); } public void disableEffect(AudioEffect effect) { effects.disable(effect); } public void enableEffect(AudioEffect effect) { effects.enable(effect); } public boolean isEnabled(AudioEffect effect) { return effects.isEnabled(effect); } public DataLine getDataLine() { return line; } public float sampleRate() { return splitter.sampleRate(); } public boolean hasEffect(AudioEffect effect) { return effects.contains(effect); } }