Mercurial > hg > jslab
view src/samer/audio/MultiFileAudioStream.java @ 1:5df24c91468d
Oh my what a mess.
author | samer |
---|---|
date | Fri, 05 Apr 2019 16:26:00 +0100 |
parents | |
children |
line wrap: on
line source
/* * FileSource.java * * Copyright (c) 2000, Samer Abdallah, King's College London. * All rights reserved. * * This software is provided AS iS and WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. */ package samer.audio; import samer.core.*; import samer.core.types.*; import samer.core.util.*; import samer.tools.*; import javax.sound.sampled.*; import javax.swing.*; import java.io.*; import java.util.*; import java.nio.ByteBuffer; /** */ public abstract class MultiFileAudioStream extends InputStream { List<File> list=null; ListIterator<File> it=null; int channelsToMix; File curFile=null; InputStream in=null; AudioFormat format=null, inFormat=null; boolean loop=false; /** * Construct a FileSource initialised with current file and loop initialised * from the current Environment. No exception is thrown if the current file * cannot be opened, however, you must be sure to set it to a valid file * (or to set a playlist) before trying to read any samples. */ public MultiFileAudioStream(AudioFormat target, List<File> files) { list=files; format=target; } public AudioFormat getFormat() { return format; } /** Set playlist to all WAV files in given directory */ public List<File> directory(File dir, String ext) { return Arrays.asList(dir.listFiles(getFileFilter(ext))); } private static java.io.FileFilter getFileFilter(final String ext) { return new java.io.FileFilter() { public boolean accept(File file) { return file.getName().toLowerCase().endsWith(ext); } }; } public synchronized List<File> getPlaylist() { return list; } /** Go back to start of playlist. Next block of samples will be from head * of first file in playlist. Will throw an exception if there is no playlist */ public synchronized void rewind() throws IOException { it=list.listIterator(); next(); } /** Move to head of next file in playlist */ public synchronized void next() throws IOException { boolean wasOpen=isOpen(); if (wasOpen) close(); if (!it.hasNext()) { if (!loop) throw new EOFException(); it=list.listIterator(); if (!it.hasNext()) throw new IOException("no files in playlist"); } curFile=it.next(); if (wasOpen) openCurrent(); } /** Move to head of previous file in playlist */ public synchronized void prev() throws Exception { boolean wasOpen=isOpen(); if (wasOpen) close(); if (!it.hasPrevious()) { if (!loop) throw new EOFException(); it=list.listIterator(list.size()); if (!it.hasPrevious()) throw new Exception("no files in playlist"); } curFile=it.previous(); if (wasOpen) openCurrent(); } public boolean isOpen() { return in!=null; } /** Closes current input stream */ public synchronized void close() { try { if (in!=null) { Shell.trace("Closing audio stream..."); in.close(); in=null; } } catch (IOException ex) {} } /** Opens the playlist starting with the first file. */ public synchronized void open() throws Exception { rewind(); if (!isOpen()) openCurrent(); } /** Opens the current file. Next read will returns samples * from head of given file. If setFormat() was called previously, then * we will attempt to do format conversion. */ private synchronized void openCurrent() throws IOException { try { File file=curFile; Shell.trace("\nFileSource:Opening audio file "+file); AudioInputStream s=AudioSystem.getAudioInputStream(file); AudioFormat fmt1, af=s.getFormat(); Shell.trace(" format: "+af); // convert to target format if required if (format!=null) { if (!format.equals(af)) { Shell.trace(" converting to "+format); if (af.getChannels()>format.getChannels()) { int frameSize = af.getChannels()*format.getSampleSizeInBits()/8; Shell.trace(" channels mix down required."); fmt1 = new AudioFormat( format.getEncoding(), format.getSampleRate(), format.getSampleSizeInBits(), af.getChannels(), frameSize, format.getFrameRate(), format.isBigEndian()); channelsToMix = af.getChannels(); } else { channelsToMix = 0; fmt1=format; } Shell.trace(" converting via "+fmt1); s=convertFormat(s,af,fmt1); inFormat = fmt1; } else { Shell.trace(" no formation conversion required"); channelsToMix = 0; inFormat = af; } } else { Shell.trace(" using stream native format"); channelsToMix = 0; inFormat = af; } in=s; } catch (Exception ex) { throw new IOException("Failed to open audio file"); } } /** Returns number of bytes available in current file */ public int available() { try { return in.available(); } catch (Exception ex) { return 0; } } /** Returns a Task which copies samples as doubles into the given * buffer between the given positions. */ public int read(byte [] buf, int off, int len) throws IOException { // loop until len samples copied into dbuf int rem=len, pos=off; while (rem>0) { int chunk = in.read(buf, pos, rem); if (chunk > 0) { // append this chunk to output pos+=chunk; rem-=chunk; } else if (it!=null) next(); // next file if there is one else if (!loop) throw new EOFException(); // not looping and no more files else rewind(); // back to first file } return len; } private static AudioInputStream convertFormat(AudioInputStream sin, AudioFormat fin, AudioFormat fout) throws Exception { Shell.trace("\nconvertFormat:"); Shell.trace(" | source: "+fin.toString()); Shell.trace(" | target: "+fout.toString()); if (fin.equals(fout)) return sin; else if (fin.getEncoding()==AudioFormat.Encoding.PCM_SIGNED) { try { Shell.trace(" | Trying direct (PCM) from "+fin.getEncoding().toString()); return AudioSystem.getAudioInputStream(fout,sin); } catch (IllegalArgumentException ex) { Shell.trace("Direct conversion failed"); } AudioFormat fint = new AudioFormat( // PCM fout.getSampleRate(), fout.getSampleSizeInBits(), fin.getChannels(), true, fout.isBigEndian()); Shell.trace(" | Trying PCM conversion via "+fint.toString()); return AudioSystem.getAudioInputStream(fout,AudioSystem.getAudioInputStream(fint,sin)); } else { // First, check for MP3 - if so, cannot convert number of channels if (fin.getChannels()==fout.getChannels() && fin.getSampleRate()==fout.getSampleRate()) { Shell.trace(" | Trying decoding from "+fin.getEncoding().toString()); return AudioSystem.getAudioInputStream(fout,sin); } else { AudioFormat fint = new AudioFormat( fin.getSampleRate(), fout.getSampleSizeInBits(), fin.getChannels(), true, fout.isBigEndian()); Shell.trace(" | Trying recursive via "+fint.toString()); return convertFormat(AudioSystem.getAudioInputStream(fint,sin),fint,fout); } } } }