Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Java, is there a way to synthesize a tone of a specific frequency?

I'm doing some work with binaural beats and am trying to build a Java application that can play two sounds at slightly different frequencies...around 25-30Hz difference.

In a perfect world, I'd like to give Java two integer inputs, say 440 and 410, and have Java play back a 440Hz tone and a 410Hz tone.

Given what I've seen in the javax.sound.* classes, it appears that Java only supports the equivalent of piano notes...A4 @ 440Hz, then A-sharp-4 @ 466.164Hz, and in the other direction, G-sharp-4 @ 415.305Hz. While "adjacent" are generally within the range to produce a binaural beat, I'm trying to achieve more control in the frequency of my tones.

Since simple audio synthesis is nothing more than frequency, intensity and length-of-time, it would appear to me that somewhere in the bowels of the javax.sound.* classes, there's some kind of lookup that says when I tell Java to play "A4", that's 440Hz . The question becomes whether or not there's a way to hack that table to say that "A4.1" is the equivalent of 449Hz.

I've been messing with javax.sound.midi, have not explored javax.sound.sampled yet; it appears that I'd need to sample my tones to use the sampled classes; I prefer to synthesize. Steer me right if I'm mistaken.

Most of the third party interfaces I've seen are geared specifically toward music production and manipulation, and, as such, are limited in their ability to work with microtones. Does anyone have any experience with or recommendations for a solution?

like image 548
dwwilson66 Avatar asked May 23 '12 23:05

dwwilson66


2 Answers

You can generate samples and send them to the soundcard using the classes in javax.sound.sampled.*; basically create a software oscillator.

It requires some knowledge, but can be really fun when you get it to work ;)

I was playing with these classed when I created this: http://bobusumisu.net/testing/bobusynth-alpha1/

Here is the tutorial that got me started: http://www.drdobbs.com/jvm/230500178

like image 171
BobuSumisu Avatar answered Sep 29 '22 03:09

BobuSumisu


This is just to supplement the answer already provided and accepted (which I gave a +1).

You can use wavetables as an alternative to running trig functions on the fly--sort of half sampled/half synthesized. I also use a sine wave table with six independent cursors pointing into it for FM synthesis, and have duplicated several Yamaha DX7 patches this way. But this is all done via javax.sound.sampled. Once a soft-synth has been built, you might want to control it with the midi library classes.

Let's say you populate a 1K array with floats for a single sine wave.

If you "play" the wave table by incrementing and looping through it and extracting each array member in turn (to write to the sound card via a SourceDataLine), you will get a pitch directly related to your sample rate. For 44100 samples per second, the 1024-member array will cycle 44100/1024 = 43.066... times in to fill that "second" with data (a very low pitch--roughly 43 Hz). If you skip every second table member, the pitch is twice that, etc. To get the pitch 440, one needs to find the correct "increment" to use to step through the wave table array, which can be found: incr = (size of waveTable * desired pitch) / sample rate

For example (1024 * 440 ) / 44100 gives an increment of: 10.21678... Thus, if the first value from the waveTable is at array location 0, the second value to be used would be in between locations 10 and 11. To get a value that lies in between two array locations, use linear interpolation.

I use this method, with javax.sound.sampled libraries, for a "Theremin" at this link. There is a keyboard displayed, but you can easily hear/see microtonal control as you move the mouse across the keys.

http://www.hexara.com/VSL/JTheremin.htm

In the above, the mouse position (called via MouseMotionListener) is used to calculate desired pitch via this function:

return Math.pow(2, ((mouseX + tuningLoc) / (octaveWidth)));

where octaveWidth is the number of pixels that covers an octave.

like image 33
Phil Freihofner Avatar answered Sep 29 '22 02:09

Phil Freihofner