Playing random pairs of words in Sound Arrays - java

My goal is to play doublets (pairs) of the phrase "This is a test", which is a WAV audio file. So far I succeeded in generating a random sequence of the phrase, such as "Test is this a", but I need to make it so that it only speaks in pairs, so "This is"... "Is a"... with a 100 m.second pause between each word and a 400 m.second pause between each pair. This is what I have thus far...
public void playDoublets(int numDoublets) throws InterruptedException {
ArrayList<Sound> list = new ArrayList();
for (int i =0; i < numWords; i++){
list.add(new Sound(myWordArray[i]));
}
Collections.shuffle(list);
for (int i = 0; i < numWords; i++){
list.get(i).blockingPlay();
Thread.sleep(400);
}
}
numDoublets is how many pairs the program plays, but I do not know where I would implement it in the code above. All this code does so far is just print out all 4 words, but not in pairs.

You should explicitly represent a pause in your list of sounds you want to play. Use an interface to generically handle both normal sounds and pauses.
import java.util.*;
public class DoubletPlayer {
private static final int PAUSE_BETWEEN_WORDS = 100;
private static final int PAUSE_BETWEEN_DOUBLETS = 400;
public static void main(String... args) {
DoubletPlayer player = new DoubletPlayer();
player.playDoublets(2);
}
interface Playable {
void play();
}
class Sound implements Playable {
private String word;
public Sound(String word) {
this.word = word;
}
#Override
public void play() {
System.out.println("sound played: " + word);
}
}
class Pause implements Playable {
private int millis;
public Pause(int millis) {
this.millis = millis;
}
#Override
public void play() {
System.out.println("pause of " + millis + "ms");
}
}
private List<Sound> sounds = new ArrayList<>();
private int currentSound = 0;
public DoubletPlayer() {
sounds.add(new Sound("This"));
sounds.add(new Sound("is"));
sounds.add(new Sound("a"));
sounds.add(new Sound("test"));
Collections.shuffle(sounds);
}
public void playDoublets(int numDoublets) {
List<Playable> doublets = generateDoublets(numDoublets);
playAll(doublets);
reset();
}
private List<Playable> generateDoublets(int numDoublets) {
List<Playable> result = new ArrayList<>();
for (int i = 0; i < numDoublets; i++) {
addDoubletTo(result);
}
return result;
}
private void addDoubletTo(List<Playable> result) {
result.add(getNextSound());
result.add(new Pause(PAUSE_BETWEEN_WORDS));
result.add(getNextSound());
result.add(new Pause(PAUSE_BETWEEN_DOUBLETS));
}
private Playable getNextSound() {
return sounds.get(currentSound++);
}
private void playAll(List<Playable> result) {
for (Playable playable : result) {
playable.play();
}
}
private void reset() {
currentSound = 0;
}
}

Related

How can I distinguish a winner in this thread race?

I have been writing a race code for a class I am in that races two threads, a tortoise and a hare. I can get both of them to run for 80 units but I don't know how to write a code that determines and outputs who the winner is. Any help would be appreciated because I am super new to coding.
I have the tortoise, hare, and raceParticipant classes. My driver class looks like this, where I would assume I put the winner code?
package Domain;
public class Driver
{
public static void main(String[] args)
{
Hare bob = new Hare();
Tortoise fred = new Tortoise();
int winDistance = 80;
do {
bob.sprint();
fred.sprint();
bob.display();
fred.display();
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}while(bob.getTotalDistance() < winDistance && fred.getTotalDistance() < winDistance);
}
}
My sprint method is
public int sprint()
{
int sleep = generator.nextInt(100);
int sprintDistance = 0;
if (sleep > sleepPercent)
{
sprintDistance = generator.nextInt(topSpeed) + 1;
}
totalDistance +=sprintDistance;
return sprintDistance;
}
I don't see you creating a new thread anywhere.
You can create a Hare class like this:
public class Hare implements Runnable {
private static final int SLEEP_DURATION = 3000; //milliseconds
private static final int SPEED = 3; //units per second
private int distanceToRun;
private final RaceFinishListener listener;
public Hare(int distanceToRun, RaceFinishListener listener) {
this.distanceToRun = distanceToRun;
this.listener = listener;
}
#Override
public void run() {
do {
distanceToRun -= SPEED;
try {
Thread.sleep(SLEEP_DURATION);
} catch (InterruptedException e) {
e.printStackTrace();
}
} while (distanceToRun > 0);
listener.onRaceFinished(getClass().getSimpleName());
}
}
and a similar Tortoise class with these variables:
private static final int SLEEP_DURATION = 1000; //sleeps less
private static final int SPEED = 1; //but is slow
Then create a listener to get notified when someone has finished:
public interface RaceFinishListener {
void onRaceFinished(String finisher);
}
and finally your main class:
public class Test implements RaceFinishListener {
private String winner;
private static final int DISTANCE_TO_RUN = 10;
public static void main(String[] args) {
new Test().race();
}
private void race() {
Hare bob = new Hare(DISTANCE_TO_RUN, this);
Tortoise fred = new Tortoise(DISTANCE_TO_RUN, this);
new Thread(bob).start();
new Thread(fred).start();
}
#Override
public void onRaceFinished(String finisher) {
synchronized (this) {
if (winner == null) {
winner = finisher;
System.out.println(finisher + " is the winner!");
} else {
System.out.println(finisher + " lost.");
}
}
}
}
Output
Tortoise is the winner!
Hare lost.
After this line:
}while(bob.getTotalDistance() < winDistance && fred.getTotalDistance() < winDistance);
You would just have:
boolean bobWins = (bob.getTotalDistance() >= winDistance);
boolean fredWins = (fred.getTotalDistance() >= winDistance);
if (bobWins && fredWins) {
System.out.println("It's a tie");
}
else if (bobWins) {
System.out.println("Bob Wins");
}
else {
System.out.println("Fred Wins");
}

javax.sound.sampled - trying to start audio sample repeatedly doesn't work

I am programming a little drum sequencer, a roland tr808 knockoff with 16 steps/measure and 16 instruments(=drum samples). User has a gui where he can thus create a 16x16 pattern.
However, if a sample is played more than once in quick succession, it often just gets played once. Say, I got a bassdrum on step 1, 5, 9 and 13 and tempo's 130BPM, it sometimes plays just the bd on 1 and 9, and sometimes the ones on 5 and/or 13 as well. If the sample is very short or the tempo is slow, the chances are higher that every step in the pattern is played correctly. So I assume that the audio line doesn't like it when I try to play a sample again when it hasn't finished yet.
But actually I thought I'd taken that into account in my code. I'd be really thankful if someone told me what's wrong with my code.
Here's my complete code as suggested by Andrew Thompson, modified so that it takes some samples from the internet. Loading them takes a bit, though. the part causing the issue is probably the play() method in the Instrument class:
package testbox;
import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.sound.sampled.*;
public class boomboxtest {
public static void main(String[] args) {
Sequencer seq = new Sequencer();
//bassdrum
seq.toggleInstrument(0,0);
seq.toggleInstrument(0,4);
seq.toggleInstrument(0,8);
seq.toggleInstrument(0,12);
//snare
seq.toggleInstrument(1,4);
seq.toggleInstrument(1,12);
//Hihat
seq.toggleInstrument(2, 2);
seq.toggleInstrument(2, 6);
seq.toggleInstrument(2, 10);
//Bongo
seq.toggleInstrument(3, 6);
seq.toggleInstrument(3, 10);
seq.setTempo(130);
seq.play();
}
}
class Sequencer {
private Mixer mixer;
private List<SequencerListener> listeners = new ArrayList<SequencerListener>();
public static final int INSTR_COUNT = 4;
private int tempo_bpm = 120;
private ExecutorService executor;
private int current_step = 0;
private int current_max_step = 16;
private boolean[][] pattern = new boolean[32][INSTR_COUNT];
private ArrayList<Instrument> instruments;
Line[] lines = new Line[16];
private SequencerEngine seq;
private String[] filenames = {"http://www.canadianmusicartists.com/sample/kick_02.wav", "http://www.canadianmusicartists.com/sample/snare01.wav", "http://www.canadianmusicartists.com/sample/H_closedhat_01.wav", "http://www.canadianmusicartists.com/sample/bongo01.wav"};
public Sequencer() {
seq = new SequencerEngine();
try{
Mixer.Info[] mixerInfo = AudioSystem.getMixerInfo();
mixer = AudioSystem.getMixer(mixerInfo[0]);
} catch (Exception e) {e.printStackTrace();}
instruments = new ArrayList<Instrument>(INSTR_COUNT);
for (int i = 0; i < INSTR_COUNT; i++) {
System.out.println("Loading instrument " + i);
Instrument instr = new Instrument(filenames[i], mixer);
instruments.add(instr);
lines[i] = instr.getLine();
}
syncMixer();
executor = Executors.newCachedThreadPool();
executor.submit(seq);
}
public void syncMixer() {
if (mixer.isSynchronizationSupported(lines, false)) {
mixer.synchronize(lines, false);
} else {
System.out.println("No hay synchronisado");
}
}
public boolean isPlaying() {
return seq.getRunning();
}
public boolean toggleInstrument (int instrument, int beat) {
pattern[beat][instrument] = !pattern[beat][instrument];
return pattern[beat][instrument];
}
public void play() {
seq.toggleRun(true);
}
public void pause() {
seq.toggleRun(false);
}
public void stop() {
pause();
setCurrent_step(0);
}
public int getTempo() {
return tempo_bpm;
}
public void setTempo(int tempo) {
if (tempo < 30) {
tempo = 30;
} else if (tempo > 200) {
tempo = 200;
} else {
this.tempo_bpm = tempo;
}
}
public int getCurrent_step() {
return current_step;
}
public void setCurrent_step(int current_step) {
this.current_step = current_step;
}
public boolean[][] getPattern() {
return pattern;
}
public void kill() {
seq.kill();
executor.shutdownNow();
}
public void addListener(SequencerListener toAdd) {
listeners.add(toAdd);
}
public class SequencerEngine implements Runnable{
private boolean running;
private boolean alive = true;
public void run() {
while( getAlive()) {
while (getRunning()) {
if (current_step >= current_max_step) {
current_step = 0;
}
for (; current_step < current_max_step ; current_step++) {
stepListen();
if(!getRunning()) {
break;
}
long time = System.currentTimeMillis();
long steptime = 60000/(4*tempo_bpm);
for (int k = 0; k < INSTR_COUNT; k++) {
if (pattern[current_step][k]) {
instruments.get(k).play();
}
}
while((System.currentTimeMillis()-time) < steptime) {}
}
}
}
}
public void stepListen() {
for (SequencerListener sl : listeners) {
sl.stepEvent(current_step);
}
}
public boolean getRunning() {
return running;
}
public boolean getAlive() {
return alive;
}
public void toggleRun(boolean toggle) {
running = toggle;
}
public void kill() {
alive = false;
}
}
}
class Instrument {
private String name;
private File soundFile;
private AudioInputStream stream;
private AudioFormat format;
private DataLine.Info info;
private Clip clip;
private Mixer mixer;
public Instrument(String filename, Mixer mixer ) {
this.name = filename;
try {
//soundFile = new File("sounds/" + filename);
URL url = new URL(filename);
this.mixer = mixer;
//stream = AudioSystem.getAudioInputStream(soundFile);
stream = AudioSystem.getAudioInputStream(url);
format = stream.getFormat();
info = new DataLine.Info(Clip.class, format);
clip = (Clip) mixer.getLine(info);
clip.open(stream);
}
catch (Exception e) {
e.printStackTrace();
}
}
public void play() {
clip.stop();
clip.setFramePosition(0);
clip.start();
}
public Line getLine() {
return clip;
}
}
interface SequencerListener {
void stepEvent(int current_step);
}
The samples are of rather questionable quality, but especially the bassdrum sample illustrates my problem really good.

StackOverFlowError when looping through options

I'm working on an exercise and I'm running into something. The following code gives me a stackoverflow error, but I have no idea why because my code should stop.
class Options {
private int amount;
private ArrayList<Integer> pieces;
public void execute() {
pieces = new ArrayList<Integer>();
pieces.add(5);
pieces.add(2);
pieces.add(3);
amount = pieces.size();
combinations(new StringBuilder());
}
public void combinations(StringBuilder current) {
if(current.length() == pieces.size()) {
System.out.println(current.toString());
return;
}
for(int i = 0; i < amount; i++) {
current.append(pieces.get(i));
combinations(current);
}
}
}
It only prints the first output (555).
Thanks.
Add a return to end your recursion
public void combinations(StringBuilder current) {
if(current.length() == pieces.size()) {
System.out.println(current.toString());
return; // <-- like so.
}
for(int i = 0; i < amount; i++) {
current.append(pieces.get(i));
combinations(current);
}
}
or put the loop in an else like
public void combinations(StringBuilder current) {
if(current.length() == pieces.size()) {
System.out.println(current.toString());
} else {
for(int i = 0; i < amount; i++) {
current.append(pieces.get(i));
combinations(current);
}
}
}
Edit
static class Options {
private List<Integer> pieces;
public void execute() {
pieces = new ArrayList<>();
pieces.add(5);
pieces.add(2);
pieces.add(3);
combinations(new StringBuilder());
}
public void combinations(StringBuilder current) {
if (current.length() == pieces.size()) {
System.out.println(current.toString());
} else {
for (int i = current.length(); i < pieces.size(); i++) {
current.append(pieces.get(i));
combinations(current);
}
}
}
}
public static void main(String[] args) {
Options o = new Options();
o.execute();
System.out.println(o.pieces);
}
Output is
523
[5, 2, 3]

