Wednesday 15 February 2012

How to calculate the level/amplitude/db of audio signal in java? -



How to calculate the level/amplitude/db of audio signal in java? -

i want create sound level meter in java microphone check how loud input is. should 1 of os. i'm not asking gui. calculating sound level out of bytestream produced

n = targetdataline.read( tempbuffer , 0 , tempbuffer.length );

so have running, not close levelmeter of os (windows) stucks in middle. have values between 0 , 100 in middle volume stucks around 60 no matter how loud input is.

this how calculate now:

amplitude = 0; (int j = 0; j < tempbuffer.length; j = j +2 ){ if (tempbuffer[j] > tempbuffer[j+1]) amplitude = amplitude + tempbuffer[j] - tempbuffer[j+1]; else amplitude = amplitude + tempbuffer[j + 1] - tempbuffer[j]; } amplitude = amplitude / tempbuffer.length * 2;

is there better/more precise way calculate sound level monitor it? or did maybe major mistake?

that audioformat:

public static audioformat getaudioformat(){ float samplerate = 20000.0f; //8000,11025,16000,22050,44100 int samplesizeinbits = 16; //8,16 int channels = 1; //1,2 boolean signed = true; //true,false boolean bigendian = false; //true,false homecoming new audioformat( samplerate, samplesizeinbits, channels, signed, bigendian ); //return new audioformat(audioformat.encoding.pcm_signed, 8000.0f, 8, 1, 1, 8000.0f, false); }

principally problem seems reading sound info incorrectly.

specifically i'm not sure excerpt supposed mean:

if (tempbuffer[j] > tempbuffer[j+1]) ... tempbuffer[j] - tempbuffer[j+1]; else ... tempbuffer[j + 1] - tempbuffer[j];

but anyhow since recording 16-bit info bytes in byte array aren't meaningful on own. each byte represents 1/2 of bits in each sample. need 'unpack' them int, float, whatever, before can them. raw lpcm, concatenating bytes done shifting them , oring them together.

here mcve demonstrate rudimentary level meter (both rms , simple peak hold) in java.

import javax.swing.swingutilities; import javax.swing.jframe; import javax.swing.jpanel; import javax.swing.jcomponent; import java.awt.borderlayout; import java.awt.graphics; import java.awt.color; import java.awt.dimension; import javax.swing.border.emptyborder; import javax.sound.sampled.audioformat; import javax.sound.sampled.targetdataline; import javax.sound.sampled.audiosystem; import javax.sound.sampled.lineunavailableexception; public class levelmeter extends jcomponent { private int meterwidth = 10; private float amp = 0f; private float peak = 0f; public void setamplitude(float amp) { this.amp = math.abs(amp); repaint(); } public void setpeak(float peak) { this.peak = math.abs(peak); repaint(); } public void setmeterwidth(int meterwidth) { this.meterwidth = meterwidth; } @override protected void paintcomponent(graphics g) { int w = math.min(meterwidth, getwidth()); int h = getheight(); int x = getwidth() / 2 - w / 2; int y = 0; g.setcolor(color.light_gray); g.fillrect(x, y, w, h); g.setcolor(color.black); g.drawrect(x, y, w - 1, h - 1); int = math.round(amp * (h - 2)); g.setcolor(color.green); g.fillrect(x + 1, y + h - 1 - a, w - 2, a); int p = math.round(peak * (h - 2)); g.setcolor(color.red); g.drawline(x + 1, y + h - 1 - p, x + w - 1, y + h - 1 - p); } @override public dimension getminimumsize() { dimension min = super.getminimumsize(); if(min.width < meterwidth) min.width = meterwidth; if(min.height < meterwidth) min.height = meterwidth; homecoming min; } @override public dimension getpreferredsize() { dimension pref = super.getpreferredsize(); pref.width = meterwidth; homecoming pref; } @override public void setpreferredsize(dimension pref) { super.setpreferredsize(pref); setmeterwidth(pref.width); } public static void main(string[] args) { swingutilities.invokelater(new runnable() { @override public void run() { jframe frame = new jframe("meter"); frame.setdefaultcloseoperation(jframe.exit_on_close); jpanel content = new jpanel(new borderlayout()); content.setborder(new emptyborder(25, 50, 25, 50)); levelmeter meter = new levelmeter(); meter.setpreferredsize(new dimension(9, 100)); content.add(meter, borderlayout.center); frame.setcontentpane(content); frame.pack(); frame.setlocationrelativeto(null); frame.setvisible(true); new thread(new recorder(meter)).start(); } }); } static class recorder implements runnable { final levelmeter meter; recorder(final levelmeter meter) { this.meter = meter; } @override public void run() { audioformat fmt = new audioformat(44100f, 16, 1, true, false); final int bufferbytesize = 2048; targetdataline line; seek { line = audiosystem.gettargetdataline(fmt); line.open(fmt, bufferbytesize); } catch(lineunavailableexception e) { system.err.println(e); return; } byte[] buf = new byte[bufferbytesize]; float[] samples = new float[bufferbytesize / 2]; float lastpeak = 0f; line.start(); for(int b; (b = line.read(buf, 0, buf.length)) > -1;) { // convert bytes samples here for(int = 0, s = 0; < b;) { int sample = 0; sample |= buf[i++] & 0xff; // (reverse these 2 lines sample |= buf[i++] << 8; // if format big endian) // normalize range of +/-1.0f samples[s++] = sample / 32768f; } float rms = 0f; float peak = 0f; for(float sample : samples) { float abs = math.abs(sample); if(abs > peak) { peak = abs; } rms += sample * sample; } rms = (float)math.sqrt(rms / samples.length); if(lastpeak > peak) { peak = lastpeak * 0.875f; } lastpeak = peak; setmeteronedt(rms, peak); } } void setmeteronedt(final float rms, final float peak) { swingutilities.invokelater(new runnable() { @override public void run() { meter.setamplitude(rms); meter.setpeak(peak); } }); } } }

note format conversion hard-coded there.

you may see "how utilize sound sample info java sound?" detailed explanation of how unpack sound info raw bytes.

related:

how maintain track of sound playback position? how create waveform rendering more interesting?

java audio javasound javax.sound.sampled

No comments:

Post a Comment