
jm.util.Read Maven / Gradle / Ivy
Show all versions of jmusic Show documentation
/*
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.util;
import jm.JMC;
import jm.audio.io.AudioFileIn;
import jm.midi.SMF;
import jm.music.data.CPhrase;
import jm.music.data.Part;
import jm.music.data.Phrase;
import jm.music.data.Score;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.*;
/**
* Reads data files and stores the musical information in the supplied Score.
*
* @author Unascribed, Adam Kirby
* @version 0.0.0.1, 27th February 2001
*/
public class Read implements JMC {
/**
* Not meant to be instantiated, only provides static members
*/
protected Read() {
}
//----------------------------------------------
// MIDI
//----------------------------------------------
/**
* Import to a jMusic score a standard MIDI file
* Assume the MIDI file name is the same as the score title with .mid appended
* prompt for a fileName
*
* @param Score
*/
public static void midi(Score score) {
FileDialog fd = new FileDialog(new Frame(),
"Select a MIDI file to open.",
FileDialog.LOAD);
fd.show();
if (fd.getFile() != null) {
Read.midi(score, fd.getDirectory() + fd.getFile());
}
}
/**
* Import to a jMusic score a standard MIDI file
*
* @param Score
* @param String fileName
*/
public static void midi(Score s, String fileName) {
if (s == null) {
System.err.println("jMusic Read.midi error: The score is not initialised! I'm doing it for you.");
s = new Score();
}
s.empty();
SMF smf = new SMF();
smf.setVerbose(true);
try {
System.out.println("--------------------- Reading MIDI File ---------------------");
InputStream is = new FileInputStream(fileName);
smf.read(is);
jm.midi.MidiParser.SMFToScore(s, smf);
System.out.println("MIDI file '" + fileName + "' read into score '" + s.getTitle() + "' Tempo = " + s.getTempo());
System.out.println("-------------------------------------------------------------");
} catch (IOException e) {
System.err.println(e);
}
}
/**
* Read the first track from a standard MIDI file into a jMusic part
*
* @param Part
*/
public static void midi(Part p) {
Score s = new Score();
midi(s);
p = s.getPart(0);
}
/**
* Read the first track from a standard MIDI file into a jMusic part
*
* @param Part
* @param String fileName
*/
public static void midi(Part p, String fileName) {
Score s = new Score();
midi(s, fileName);
p = s.getPart(0);
}
/**
* Read the first phrase of the first track from a standard MIDI file
* into a jMusic phrase
*
* @param Phrase
*/
public static void midi(Phrase phr) {
Score s = new Score();
midi(s);
phr = s.getPart(0).getPhrase(0);
}
/**
* Read the first phrase of the first track from a standard MIDI file
* into a jMusic phrase
*
* @param Phrase
* @param String fileName
*/
public static void midi(Phrase phr, String fileName) {
Part p = new Part();
midi(p, fileName);
phr = p.getPhrase(0);
}
/**
* Read the first track from a standard MIDI file into a jMusic cphrase
*
* @param Part
* @param String fileName
*/
public static void midi(CPhrase cphr, String fileName) {
Score s = new Score();
midi(s, fileName);
Part p = new Part();
p = s.getPart(0);
for (int i = 0; i < p.size(); i++) {
cphr.addPhrase(p.getPhrase(i));
}
}
//----------------------------------------------
// jm
//----------------------------------------------
/**
* Import the jm file as a jMusic score
* Use the score title as a the fileName
*
* @param Score
*/
public static void jm(Score s) {
jm(s, s.getTitle() + ".jm");
}
/**
* Import the jm file as a jMusic score
*
* @param Score
* @param String fileName
*/
public static void jm(Score s, String fileName) {
if (s == null) {
System.err.println("jMusic Read.jm error: The score is not initialised! I'm doing it for you.");
s = new Score();
}
s.empty();
try {
System.out.println("--------------------- Reading .jm File ---------------------");
InputStream is = new FileInputStream(fileName);
ObjectInputStream ois = new ObjectInputStream(is);
try {
s.addPartList(((Score) ois.readObject()).getPartArray());
System.out.println("reading");
} catch (ClassNotFoundException e) {
System.err.println(e);
}
System.out.println("jm file '" + fileName + "' read into score '" + s.getTitle() + "'");
System.out.println("-------------------------------------------------------------");
} catch (IOException e) {
System.err.println(e);
}
}
/**
* Read the first part from a jm file into a jMusic part
*
* @param Part
* @param String fileName
*/
public static void jm(Part p, String fileName) {
if (p == null) {
System.err.println("jMusic Read.jm error: The part is not initialised! I'm doing it for you.");
p = new Part();
}
p.empty();
Score s = new Score();
jm(s, fileName);
p.addPhraseList(s.getPart(0).getPhraseArray());
}
/**
* Read the first phrase of the first part from jm file
* into a jMusic phrase
*
* @param Phrase
* @param String fileName
*/
public static void jm(Phrase phr, String fileName) {
if (phr == null) {
System.err.println("jMusic Read.jm error: The phrase is not initialised! I'm doing it for you.");
phr = new Phrase();
}
phr.empty();
Part p = new Part();
jm(p, fileName);
phr.addNoteList(p.getPhrase(0).getNoteArray());
}
/**
* Read the first part from a jm file into a jMusic cphrase
*
* @param Part
* @param String fileName
*/
public static void jm(CPhrase cphr, String fileName) {
if (cphr == null) {
System.err.println("jMusic Read.jm error: The CPhrase is not initialised! I'm doing it for you.");
cphr = new CPhrase();
}
cphr.empty();
Score s = new Score();
jm(s, fileName);
Part p = new Part();
p = s.getPart(0);
for (int i = 0; i < p.size(); i++) {
cphr.addPhrase(p.getPhrase(i));
}
}
//----------------------------------------------
// XML
//----------------------------------------------
/**
* Import the xml file as a jMusic score.
* Prompt for a fileName
*
* @param Score
*/
public static void xml(Score score) {
FileDialog fd = new FileDialog(new Frame(),
"Select a jMusic XML file to open.",
FileDialog.LOAD);
fd.show();
if (fd.getFile() != null) {
Read.xml(score, fd.getDirectory() + fd.getFile());
}
}
/**
* Import the xml file as a jMusic score
*
* @param Score
* @param String fileName
*/
public static void xml(Score s, String fileName) {
if (s == null) {
System.err.println("jMusic Read.xml error: The score is not initialised! I'm doing it for you.");
s = new Score();
}
s.empty();
try {
System.out.println("--------------------- Reading .xml File ---------------------");
BufferedReader br = new BufferedReader(new FileReader(fileName));
try {
s.addPartList(XMLParser.xmlStringToScore(br.readLine()).getPartArray());
System.out.println("reading");
} catch (ConversionException e) {
System.err.println(e);
}
System.out.println("xml file '" + fileName + "' read into score '" + s.getTitle() + "'");
System.out.println("-------------------------------------------------------------");
} catch (IOException e) {
System.err.println(e);
}
}
/**
* Read the first part from a xml file into a jMusic part
*
* @param Part
* @param String fileName
*/
public static void xml(Part p, String fileName) {
if (p == null) {
System.err.println("jMusic Read.xml error: The part is not initialised! I'm doing it for you.");
p = new Part();
}
p.empty();
Score s = new Score();
xml(s, fileName);
p.addPhraseList(s.getPart(0).getPhraseArray());
}
/**
* Read the first phrase of the first part from xml file
* into a jMusic phrase
*
* @param Phrase
* @param String fileName
*/
public static void xml(Phrase phr, String fileName) {
if (phr == null) {
System.err.println("jMusic Read.xml error: The phrase is not initialised! I'm doing it for you.");
phr = new Phrase();
}
phr.empty();
Part p = new Part();
xml(p, fileName);
phr.addNoteList(p.getPhrase(0).getNoteArray());
}
/**
* Read the first part from a xml file into a jMusic cphrase
*
* @param Part
* @param String fileName
*/
public static void xml(CPhrase cphr, String fileName) {
if (cphr == null) {
System.err.println("jMusic Read.xml error: The CPhrase is not initialised! I'm doing it for you.");
cphr = new CPhrase();
}
cphr.empty();
Score s = new Score();
xml(s, fileName);
Part p = new Part();
p = s.getPart(0);
for (int i = 0; i < p.size(); i++) {
cphr.addPhrase(p.getPhrase(i));
}
}
//----------------------------------------------
// Audio
//----------------------------------------------
public static float[] audio(String fileName) {
System.out.println("-------------------- Reading Audio File ---------------------");
AudioFileIn afi = new AudioFileIn(fileName);
float[] sampleData = afi.getSampleData();
System.out.println("File '" + fileName + "' read in. Details:");
System.out.println("Channels = " + afi.getChannels()
+ " Samples per channel = " + afi.getDuration() / afi.getChannels()
+ " Sample rate = " + afi.getSampleRate()
+ " Bit depth = " + afi.getSampleBitDepth());
System.out.println("-------------------------------------------------------------");
return sampleData;
}
public static void audio(float[] sampleData, String fileName) {
System.out.println("-------------------- Reading Audio File ---------------------");
AudioFileIn afi = new AudioFileIn(fileName);
sampleData = afi.getSampleData();
System.out.println("Audio file '" + fileName + "' read in. Details:");
System.out.println("Channels = " + afi.getChannels()
+ " Samples per channel = " + afi.getDuration() / afi.getChannels()
+ " Sample rate = " + afi.getSampleRate()
+ " Bit depth = " + afi.getSampleBitDepth());
System.out.println("-------------------------------------------------------------");
}
//--------- Simultaneous midi and jm reading with error messaging --------//
/**
* Returns a Score read from a MIDI or JM file, without displaying error
* messages.
*
* @param file File to read
* @return Score read from file, or null if an error occured
* @see #midiOrJmWithNoMessaging(String, String)
*/
public static Score midiOrJmWithNoMessaging(final File file) {
return new JmMidiProcessor(file).getScore();
}
/**
* Returns a Score read from a MIDI or JM file, without displaying error
* messages.
*
* The path of the file is separated into directory
and
* filename
so that the latter can be used as the title of the
* score. If directory
is null then this method attempts
* to read the file specified by filename
.
*
* @param directory String describing the directory structure of the file to
* be read, which must include the terminating separator
* @param filename String describing the file name
* @return Score read from file, or null if an error occured
* @see #midiOrJmWithNoMessaging(File)
*/
public static Score midiOrJmWithNoMessaging(final String directory,
final String filename) {
return new JmMidiProcessor(directory, filename).getScore();
}
/**
* Returns a Score read from a MIDI or JM file, displaying errors in a
* {@link Dialog}.
*
* @param file File to read
* @param owner Frame whose control is to be suspended while the error
* messages are displayed
* @return Score read from file, or null if an error occured
* @see #midiOrJmWithAWTMessaging(String, String, Frame)
*/
public static Score midiOrJmWithAWTMessaging(final File file,
final Frame owner) {
JmMidiProcessor processor = new JmMidiProcessor(file);
displayErrorDialog(owner, processor.getMessage());
return processor.getScore();
}
/**
* Returns a Score read from a MIDI or JM file, displaying errors in a
* {@link Dialog}.
*
* The path of the file is separated into directory
and
* filename
so that the latter can be used as the title of the
* score. If directory
is null then this method attempts
* to read the file specified by filename
.
*
* @param directory String describing the directory structure of the file to
* be read, which must include the terminating separator
* @param filename String describing the file name
* @param owner Frame whose control is to be suspended while the error
* messages are displayed
* @return Score read from file, or null if an error occured
* @see #midiOrJmWithAWTMessaging(File, Frame)
*/
public static Score midiOrJmWithAWTMessaging(final String directory,
final String filename,
final Frame owner) {
JmMidiProcessor processor = new JmMidiProcessor(directory, filename);
displayErrorDialog(owner, processor.getMessage());
return processor.getScore();
}
/**
* Displays an error message in a {@link Dialog}. The message displayed is
* retrieved from the class variable {@link #message}. This method is
* designed for use by the {@link #midiOrWithAWTMessaging()} methods.
*
* This method is for Dialogs whose control is to be taken from a Frame.
* If the owner is a Dialog use {@link #displayErrorDialog(Dialog)} instead.
*
* @param owner Frame whose control is to be suspended while the error
* messages are displayed
* @param message String to be displayed
* @see displayErrorDialog(Frame)
* @see #midiOrJmWithAWTMessaging(File, Dialog);
* @see #midiOrJmWithAWTMessaging(String, String, Dialog);
*/
private static void displayErrorDialog(final Frame owner,
final String message) {
if (message == null) {
return;
}
Dialog dialog = new Dialog(owner, "Not a valid MIDI or jMusic File",
true);
completeErrorDialog(dialog, message);
}
/**
* Adds supplementary components to the error dialog and displays it. This
* method is executed by both {@link displayErrorDialog(Frame)} and {@link
* dispayedErrorDialog(Dialog)} and stores the code common to both.
*
* @param dialog Dialog that is to display the error message.
* @param message String to be displayed
*/
private static void completeErrorDialog(final Dialog dialog,
final String message) {
dialog.add(new Label(message), BorderLayout.CENTER);
Button okButton = new Button("OK");
okButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
dialog.dispose();
}
}
);
Panel buttonPanel = new Panel();
buttonPanel.add(okButton);
dialog.add(buttonPanel, BorderLayout.SOUTH);
dialog.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
dialog.dispose();
}
}
);
dialog.pack();
dialog.show();
}
/**
* Returns a Score read from a MIDI or JM file, displaying errors in a
* {@link javax.swing.JDialog}.
*
* @param file File to read
* @param owner Component whose control is to be suspended while the error
* messages are displayed
* @return Score read from file, or null if an error occured
* @see #midiOrJmWithSwingMessaging(String, String, Component)
*/
public static Score midiOrJmWithSwingMessaging(final File file,
final Component owner) {
JmMidiProcessor processor = new JmMidiProcessor(file);
displayErrorJDialog(owner, processor.getMessage());
return processor.getScore();
}
//--------- Simultaneous midi and jm reading with error messaging --------//
/**
* Returns a Score read from a MIDI or JM file, displaying errors in a
* {@link javax.swing.JDialog}.
*
* The path of the file is separated into directory
and
* filename
so that the latter can be used as the title of the
* score. If directory
is null then this method attempts
* to read the file specified by filename
.
*
* @param directory String describing the directory structure of the file to
* be read, which must include the terminating separator
* @param filename String describing the file name
* @param owner Component whose control is to be suspended while the
* error messages are displayed
* @return Score read from file, or null if an error occured
* @see #midiOrJmWithSwingMessaging(File, Component)
*/
public static Score midiOrJmWithSwingMessaging(final String directory,
final String filename,
final Component owner) {
JmMidiProcessor processor = new JmMidiProcessor(directory, filename);
displayErrorJDialog(owner, processor.getMessage());
return processor.getScore();
}
/**
* Displays an error message in a {@link javax.swing.JDialog}. The message displayed is
* retrieved from the class variable {@link #message}. This method is
* designed for use by the {@link #midiOrWithSwingMessaging()} methods.
*
* @param owner Component whose control is to be suspended while the
* error messages are displayed
* @param message String to display
* @see #midiOrJmWithSwingMessaging(File, Component);
* @see #midiOrJmWithSwingMessaging(String, String, Component);
*/
private static void displayErrorJDialog(final Component owner,
final String message) {
if (message == null) {
return;
}
JOptionPane.showMessageDialog(owner, message,
"Not a valid MIDI or jMusic File",
JOptionPane.ERROR_MESSAGE);
}
/**
* Handles methods common to the main static methods.
*/
protected static class JmMidiProcessor {
/**
* Error message to display, any method who alters this field should be
* syncrhronized.
*/
private String message = null;
/**
* Score describing the musical information extracted from the file.
*/
private Score score = new Score();
/**
* Creates a new processor for reading jm and midi information from a
* specified File.
*
* @param file File storing the musical information
*/
public JmMidiProcessor(final File file) {
if (file == null) {
message = "The selected file is null. No JM/MIDI information "
+ "could be imported.";
score = null;
} else if (file.isDirectory()) {
message = "The selected file is a directory. No JM/MIDI "
+ "information could be imported.";
score = null;
} else {
JmMidiProcessor processor = new JmMidiProcessor(
file.getParent() + file.separator, file.getName());
message = processor.getMessage();
score = processor.getScore();
}
}
/**
* Creates a new processor for reading jm and midi information from the
* specified directory and file Strings.
*
* @param directory String describing the path of the directory, this
* must be terminated with a file separator.
* @param filename String describing the name of the file to be read
*/
public JmMidiProcessor(final String directory, final String filename) {
if (filename == null) {
message = "The filename String is null. No JM/MIDI information"
+ " could be imported.";
score = null;
return;
}
/** Attempt to read file */
try {
score.setTitle(filename);
SMF smf = new SMF();
if (directory == null) {
InputStream is = new FileInputStream(filename);
smf.read(is);
jm.midi.MidiParser.SMFToScore(score, smf);
} else {
InputStream is = new FileInputStream(directory + filename);
smf.read(is);
jm.midi.MidiParser.SMFToScore(score, smf);
}
} catch (IOException e1) {
message = e1.getMessage();
if (message == null) {
message = "Unknown IO Exception";
score = null;
return;
} else if (message.equals("Track Started in wrong place!!!!"
+ " ABORTING")) {
message = "The MIDI file corrupted. Track data started in "
+ "the wrong place.";
score = null;
return;
} else if (message.equals("This is NOT a MIDI file !!!")) {
try {
FileInputStream fis = new FileInputStream(directory
+ filename);
ObjectInputStream ois = new ObjectInputStream(fis);
score = (Score) ois.readObject();
ois.close();
fis.close();
} catch (SecurityException e2) {
message = "Read access not allowed to " + filename;
score = null;
return;
} catch (ClassNotFoundException e2) {
message = "The file " + filename
+ " is neither a jm nor a MIDI file";
score = null;
return;
} catch (ClassCastException e2) {
message = "The file " + filename
+ " is neither a jm nor a MIDI file";
score = null;
return;
} catch (StreamCorruptedException e2) {
message = "The file " + filename
+ " is neither a jm nor a MIDI file";
score = null;
return;
} catch (IOException e2) {
message = e2.getMessage();
if (message == null) {
message = "Unknown Exception. No musical "
+ "information could be imported.";
}
score = null;
return;
}
} else {
score = null;
return;
}
}
}
/**
* Returns the score extracted from the file.
*
* @return score read, or null if an error occured
*/
public Score getScore() {
return score;
}
/**
* Returns the error message.
*
* @return description of error, or null if no error occured
*/
public String getMessage() {
return message;
}
}
}