All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jm.audio.Audio Maven / Gradle / Ivy

The newest version!
/*



Copyright (C) 2000 Andrew Sorensen & Andrew Brown

This program 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 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 General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/
package jm.audio;

import jm.audio.io.SampleOut;
import jm.music.data.Note;
import jm.music.data.Part;
import jm.music.data.Phrase;
import jm.music.data.Score;

import java.io.*;
import java.util.Enumeration;
import java.util.Stack;

/**
 * The Audio class provides a number of static methods to help pass
 * a jmusic score to the audio architecture and for putting a notes
 * sample information into the correct location in a global audio file.

* WARNING !!!!!!! * This class is an absolute disgrace ;) It works but is very ugly * and I can't be bothered to clean it up at the moment. If anyone feels like * cleaning it up go for it ;) * * @author Andrew Sorensen * @version 1.0, Sun Feb 25 18:42:43 2001 */ public final class Audio implements jm.JMC { /** * Do we want to write the jpf file */ private static boolean JPF = false; //Provided so that I can set the number of channels in the addEmUp method private static int channels; private static int sampleRate; /** * Makes an array which contains all the notes from all the phrases * from all the instruments etc. solely based on start times. * This method also writes a jpf file which is a text file containing * the names of all the notes corresponding audio files with their * start times and lengths. * * @param score the score to take data from */ public static void processScore(Score score, Instrument[] instList, String fileName) { Stack inst = new Stack(); // add an instrument to avoid errors from no instrument assignment by user inst.push(instList[0]); for (int i = 0; i < instList.length; i++) { if (instList[i] != null) { if (!instList[i].getInitialised()) { try { if (instList[i].getInitialised() == false) { instList[i].createChain(); instList[i].setInitialised(true); } } catch (AOException e) { e.printStackTrace(); } } } } Enumeration enum1 = score.getPartList().elements(); //set score tempo double score_ratio = 60.0 / score.getTempo(); int partCounter = 0; /* Enumerate through all parts */ while (enum1.hasMoreElements()) { Part part = (Part) enum1.nextElement(); //set part tempo double part_ratio = score_ratio; if (part.getTempo() > 0.0) part_ratio = 60.0 / part.getTempo(); /* Get the instrument being used for this part */ if (part.getInstrument() != NO_INSTRUMENT) { try { inst.push(instList[part.getInstrument()]); } catch (ArrayIndexOutOfBoundsException npe) { System.out.println("jMusic Audio warning: Can't find the instrument number " + part.getInstrument() + " that you have specified for " + "the part named " + part.getTitle() + "."); } } System.out.println("Part " + partCounter++ + " '" + part.getTitle() + "'. "); /* Enumerate through all phrases */ Enumeration enum2 = part.getPhraseList().elements(); int phraseCounter = 0; while (enum2.hasMoreElements()) { Phrase phr = (Phrase) enum2.nextElement(); //get phrase tempo double phrase_ratio = part_ratio; if (phr.getTempo() > 0.0) { System.out.println("A: " + phrase_ratio); phrase_ratio = 60.0 / phr.getTempo(); System.out.println("B: " + phrase_ratio); } /* Get the instrument being used for this phrase */ if (phr.getInstrument() != NO_INSTRUMENT) { try { // add phrase instrument to stack inst.push(instList[phr.getInstrument()]); } catch (ArrayIndexOutOfBoundsException npe) { System.out.println("jMusic Audio warning: Can't find the instrument number " + phr.getInstrument() + " that you have specified for" + " the phrase named " + phr.getTitle() + "."); } } double time = part_ratio * phr.getStartTime(); //start time of phrase double ntime = 0.0; //notes distance from phrases start time Enumeration enum3 = phr.getNoteList().elements(); System.out.print(" Phrase " + phraseCounter++ + " '" + phr.getTitle() + "'" + " starting at beat " + phr.getStartTime() + ": "); /* Enumerate through all notes */ int phraseNoteCounter = 0; while (enum3.hasMoreElements()) { Note note = (Note) enum3.nextElement(); if (note.getFrequency() == (double) REST) { //This a rest ??? ntime += phrase_ratio * note.getRhythmValue(); continue; } phraseNoteCounter++; if (phraseNoteCounter % 10 == 0) { System.out.print(phraseNoteCounter); } else System.out.print("."); Note new_note = note.copy(); //System.out.println("new note pitch = " + new_note.getPitch()); new_note.setDuration(phrase_ratio * note.getDuration()); new_note.setRhythmValue(phrase_ratio * note.getRhythmValue()); Instrument currInst = (Instrument) inst.peek(); currInst.setBlock(false); currInst.setFinished(true); currInst.renderNote(new_note, ((double) time + ntime)); currInst.setFinished(false); currInst.iterateChain(); ntime += phrase_ratio * note.getRhythmValue(); } System.out.println(); // remove phrase instrument from stack if (phr.getInstrument() != NO_INSTRUMENT) inst.pop(); } } } /** * Combine converts the floating point audio file and combines them into an integer file. */ public static void combine(String fileJmp, String tmpFile, String fileOut, boolean deleteFiles, boolean multi) { if (multi) { Audio.sampleRate = SampleOut.samprate; Audio.channels = SampleOut.numofchan; System.out.println("Bit Depth: 16" + " Sample rate: " + SampleOut.samprate + " Channels: " + SampleOut.numofchan); Audio.addEmUp(tmpFile, fileOut, SampleOut.max); return; } else { int numofdot = 1; //For print outs only float max = (float) 0.0; //the largest sample value try { FileReader fr = new FileReader(fileJmp); StreamTokenizer st = new StreamTokenizer(fr); RandomAccessFile raf = new RandomAccessFile(tmpFile, "rw"); double time1 = System.currentTimeMillis(); for (; ; ) { try { st.nextToken(); String fileName = st.sval; if (fileName == null) { //No more tokens break; } st.nextToken(); long position = (long) (st.nval * 4); st.nextToken(); int length = (int) st.nval; float res = getAudio(fileName, position, length, max, raf); if (max < res) { max = res; System.out.println("Max is smaller: " + max); } if (res < 0 && max < (res * (float) -1.0)) { max = (res * (float) -1.0); System.out.println("MAX is bigger: " + max); } /* if(deleteFiles){ if(DEBUG)System.out.println("Deleting " + fileName); File fl = new File(fileName); fl.delete(); } */ if ((numofdot % 10) == 0) { if (VERBOSE) System.out.print(numofdot); } else { if (VERBOSE) System.out.print("."); } numofdot++; // close random access file raf.close(); } catch (EOFException eof) { //This is expected break; } catch (IOException ioe) { ioe.printStackTrace(); } } System.out.print("\n"); double time2 = System.currentTimeMillis(); System.out.println("Created tmp file in " + (((time2 - time1)) / 1000.0) + " seconds"); double now = System.currentTimeMillis(); //addEmUp(raf, fileOut, max); addEmUp(tmpFile, fileOut, max); double now2 = System.currentTimeMillis(); System.out.println("Mixed to a single file in " + (((now2 - now)) / 1000.0) + " seconds"); if (deleteFiles) { File jmp = new File(fileJmp); File tpm = new File(tmpFile); jmp.delete(); tpm.delete(); } } catch (IOException ioe) { ioe.printStackTrace(); } } } private static float getAudio(String fileName, long position, int length, float max, RandomAccessFile raf) { FileInputStream fis = null; BufferedInputStream bis = null; DataInputStream dis = null; try { fis = new FileInputStream(fileName); bis = new BufferedInputStream(fis, 4096); dis = new DataInputStream(bis); //Read the files header if (dis.readInt() != 0x2E736E64) { System.out.println("jMusic SampleIn warning: This file is NOT in the .au/.snd file format"); return max; } int offset = dis.readInt(); int numOfBytes = dis.readInt(); int format = dis.readInt(); Audio.sampleRate = dis.readInt(); Audio.channels = dis.readInt(); fis.skip(offset - 24); //skip the rest of the header //adjust position and length for multiple channels position *= (long) channels; length *= channels; } catch (IOException ioe) { ioe.printStackTrace(); } for (; ; ) { try { raf.seek(position); //read in and convert to sample float sample = (float) ((float) dis.readShort() / (float) 32767); try {//if we can read from the file float d = raf.readFloat(); raf.seek(position); position += 4; float tmp = d + sample; if (max < tmp) { max = tmp; System.out.println("MAX small: " + max); } if (tmp < 0 && max < (tmp * (float) -1.0)) { max = (tmp * (float) -1.0); System.out.println("MAX large: " + max); } raf.writeFloat(tmp); } catch (EOFException eofe) { //This means that there is nothing to read so we can happily write if (max < sample) max = sample; if (sample < 0 && max < (sample * (float) -1.0)) { max = (sample * (float) -1.0); } raf.writeFloat(sample); position += 4; } } catch (EOFException eofe) { //we've run out of samples to read break; } catch (IOException ioe) { ioe.printStackTrace(); } } try { dis.close(); fis.close(); } catch (IOException ioe) { ioe.printStackTrace(); } return max; } public static void addEmUp(String tmpFileName, String fileName, float max) { if (VERBOSE) { System.out.println("MAX amplitude: " + max); System.out.println("Writing .au/.snd file '" + fileName + "' please wait..."); } try { FileOutputStream fos = new FileOutputStream(fileName); BufferedOutputStream bos = new BufferedOutputStream(fos, 4096); DataOutputStream dos = new DataOutputStream(bos); File tmpF = new File(tmpFileName); FileInputStream fin = new FileInputStream(tmpF); BufferedInputStream bin = new BufferedInputStream(fin, 4096); DataInputStream dis = new DataInputStream(bin); int offset = 28; // Modified FP nov 2004 int numOfBytes = 0; //int numOfBytes = ((int)tmpF.length()/2)+16; int format = 3;//6; //write header dos.writeInt(0x2E736E64); // .snd dos.writeInt(offset); //offset from the beginning or the file dos.writeInt(numOfBytes); //num of bytes in file (after this) dos.writeInt(format); //compression format dos.writeInt(Audio.sampleRate); //sampling rate dos.writeInt(Audio.channels); //num of channels dos.writeInt((short) 0); //add some padding //put RandomAccessFile back to the start //raf.seek(0); double tt = System.currentTimeMillis(); try { for (; ; ) { float samp = dis.readFloat(); float outgoing = samp / max; if (outgoing < (float) -1.0 || outgoing > (float) 1.0) { System.out.println("Outgoing= " + outgoing + " SAMPLE: " + samp + " MAX: " + max + " SampleOut.max: " + SampleOut.max); } //dos.writeFloat(outgoing); dos.writeShort((short) (outgoing * 32767)); numOfBytes += 2; //System.out.println((short)(dis.readFloat()/max)*32767); } } catch (EOFException eofe) { //expected double ttt = System.currentTimeMillis(); System.out.println("Finished writing the audio file in " + (((ttt - tt)) / 1000.0) + " seconds"); dos.flush(); fos.flush(); bos.flush(); dos.close(); fos.close(); bos.close(); fin.close(); bin.close(); dis.close(); tmpF.delete(); // Thanks to Francois Pinot for this work around if (tmpF.exists()) { // set to empty (to avoid subsequent overlaying) RandomAccessFile raf = new RandomAccessFile(tmpFileName, "rw"); raf.setLength(0); raf.close(); } // Added FP nov 2004 RandomAccessFile auxraf = new RandomAccessFile(fileName, "rw"); auxraf.seek(8); auxraf.writeInt(numOfBytes); auxraf.close(); // End added FP nov 2004 return; } catch (IOException ioe) { ioe.printStackTrace(); } } catch (IOException ioe) { ioe.printStackTrace(); System.out.println(ioe); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy