Reputation: 1
import java.io.File;
import java.io.IOException;
import java.util.Scanner;
import javax.sound.sampled.*;
public class Main{
static File [] arr= new File[100];
static String[] arrNote = new String[100];
public void play(File filename)throws UnsupportedAudioFileException, IOException,InterruptedException,
LineUnavailableException{
AudioInputStream audioStream = AudioSystem.getAudioInputStream(filename);
Clip clip = AudioSystem.getClip();
clip.open(audioStream);
clip.start();
Thread.sleep(500);
clip.close();
}
public static void main(String[]args) throws UnsupportedAudioFileException, IOException,InterruptedException,
LineUnavailableException{
Scanner scanner = new Scanner(System.in);
String response = "";
Main a = new Main();
int numItems = 0;
System.out.println("Store music notes, type in Alphabate + number for example(E3) for the music note you want to store in the array, type Q when finished");
while(!response.equals("Q")){
response = scanner.next();
response.toUpperCase();
switch(response){
case("B3"):
arr[numItems] = new File("C:\\Users\\westg\\OneDrive\\Desktop\\piano.wav\\B3.wav");
arrNote[numItems] = "B3";
numItems++;
break;
case("C3"):
arr[numItems] = new File("C:\\Users\\westg\\OneDrive\\Desktop\\piano.wav\\C3.wav");
arrNote[numItems] = "C3";
numItems++;
break;
case("D3"):
arr[numItems] = new File("C:\\Users\\westg\\OneDrive\\Desktop\\piano.wav\\D3.wav");
arrNote[numItems] = "D3";
numItems++;
break;
case("E3"):
arr[numItems] = new File("C:\\Users\\westg\\OneDrive\\Desktop\\piano.wav\\E3.wav");
arrNote[numItems] = "E3";
numItems++;
break;
case("F3"):
arr[numItems] = new File("C:\\Users\\westg\\OneDrive\\Desktop\\piano.wav\\F3.wav");
arrNote[numItems] = "F3";
numItems++;
break;
case("Q"):
break;
default: System.out.println("Not a valid response");
}
}
System.out.println("Your music note sequence: ");
for (int x = 0; x < numItems; x ++){
System.out.print(x + 1 + "." + arrNote[x] + " ");
}
System.out.println("If you want to play your music, click any key to continue");
response = scanner.next();
while(!response.equals("Q")){
System.out.println("P = play, S = Stop, R= Reset, Q = Quit");
System.out.print("Enter your choice: ");
response = scanner.next();
response = response.toUpperCase();
switch (response) {
case("P"):
for (int i = 0; i < numItems; i++){
a.play(arr[i]);
}
default: System.out.println("Not a valid response");
}
System.out.println("Bye");
}
}
}
this is the code I used to play different piano note wav files one by one to create a music, but when I make the Thread.sleep less than 1000, the music note will jam up, it will skipped or play some notes together, is there anyway I can play these files one by one in order, or is there other way I can use to create a music editor that allows me to combine different music notes together to play songs using java?`enter code here.
Upvotes: 0
Views: 44
Reputation: 347314
So, you're basic problem is, you're closing the clip before it's either had a chance to play or play completely.
Rather than relying on Thread.sleep
, which won't take into account the variable nature of the playback (ie the source clips been different lengths or the sound system needing more time) you should be trying to use a more imperial measurement.
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineEvent;
import javax.sound.sampled.LineListener;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
public class Test {
public static void main(String[] args) {
new Test();
}
public enum Note {
A3_MINOR(Note.class.getResource("/notes/a-3.wav")),
A4_MINOR(Note.class.getResource("/notes/a-4.wav")),
A5_MINOR(Note.class.getResource("/notes/a-5.wav")),
A3(Note.class.getResource("/notes/a3.wav")),
A4(Note.class.getResource("/notes/a4.wav")),
A5(Note.class.getResource("/notes/a5.wav")),
B3(Note.class.getResource("/notes/b3.wav")),
B4(Note.class.getResource("/notes/b4.wav")),
B5(Note.class.getResource("/notes/b5.wav")),
C3_MINOR(Note.class.getResource("/notes/c-3.wav")),
C4_MINOR(Note.class.getResource("/notes/c-4.wav")),
C5_MINOR(Note.class.getResource("/notes/c-5.wav")),
C3(Note.class.getResource("/notes/c3.wav")),
C4(Note.class.getResource("/notes/c4.wav")),
C5(Note.class.getResource("/notes/c5.wav")),
D3_MINOR(Note.class.getResource("/notes/d-3.wav")),
D4_MINOR(Note.class.getResource("/notes/d-4.wav")),
D5_MINOR(Note.class.getResource("/notes/d-5.wav")),
D3(Note.class.getResource("/notes/d3.wav")),
D4(Note.class.getResource("/notes/d4.wav")),
D5(Note.class.getResource("/notes/d5.wav")),
E3(Note.class.getResource("/notes/e3.wav")),
E4(Note.class.getResource("/notes/e4.wav")),
E5(Note.class.getResource("/notes/e5.wav")),
F3_MINOR(Note.class.getResource("/notes/f-3.wav")),
F4_MINOR(Note.class.getResource("/notes/f-4.wav")),
F5_MINOR(Note.class.getResource("/notes/f-5.wav")),
F3(Note.class.getResource("/notes/f3.wav")),
F4(Note.class.getResource("/notes/f4.wav")),
F5(Note.class.getResource("/notes/f5.wav")),
G3_MINOR(Note.class.getResource("/notes/g-3.wav")),
G4_MINOR(Note.class.getResource("/notes/g-4.wav")),
G5_MINOR(Note.class.getResource("/notes/g-5.wav")),
G3(Note.class.getResource("/notes/g3.wav")),
G4(Note.class.getResource("/notes/g4.wav")),
G5(Note.class.getResource("/notes/g5.wav")),;
private URL source;
private Note(URL source) {
this.source = source;
}
public URL getSource() {
return source;
}
}
public Test() {
List<Note> notes = new ArrayList<>(16);
notes.add(Note.A3_MINOR);
notes.add(Note.A4_MINOR);
notes.add(Note.A5_MINOR);
notes.add(Note.A3);
notes.add(Note.A4);
notes.add(Note.A5);
play(notes);
}
protected void play(List<Note> notes) {
for (Note note : notes) {
System.out.println("Play " + note + "; " + note.getSource());
try {
AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(note.getSource());
Clip clip = AudioSystem.getClip();
clip.open(audioInputStream);
clip.start();
clip.drain();
} catch (UnsupportedAudioFileException | IOException | LineUnavailableException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
}
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
Now, if you run this, you'll find one particular problem. They "seem" to all play at once (like smashing you hands on the keyboard) ... not pretty.
So, instead, we need to know more information, specifically, when the clip actually completes.
So, I added a LineListener
to the Clip
and used a ReentrantLock
to "wait" till the clip had "stopped", for example...
protected void play(List<Note> notes) {
ReentrantLock waitLock = new ReentrantLock();
Condition waitCondition = waitLock.newCondition();
for (Note note : notes) {
System.out.println("Play " + note + "; " + note.getSource());
try {
AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(note.getSource());
Clip clip = AudioSystem.getClip();
clip.addLineListener(new LineListener() {
@Override
public void update(LineEvent event) {
if (event.getType().equals(LineEvent.Type.STOP)) {
waitLock.lock();
try {
waitCondition.signal();
} finally {
waitLock.unlock();
}
}
}
});
clip.open(audioInputStream);
clip.start();
clip.drain();
waitLock.lock();
try {
waitCondition.await();
} catch (InterruptedException ex) {
//Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
} finally {
waitLock.unlock();
}
clip.close();
} catch (UnsupportedAudioFileException | IOException | LineUnavailableException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
}
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
}
This ensures that each note is played immediately after the last note has completed.
Now, if you prefer to have a little "overlap" of the notes, then simply, don't close
the clip, let it play.
protected void play(List<Note> notes) {
ReentrantLock waitLock = new ReentrantLock();
Condition waitCondition = waitLock.newCondition();
for (Note note : notes) {
System.out.println("Play " + note + "; " + note.getSource());
try {
AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(note.getSource());
Clip clip = AudioSystem.getClip();
clip.open(audioInputStream);
clip.start();
clip.drain();
Thread.sleep(125);
} catch (UnsupportedAudioFileException | IOException | LineUnavailableException | InterruptedException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
}
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
}
If needed, you could use the LineListener
to close
the clip instead
nb: I sourced my note files from https://sound.stackexchange.com/questions/22769/are-there-free-records-of-separate-piano-notes-in-wav-files-for-instance, specifically, http://www.mediafire.com/download/zp8brp1f6q777b1/Midi_Notes.rar and http://www.mediafire.com/download/zd1mqtazulgv28a/mp3_Notes.rar. I used the MP3 files and converted them to wav files
Upvotes: 2