1

So i've been looking into the java sound api and I can get input,record and play back sounds and i can draw a graph using coordinates or sin.

I want to be able to have a live "Oscilloscope" as such which takes input from the mic and converts it into a waveform which scrolls left over time and when a noise is made the sound (frequency?) is added on to the left hand side of the graph and then goes back to normal when no more noise is made.

how can I convert an array of bytes into a graph?

so far i have a file that can record and play back sound (saved in a buffer not file) and then save it to a .wav and draw a wave .png from the .wav however this isn't a live feed and i'm not sure where to go from here.

Greg
  • 754
  • 9
  • 18
  • Convert the bytes to samples in between reading them from the input and writing them to the output. Then draw the buffer to a panel. You don't need a library, you can do this with Swing painting and about 100 lines of code depending on how nice you want it to look. – Radiodef Nov 16 '13 at 21:35
  • Can you give an example of a byte to coordinate code please I couldn't find any that work – Greg Nov 16 '13 at 22:16
  • Here is [one example](http://stackoverflow.com/a/11024268/418556).. – Andrew Thompson Nov 16 '13 at 22:51
  • I have come across that many times before and it creates a jpeg image of the graph not a live drawing.but thanks anyway – Greg Nov 16 '13 at 22:56
  • I'm working on a program right now that will basically do what you are asking. These kinds of questions get asked frequently enough that I guess I'm just writing one to repost. It's not particularly short but it will demonstrate how to do basically all these things. – Radiodef Nov 16 '13 at 23:03
  • Cool sounds interesting. Keep me posted :) – Greg Nov 16 '13 at 23:06

1 Answers1

2

Here is a (relatively small) application that will play back sound and draw a simple graphic on a panel:

WaveformDemo on github

It has some sparse comments to point out what is going on but it is generally straightforward. Really the best thing is just to look at the code. It does most of what you're asking about sans the recording but the code can be easily adapted to that. Only difference is you will be pulling the bytes from your TargetDataLine instead of an AudioInputStream.

Some of the stuff like the window function and quantizing might require a lengthy explanation but that's all covered in plenty of literature. In my experience while there are plenty of technical texts there are not a whole lot of code examples around on the web for this kind of thing. Java Sound Resources is a pretty good resource for Java in particular but it is a bit outdated. So I hope this can get you started.

Radiodef
  • 37,180
  • 14
  • 90
  • 125
  • Thanks a lot it is just what i was looking for and its very nicely explained in the comments. – Greg Nov 17 '13 at 11:49
  • One last question though i've been playing around with you're code and it runs of loading a file and playing it, i can create a file using the mic and then play it but how would i be able to get direct input from the mic and display it on the graph in real-time? i've tried a audio input stream but it wont let me use it as audioFile overrides getFile and i cant for instance change it to a byte[]; rather than a file. – Greg Nov 17 '13 at 12:29
  • No problem. When you call read on the TargetDataLine use those bytes. You don't need an AudioInputStream unless you are reading from a file. The tutorial shows a loop (under _"Reading the Data from the TargetDataLine"_) that's structurally identical to the one in the SwingWorker playback loop: http://docs.oracle.com/javase/tutorial/sound/capturing.html After calling `read` send those bytes to be converted and display them. – Radiodef Nov 17 '13 at 14:29
  • so i've done exactly as you said and [here's](http://www.snippetcake.com/Embed.php?Public=474) what i've got but i get a outofbounds exception error for 1024 when creating a sample, why is this i thought it was the correct amount for a byte? – Greg Nov 17 '13 at 15:34
  • What line do you get the exception on? I see a couple things that look like errors: you are calling out.write twice and also you should call `window` and `drawDisplay` with `count * 8 / format.getSampleSizeInBits()`. The svalid parameter is the number of valid samples in the buffer, so the number of valid bytes divided by the number of bytes in a sample. I'm not sure either of those problems will cause out of bounds though. – Radiodef Nov 17 '13 at 15:50
  • "Exception in thread "Thread-3" java.lang.ArrayIndexOutOfBoundsException: 1024" bla bla bla "at (WaveformDemo.java:395)" and "(WaveformDemo.java:295)" aaa yeah the second out.write was meant to be commented out and changing the count to *8 didn't make a difference – Greg Nov 17 '13 at 15:54
  • Oh OK. Try changing your declaration of bufferSize so the byte array matches the sample array `int bufferSize = samples.length * 8 / format.getSampleSizeInBits();` – Radiodef Nov 17 '13 at 16:00
  • ok now it works however nothing is actually displayed like its not being drawn so i found that audioFormat was returning null cause it hasn't been set to anything so in setting it to getFormat() it now works a treat :) although it does open up a second panel when pressing open to run it ill have to look into that. thanks for your help. – Greg Nov 17 '13 at 16:19
  • Yeah you are creating a new WaveformDemo at the beginning of your doInBackground. It looks like you are doing it to call getFormat and what you can do is add a method getFormat to the interface PlayerRef. Then you can call getFormat on the reference passed in to the SwingWorker. The PlayerRef interface is a way to access the main class from inside the playback loop without passing the whole thing in. You could change the PlaybackLoop constructor so it takes a WaveformDemo and pass the whole thing in though if you wanted. Glad it's working otherwise. : ) – Radiodef Nov 17 '13 at 16:34
  • Hey @Greg, is there any way you could share the file that you've uploaded here? – Eyal Wurmbrand Mar 12 '16 at 21:39