Error with code for playlists in java mp3 player

I'm struggling with creating a playlist for my simple mp3 player in Java but the code is somehow not working. Here is the playlist part:
FileFilter filter = new FileNameExtensionFilter("MP3 Files", "mp3", "mpeg3");
JFileChooser chooser = new JFileChooser("C:\\Users\\Junior\\Music");
chooser.addChoosableFileFilter(filter);
chooser.setMultiSelectionEnabled(true);
int returnVal = chooser.showOpenDialog(null);
if(returnVal == JFileChooser.APPROVE_OPTION){
//File myFile=chooser.getSelectedFile();
File[] files=chooser.getSelectedFiles();
//String song=myFile+"";
for(int i=0; i<files.length;i++){
name=files[i].getName()+"";//getting song name for display purpose
try {
MC.Stop();//stopping if any file is playing
display.setText(name.substring(0,name.length()-4));//setting name songs in display (without .mp3)
MC.Play(files[i]+"");//from main class i'm calling play method
} catch (IOException e) {//i'm not really catching any exceptions so...
}//end of catch
}//end of for-loop
}//end of if
This code is playing the last song selected (even if I choose multiple files - so the last selected song) but not advancing to the next song.
I thought this might help you from reading your comment. This is a playlist class that I created. It's an abstract class, so you need to create your own class that extends this class, and implement the loadSongs method
public abstract class Playlist {
public static final int LOOP_NONE = 0;
public static final int LOOP_PLAYLIST = 1;
public static final int LOOP_SONG = 2;
private List<File> songs;
private int playlistPos;
private int loopMode;
private boolean isShuffled;
public Playlist() {
isShuffled = false;
loopMode = 0;
}
protected abstract List<File> loadPlaylist();
public void initPlaylist() {
songs = loadPlaylist();
}
public File getCurrentSong() {
return songs.get(playlistPos);
}
public int getPlaylistPosition() {
return playlistPos;
}
public void setPlaylistPosition(int playlistPos) {
this.playlistPos = playlistPos;
}
public int getPlaylistSize() {
return songs.size();
}
public boolean isFinalSong() {
return playlistPos == songs.size() - 1;
}
public boolean isShuffled() {
return isShuffled;
}
public int getLoopMode() {
return loopMode;
}
public void toggleShuffle() {
setShuffle(!isShuffled);
}
public void toggleLoop() {
loopMode = (loopMode + 1) % 3;
}
public void skipForward() {
playlistPos = (playlistPos + 1) % songs.size();
// Re-shuffle songs each time the playlist loops
if (playlistPos == 0 && isShuffled) {
shuffle();
}
}
public void skipBack() {
playlistPos = playlistPos == 0 ? songs.size() - 1 : playlistPos - 1;
}
public void setLoop(int loopMode) {
this.loopMode = loopMode;
}
public void setShuffle(boolean shuffle) {
this.isShuffled = shuffle;
if (isShuffled) {
shuffle();
}
else {
unshuffle();
}
}
protected void shuffle() {
Collections.shuffle(songs.subList(playlistPos + 1, songs.size()));
}
protected void unshuffle() {
initPlaylist();
}
}
So you would create a subclass like this:
public TestPlaylist extends Playlist {
#Override
protected List<File> loadPlaylist() {
// Show your file chooser, and return the selected files
// as a list.
}
}
And to use it, you would write:
Playlist playlist = new TestPlaylist();
playlist.initPlaylist();
// Do what you want with it, for example:
playlist.setShuffle(true);
MC.play(playlist.getCurrentSong().getAbsolutePath());

pausing threads in java

I was wondering if someone coule help me on how to implement a thread which runs infinitely in the background until the user presses p at which point it pauses the other threads and upon pressing r resumes other threads. This is some of the code
Some of the main object
public class CardGame
{
static Player[] players;
static int handSize;
static Queue<Card>[] playingDeckArray;
public static void main(String[] args){
Scanner reader = new Scanner(System.in);
System.out.println( "\nHello, how many players would you like" );
int playersNum = Integer.parseInt(Checks.userInputCheck( "\\d" ));
System.out.println( "\nHow many cards should each player begin with" );
int handSize = Integer.parseInt(Checks.userInputCheck( "\\d" ));
System.out.println( "\nWhich strategy would you like to use 1 or 2" );
int strategy = Integer.parseInt(Checks.userInputCheck( "[12]$" ));
Logger.createDeck( playersNum, handSize );
makePlayers( playersNum, handSize, strategy );
makePlayingDecks( playersNum );
dealInitialHand( playersNum, players, handSize );
makePlayerOutputs();
for ( int i = 0; i < players.length; i++){
logInitialHand(players[i]);
}
CardGame cG = new CardGame();
cG.startPauseThread();
for ( int i = 0; i < players.length; i++){
new Thread(players[i]).start();
}
}
public void startPauseThread(){
Thread add = new Thread( pauseInputThread );
add.start();
}
Thread pauseInputThread = new Thread(){
public void run(){
int i = 0;
for(;;){
System.out.println("i'm still here" );
Scanner reader = new Scanner(System.in);
String result = Checks.userInputCheck( "[pPrR]$" );
i++;
System.out.println(i);
}
}
};
}
The player object which are the threads to be paused
public class Player implements Runnable
{
Card[] hand;
String playerName;
int strategyChosen;
public void run(){
System.out.println( "les do dis" );
}
private Player(){
}
public Player( int strategy, int cardsInHand, int playerNumber ){
hand = new Card[cardsInHand];
strategyChosen = strategy;
playerName = "Player " + playerNumber;
}
public String getPlayerName(){
return playerName;
}
public void fillHand(){
for ( int i = 0; i < hand.length; i++){
hand[i] = new Card(0);
}
}
public void setHand( int value, int index ){
hand[index].setCardValue( value );
}
public void seeHand(){
for ( int i = 0; i < hand.length; i++){
System.out.println( hand[i].getCardValue() );
}
}
public String getHand(){
String result = "";
for ( int i = 0; i < hand.length; i++ ){
result = result + hand[i].getCardValue() + " \n" ;
}
return result;
}
public int getHandValue( Card card ){
return card.getCardValue();
}
}
The players will be 'playing a game' where they draw and discard objects from arrays, but the user should be able to pause and resume the programm at any point during the game. i just dont quite understand how to go about that, using events and listners.
Help would be appreciated. Thank you.
Thread has no mechanism for this on its own. You can, however, easily add this functionality in to your own process. You'll have some flag to set and check and then probably the best is to have a wait/notify scheme. Here's a simple demonstration:
abstract class PausableTask implements Runnable {
private volatile boolean paused;
private final Object lock = new Object();
void setPaused(boolean shouldPause) {
synchronized (lock) {
paused = shouldPause;
if (!paused) {
lock.notify();
}
}
}
boolean isPaused() { return paused; }
#Override
public void run() {
for (;;) {
synchronized (lock) {
while (paused) {
try {
lock.wait();
} catch (InterruptedException e) {}
}
}
doTask();
}
}
abstract void doTask();
}
class Counter {
volatile long count;
public static void main(String[] args) {
final Counter counter = new Counter();
PausableTask increment = new PausableTask() {
#Override
void doTask() {
counter.count++;
}
};
PausableTask decrement = new PausableTask() {
#Override
void doTask() {
counter.count--;
}
};
decrement.setPaused(true);
PausableTask next = increment;
Scanner in = new Scanner(System.in);
long count = counter.count;
new Thread(increment).start();
new Thread(decrement).start();
for (;;) {
System.out.print(
(next == increment ? "Counting up from " : "Counting down from ")
+ count + ". Enter 'exit' to abort or anything else to toggle: "
);
if (in.nextLine().equals("exit")) {
System.exit(0);
}
if (increment.isPaused()) {
next = increment;
decrement.setPaused(true);
} else {
next = decrement;
increment.setPaused(true);
}
count = counter.count;
next.setPaused(false);
}
}
}
For taking user input from the keyboard, there's not really a convenient way to do that in Java. If you want to take straight keystrokes you need a GUI component for them to happen in. If you do plan on implementing a GUI take a look at the key bindings tutorial.
It's not possible to pause a thread simply by calling some predefined method, nor it's possible to kill a thread. The only thing you can do is to implement this behavior by yourself. It means that you will do something like this:
public class MyThread extends Thread {
private volatile boolean running = true;
private volatile boolean paused = false;
public void kill() {
this.running = false;
}
public void setPaused(boolean paused) {
this.paused = paused;
}
#Override
public void run() {
while (running) {
if (!paused) {
// do another step
}
}
}
}
However, it's possible that I didn't understand your question correctly. Leave me a feedback so I can update my answer eventually.

Categories