A few sounds in Java

I am trying to play 2 sounds (e.g. 220 Hz and 440 Hz) simultaneously in Java.

I was able to play one sound using StdAudio . Later I made it non-static and deleted some methods that are not relevant to me.

I do not know how to play 2 sounds at the same time. I tried to do this using a thread, but they are not always in sync.

Below is my modified version of StdAudio, and here is an example of how I tried to use streams.

program.java

public class program { public static void main(String[] args) { Thread t1 = new Thread(new soundThread(220)); t1.start(); Thread t2 = new Thread(new soundThread(440)); t2.start(); t1.notify(); t2.notify(); } } 

soundThread.java

 public class soundThread implements Runnable { private int fq; public soundThread(int fq) { this.fq = fq; } public void run() { StdAudio s = new StdAudio(); double[] note = s.note(fq, 2, 1); try { this.wait(); } catch (Exception e) { } s.play(note); s.close(); } } 

Stdaudio.java

 /************************************************************************* * Compilation: javac this.java * Execution: java StdAudio * * Simple library for reading, writing, and manipulating .wav files. * * Limitations * ----------- * - Does not seem to work properly when reading .wav files from a .jar file. * - Assumes the audio is monaural, with sampling rate of 44,100. * *************************************************************************/ import javax.sound.sampled.*; /** * <i>Standard audio</i>. This class provides a basic capability for creating, * reading, and saving audio. * <p> * The audio format uses a sampling rate of 44,100 (CD quality audio), 16-bit, * monaural. * * <p> * For additional documentation, see <a * href="http://introcs.cs.princeton.edu/15inout">Section 1.5</a> of * <i>Introduction to Programming in Java: An Interdisciplinary Approach</i> by * Robert Sedgewick and Kevin Wayne. */ public final class StdAudio { /** * The sample rate - 44,100 Hz for CD quality audio. */ public final int SAMPLE_RATE = 44100; private final int BYTES_PER_SAMPLE = 2; // 16-bit audio private final int BITS_PER_SAMPLE = 16; // 16-bit audio private final double MAX_16_BIT = Short.MAX_VALUE; // 32,767 private final int SAMPLE_BUFFER_SIZE = 4096; private SourceDataLine line; // to play the sound private byte[] buffer; // our internal buffer private int bufferSize = 0; // number of samples currently in internal // buffer // initializer { init(); } // open up an audio stream private void init() { try { // 44,100 samples per second, 16-bit audio, mono, signed PCM, little // Endian AudioFormat format = new AudioFormat((float) SAMPLE_RATE, BITS_PER_SAMPLE, 1, true, false); DataLine.Info info = new DataLine.Info(SourceDataLine.class, format); line = (SourceDataLine) AudioSystem.getLine(info); line.open(format, SAMPLE_BUFFER_SIZE * BYTES_PER_SAMPLE); // the internal buffer is a fraction of the actual buffer size, this // choice is arbitrary // it gets divided because we can't expect the buffered data to line // up exactly with when // the sound card decides to push out its samples. buffer = new byte[SAMPLE_BUFFER_SIZE * BYTES_PER_SAMPLE / 3]; } catch (Exception e) { System.out.println(e.getMessage()); System.exit(1); } // no sound gets made before this call line.start(); } /** * Close standard audio. */ public void close() { line.drain(); line.stop(); } /** * Write one sample (between -1.0 and +1.0) to standard audio. If the sample * is outside the range, it will be clipped. */ public void play(double in) { // clip if outside [-1, +1] if (in < -1.0) in = -1.0; if (in > +1.0) in = +1.0; // convert to bytes short s = (short) (MAX_16_BIT * in); buffer[bufferSize++] = (byte) s; buffer[bufferSize++] = (byte) (s >> 8); // little Endian // send to sound card if buffer is full if (bufferSize >= buffer.length) { line.write(buffer, 0, buffer.length); bufferSize = 0; } } /** * Write an array of samples (between -1.0 and +1.0) to standard audio. If a * sample is outside the range, it will be clipped. */ public void play(double[] input) { for (int i = 0; i < input.length; i++) { play(input[i]); } } /** * Create a note (sine wave) of the given frequency (Hz), for the given * duration (seconds) scaled to the given volume (amplitude). */ public double[] note(double hz, double duration, double amplitude) { int N = (int) (this.SAMPLE_RATE * duration); double[] a = new double[N + 1]; for (int i = 0; i <= N; i++) a[i] = amplitude * Math.sin(2 * Math.PI * i * hz / this.SAMPLE_RATE); return a; } } 

Thanks in advance, Shay Ben Moshe

EDIT: The solution wrote this method:

 public double[] multipleNotes(double[] hzs, double duration, double amplitude) { amplitude = amplitude / hzs.length; int N = (int) (SAMPLE_RATE * duration); double[] a = new double[N + 1]; for (int i = 0; i <= N; i++) { a[i] = 0; for (int j = 0; j < hzs.length; j++) a[i] += amplitude * Math.sin(2 * Math.PI * i * hzs[j] / SAMPLE_RATE); } return a; } 

EDIT2: An even better solution for me (O (1) memory):

 public void multiplePlay(double[] hzs, double duration, double amplitude) { amplitude = amplitude / hzs.length; int N = (int) (SAMPLE_RATE * duration); double sum; for (int i = 0; i <= N; i++) { sum = 0; for (int j = 0; j < hzs.length; j++) sum += amplitude * Math.sin(2 * Math.PI * i * hzs[j] / SAMPLE_RATE); this.play(sum); } } 
+4
source share
4 answers

Expand a bit in my comment about simply combining two sounds into one ...

You showed this:

 public double[] note(double hz, double duration, double amplitude) { int N = (int) (this.SAMPLE_RATE * duration); double[] a = new double[N + 1]; for (int i = 0; i <= N; i++) a[i] = amplitude * Math.sin(2 * Math.PI * i * hz / this.SAMPLE_RATE); return a; } 

So how about mixing two sounds in one and playing that unique sound? For example, you can do something like this:

 public double[] notes(double hz1, double hz2, double duration, double amplitude) { final double[] a1 = note( hz1, duration, amplitude ); final double[] a2 = note( hz2, duration, amplitude ); final double[] a3 = new double[a2.length]; for ( int i = 0; i < a1.length; i++ ) { a3[i] = (a1[i] + a2[i]) / 2; } return a3; } 

And you just call it that:

 final double[] sound = notes(220,400,...,...); 
+6
source
0
source

The OpenAL Open Audio API, available on iOS in the OpenAL framework, provides an interface optimized for positioning sounds in a stereo field during playback. Playback, positioning and moving sounds work the same way as on other platforms. OpenAL also allows you to mix sounds. Here for more: http://developer.apple.com/library/IOS/#documentation/AudioVideo/Conceptual/MultimediaPG/UsingAudio/UsingAudio.html

0
source

You can play multiple sounds of a certain frequency using the JSyn library.

It will work for what you want right now, and you may want to move on to it later if you want to do something more complex.

http://www.softsynth.com/jsyn/

As an example, I also managed to find some more complex sounds here:

JSyn, a siren sound using a generator, controlled / driven / inputInto / daisy-chainedTo by another oscillator and constant ... and generating more than one sound

This code will generate tones at a frequency of 220 Hz and 440 Hz at the same time.

com.jsyn.Synthesizer synth = JSyn.createSynthesizer (),
com.jsyn.unitgen.SineOscillator sine1 = new SineOscillator ();
com.jsyn.unitgen.SineOscillator sine2 = new SineOscillator ();
com.jsyn.unitgen.LineOut lineOut = new LineOut ();

synth.add (sine1);
synth.add (Sine2);
synth.add (LineOut);

sine1.frequency.set (220);
sine2.frequency.set (440);

sine1.output.connect (0, lineOut.input, 0); // left and right channels
sine1.output.connect (0, lineOut.input, 1);
sine2.output.connect (0, lineOut.input, 0); // left and right channels
sine2.output.connect (0, lineOut.input, 1);

lineOut.start ();

0
source

All Articles