samer@0: /* samer@0: * StreamSource.java samer@0: * samer@0: * Copyright (c) 2012, Samer Abdallah, King's College London. samer@0: * All rights reserved. samer@0: * samer@0: * This software is provided AS iS and WITHOUT ANY WARRANTY; samer@0: * without even the implied warranty of MERCHANTABILITY or samer@0: * FITNESS FOR A PARTICULAR PURPOSE. samer@0: */ samer@0: samer@46: package ishara.audio; samer@0: import javax.sound.sampled.*; samer@0: import java.io.*; samer@0: samer@0: public class StreamSource extends AudioSource samer@0: { samer@0: InputStream in; samer@0: samer@0: public StreamSource(AudioInputStream ain) throws Exception { super(ain.getFormat()); in=ain; } samer@0: public StreamSource(AudioInputStream ain, AudioFormat target) throws Exception { samer@0: this(prepareStream(ain,target)); samer@0: } samer@0: samer@0: // AudioSource interface methods samer@0: public void dispose() { samer@0: print("Closing audio stream..."); samer@0: try { in.close(); } catch (IOException ex) {} samer@0: } samer@0: samer@0: public void start() {} samer@0: public void stop() {} samer@0: public int read(byte [] buf, int off, int len) throws Exception { samer@0: return in.read(buf,off,len); samer@0: } samer@0: samer@0: public static AudioInputStream prepareStream(AudioInputStream ain, AudioFormat target) throws Exception { samer@0: // convert to target format if required samer@0: print("Preparing audio stream..."); samer@0: print(" / audio format: "+ain.getFormat().toString()); samer@0: if (target==null) { samer@0: AudioFormat fin=ain.getFormat(); samer@0: ain=convertFormat(new AudioFormat( fin.getSampleRate(), 16, fin.getChannels(), true, false), ain); samer@0: } else { samer@0: ain=convertFormat(target, ain); samer@0: } samer@0: print(" \\ final format: "+ain.getFormat().toString()); samer@0: return ain; samer@0: } samer@0: samer@0: private static AudioInputStream convertVia(AudioFormat fout, AudioInputStream sin, AudioFormat fint) throws Exception samer@0: { samer@0: print(" | Trying recursive via "+fint.toString()); samer@0: AudioInputStream sint=AudioSystem.getAudioInputStream(fint,sin); samer@0: AudioFormat fres=sint.getFormat(); samer@0: if (!fres.equals(fint)) { samer@0: print(" | obtained "+fres.toString()); samer@0: } samer@0: return convertFormat(fout, sint); samer@0: } samer@0: samer@0: public static AudioInputStream convertFormat(AudioFormat fout, AudioInputStream sin) throws Exception samer@0: { samer@0: AudioFormat fin=sin.getFormat(); samer@0: samer@0: if (fin.equals(fout)) return sin; samer@0: if (fin.getEncoding()!=AudioFormat.Encoding.PCM_SIGNED) { samer@0: if (fin.getEncoding().getClass().getName().startsWith("javazoom.spi.")) { samer@0: // these are broken, must go via 16 bit decode with no channels change samer@0: print(" ! Detected noncompliant Javazoom decoder, going via 16 bit."); samer@0: return convertVia( fout, sin, new AudioFormat( samer@0: fin.getSampleRate(), 16, fin.getChannels(), true, fout.isBigEndian())); samer@0: } samer@0: samer@0: // first get into PCM encoding, then try recursive samer@0: try { samer@0: return convertVia( fout, sin, new AudioFormat( samer@0: fin.getSampleRate(), fout.getSampleSizeInBits(), samer@0: fin.getChannels(), true, fout.isBigEndian())); samer@0: } catch (IllegalArgumentException ex) { samer@0: print(" * Direct conversion failed"); samer@0: } samer@0: return convertVia( fout, sin, new AudioFormat( samer@0: fin.getSampleRate(), fin.getSampleSizeInBits(), samer@0: fin.getChannels(), true, fout.isBigEndian())); samer@0: } samer@0: samer@0: if ( !unify(fin.getChannels(),fout.getChannels()) samer@0: || !unify(fin.getSampleSizeInBits(),fout.getSampleSizeInBits())) { samer@0: // convert these before doing any sample rate conversion samer@0: return convertVia(fout, sin, new AudioFormat( samer@0: fin.getSampleRate(), fout.getSampleSizeInBits(), samer@0: fout.getChannels(), true, fout.isBigEndian())); samer@0: } samer@0: samer@0: // the only thing left is sample rate samer@0: return AudioSystem.getAudioInputStream(fout,sin); samer@0: } samer@0: samer@0: private static boolean unify(int x, int y) { return x==-1 || y==-1 || x==y; } samer@0: private static boolean unify(float x, float y) { return x==-1 || y==-1 || x==y; } samer@0: } samer@0: