i have some code that will make sound, a sine wave, actually, but i want to be able to actually play more than one sound at once, how can i modify this code to make it work. i found this on the internet somewhere, and it was hard to find.

import javax.sound.sampled.* ;

public class test {
	public static void main ( String [ ] args ) {
		int seconds = 1 ;
		int sampleRate = 8000 ;
		double frequency = 200.0 ;
		double RAD = 2.0 * Math.PI ;
		try {
			AudioFormat af = new AudioFormat ( ( float ) sampleRate , 8 , 1 ,
					true , true ) ;
			DataLine.Info info = new DataLine.Info ( SourceDataLine.class , af ) ;
			SourceDataLine source = ( SourceDataLine ) AudioSystem
					.getLine ( info ) ;
			source.open ( af ) ;
			source.start ( ) ;
			byte [ ] buf = new byte [ sampleRate * seconds ] ;
			for ( int i = 0 ; i < buf.length ; i ++ ) {
				buf [ i ] = ( byte ) ( Math.sin ( RAD * frequency / sampleRate
						* i ) * 127.0 ) ;
				System.out.println ( buf [ i ] ) ;
			}
			source.write ( buf , 0 , buf.length ) ;
			source.drain ( ) ;
			source.stop ( ) ;
			source.close ( ) ;
		} catch ( Exception e ) {
			System.out.println ( e ) ;
		}
		System.exit ( 0 ) ;
	}
}

Why not encapsulate what produces the sound in a thread and execute multiple versions of the thread (where upon initialization, you specify a String for the file to read to get the .wav file to play)?

Edit: Oh I just noticed you're producing sound based on numbers and not a file. In that case I suppose number arguments in the constructor for the thread object, store them and use them for the thread to execute a different sound.

now i have another problem, i did this and now the sound won't even play at all :(

code:

import javax.sound.sampled.* ;

public class test {
	public static void main ( String [ ] args ) {
		Thread p1 = new Player ( ) ;
		Thread p2 = new Player ( 1000.0 ) ;
		p1.start ( ) ;
		//p2.start();
	}
}
import javax.sound.sampled.* ;

public class Player extends Thread {
	int seconds ;
	int sampleRate = 8000 ;
	double frequency ;
	static double RAD = 2.0 * Math.PI ;
	byte [ ] buf ;

	public Player ( ) {
		this ( 200 , 1 ) ;
	}

	public Player ( double f ) {
		this ( f , 1 ) ;
	}

	public Player ( int s ) {
		this ( 200 , s ) ;
	}

	public Player ( double f , int s ) {
		frequency = f ;
		seconds = s ;
		buf = new byte [ sampleRate * seconds ] ;
		for ( int i = 0 ; i < buf.length ; i ++ ) {
			buf [ i ] = ( byte ) ( ( Math.sin ( RAD * frequency / sampleRate
					* i ) ) * 127.0 ) ;
			System.out.println ( buf [ i ] ) ;
		}
	}

	@ Override public void run ( ) {
		try {
			AudioFormat af = new AudioFormat ( ( float ) sampleRate , 8 , 1 ,
					true , true ) ;
			DataLine.Info info = new DataLine.Info ( SourceDataLine.class , af ) ;
			SourceDataLine source = ( SourceDataLine ) AudioSystem
					.getLine ( info ) ;
			source.open ( af ) ;
			source.write ( buf , 0 , buf.length ) ;
			source.drain ( ) ;
			source.stop ( ) ;
			source.close ( ) ;
		} catch ( Exception e ) {
			System.out.println ( e ) ;
		}
	}
}

any help?

I think you may need to join the main program to your threads so that the main program waits for the threads to finish then exits.

import javax.sound.sampled.* ;

public class test {
	public static void main ( String [ ] args ) {
		Thread p1 = new Player ( ) ;
		Thread p2 = new Player ( 1000.0 ) ;
		p1.start ( ) ;
		p2.start();
                                joinAll(p1, p2);
	}

                private static void joinAll(Thread... args){
                      for(Thread element : args)
                            element.join();
                }
}

ok i added that (by the way element.join() not args.join() ) but it still doesn't play the sound

This worked for me--

import javax.sound.sampled.*;

public class test_sound {

	private class MyThread extends Thread{

		int seconds = 1, sampleRate = 8000;
		double frequency = 200.0;

		public MyThread(){

		}

		public MyThread(int seconds, int sampleRate, double frequency){
			this.seconds = seconds;
			this.sampleRate = sampleRate;
			this.frequency = frequency;
		}

		public void run(){
			while(true){
				//int seconds = 1 ;
				//int sampleRate = 8000 ;
				//double frequency = 200.0 ;
				double RAD = 2.0 * Math.PI ;
				try {
					AudioFormat af = new AudioFormat ( ( float ) sampleRate , 8 , 1 ,
							true , true ) ;
					DataLine.Info info = new DataLine.Info ( SourceDataLine.class , af );
					SourceDataLine source = (SourceDataLine)AudioSystem.getLine(info);
					source.open ( af ) ;
					source.start ( ) ;
					byte [ ] buf = new byte [ sampleRate * seconds ] ;
					for ( int i = 0 ; i < buf.length ; i ++ ) {
						buf [ i ] = ( byte ) ( Math.sin ( RAD * frequency / sampleRate
								* i ) * 127.0 );
					}
					source.write ( buf , 0 , buf.length ) ;
					source.drain ( ) ;
					source.stop ( ) ;
					source.close ( ) ;
				} catch ( Exception e ) {
					System.out.println ( e ) ;
				}
			}
		}
	}

	public static void main ( String [ ] args ) {
		test_sound tc = new test_sound();
		Thread m1 = tc.new MyThread(2, 7000, 400);
		Thread m2 = tc.new MyThread(3, 6000, 350);

		m1.start();
		sleep(750);
		m2.start();
		joinAll(m1, m2);
	}

	private static void sleep(long milli){
		try{
			Thread.sleep(milli);
		}catch(Exception e){}
	}

	private static void joinAll(Thread... args){
		for(Thread element : args){
			try{
				element.join();
			}catch(Exception e){System.out.println(e);}
		}
	}
}

Though I think this version will be far more helpful for Sound experimentation--

import javax.sound.sampled.*;
import java.util.Random;

public class test_sound {

	private class MyThread extends Thread{

		int seconds = 1, sampleRate = 8000;
		double frequency = 200.0;
		boolean randomize = false;
		private Random rgen = new Random();

		public MyThread(){

		}

		public MyThread(int seconds, int sampleRate, double frequency){
			this.seconds = seconds;
			this.sampleRate = sampleRate;
			this.frequency = frequency;
		}

		public MyThread(boolean condition){
			if(condition){
				randomize = condition;
			}
		}

		public void run(){
			while(true){
				if(randomize){
					seconds = rgen.nextInt(3) + 1;
					sampleRate = rgen.nextInt(8000);
					frequency = rgen.nextInt(1200);
					System.out.println(seconds + " " + sampleRate + " " + frequency + "\n");
				}
				double RAD = 2.0 * Math.PI ;
				try {
					AudioFormat af = new AudioFormat ( ( float ) sampleRate , 8 , 1 ,
							true , true ) ;
					DataLine.Info info = new DataLine.Info ( SourceDataLine.class , af );
					SourceDataLine source = (SourceDataLine)AudioSystem.getLine(info);
					source.open ( af ) ;
					source.start ( ) ;
					byte [ ] buf = new byte [ sampleRate * seconds ] ;
					for ( int i = 0 ; i < buf.length ; i ++ ) {
						buf [ i ] = ( byte ) ( Math.sin ( RAD * frequency / sampleRate
								* i ) * 127.0 );
					}
					source.write ( buf , 0 , buf.length ) ;
					source.drain ( ) ;
					source.stop ( ) ;
					source.close ( ) ;

				} catch ( Exception e ) {
					System.out.println ( e ) ;
				}
			}
		}
	}

	public static void main ( String [ ] args ) {
		test_sound tc = new test_sound();
	//	Thread m1 = tc.new MyThread(2, 7000, 400);
	//	Thread m2 = tc.new MyThread(3, 6000, 350);
		Thread m3 = tc.new MyThread(true);

	//	m1.start();
	//	sleep(750);
	//	m2.start();
		m3.start();
		joinAll(/*m1, m2,*/ m3);
	}

	private static void sleep(long milli){
		try{
			Thread.sleep(milli);
		}catch(Exception e){}
	}

	private static void joinAll(Thread... args){
		for(Thread element : args){
			try{
				element.join();
			}catch(Exception e){System.out.println(e);}
		}
	}
}
Comments
provided useful working sample code

yes, thank you, that was very helpful, but how should i make it stop without having to exit the application?

Hmm I'd personally set a trigger/flag for when the Thread should execute the sound-producing algorithm (like a boolean that is controlled by a listener like a key listener, mouse listener or action listener).

Either that or you can implement a sound-Command pattern where Sound Commands are pushed into a queue and read only when they're needed (which is probably more ideal for producing music, but a bit harder).

i was thinking about the boolean thing, i wouldn't have thought of using a queue. really i want to make a keyboard controlled (haha) keyboard, like a simple piano app. so the boolean would probably be the best thing to use.

i was thinking about the boolean thing, i wouldn't have thought of using a queue. really i want to make a keyboard controlled (haha) keyboard, like a simple piano app. so the boolean would probably be the best thing to use.

Oh that's easy.

Key pressed (and held down) automically set flag off and also set numbers to produce the sound of the key.

Key release set flag on.

This article has been dead for over six months. Start a new discussion instead.