Android Question How to Get dB and Hz from Buffer (AudioStreamer)

abbas abedi

Member
Hi
I used AudioStreamer for get stream voice as Live and how can I Get Buffer byte info ?
for example like dB volume or Hz or dB of any Hz
unnamed.jpg
 

abbas abedi

Member
I used this code for dB but I think dont work correctly

B4X:
Sub streamer_RecordBuffer (Buffer() As Byte)

    Dim Sum As Int

    For i = 0 To 480 Step 2           
        Sum=Sum+(Buffer(i)*256)+Buffer(i+1)
    Next

    Sum=Sum/240+(32767/2)
    Sum=20*Logarithm(Sum/32767,10)
    
    Log("dB " & Sum )

End Sub
 
Upvote 0

JordiCP

Expert
Licensed User
Longtime User
dB is a logarithmic measure of power, usually relative (for instance, the gain of an amplifier) or 'absolute' when you reference it to a given unit (for instance dBm, when you compare a given electric power refered to a miliwatt)

The difference between them is only an additive factor, which is the reference

In your calculation, if buffer contains a wave amplitude which can take both positive and negative values, these values must always be squared (power is proportional to the square of the amplitude), otherwise the resulting sum could be null.

also, when calculating dBs from a dynamic input, which I guess is the case, the way to proceed is by a sliding a time window and/or time segments which include N samples.

hope it helps 🙂
 
Upvote 0

kimstudio

Active Member
Licensed User
Longtime User
Byte in B4A is signed, so this (Buffer(i)*256)+Buffer(i+1) to convert byte to short is not correct. ByteConverter lib can solve this.

As converted short also signed, calculate mean value will almost always get zero. We can get the max absolute value of this buffer and use
db=20*Logarithm(max(abs(buffer short))/32768,10) to get db. If mean is prefered then db=20*Logarithm(mean(abs(buffer short))/32768,10).

Also, sum should be defined as double, not int.
 
Upvote 0

emexes

Expert
Licensed User
I feel like audio level (power?) would be proportional to the average difference between sample values in a block of audio (or perhaps the square of that).

If you take the simple maximum or high-low sample value of range of a block of audio, then high frequency energy will probably be hidden by lower frequency energy.

Having said that, I am scouring the internet for some actual code based on more than just feeling.
 
Upvote 0

emexes

Expert
Licensed User
Having said that, I am scouring the internet for some actual code based on more than just feeling.
Well that was harder to find than you'd think. Closest I got was:

https://stackoverflow.com/questions...he-level-amplitude-db-of-audio-signal-in-java

which also now has me wondering whether your sixteen-bit samples are big-endian or little-endian; two's-complement or sign+magnitude or offset; and mono or stereo?

Anyway, once you've got the sample values correctly interpreted, that code then normalises the samples to +/- 1.0, then does a rms average, from which you can then do the "20 * log10(rms) + 0 dB offset" conversion.
 
Upvote 0

abbas abedi

Member
Well that was harder to find than you'd think. Closest I got was:

https://stackoverflow.com/questions...he-level-amplitude-db-of-audio-signal-in-java

which also now has me wondering whether your sixteen-bit samples are big-endian or little-endian; two's-complement or sign+magnitude or offset; and mono or stereo?

Anyway, once you've got the sample values correctly interpreted, that code then normalises the samples to +/- 1.0, then does a rms average, from which you can then do the "20 * log10(rms) + 0 dB offset" conversion.
excellent, could you please convert Java codes to b4a ?
 
Upvote 0

emexes

Expert
Licensed User
excellent, could you please convert Java codes to b4a ?
Sure, I've got a few free minutes. 🍻

B4X:
'convert audio bytes to Shorts (16-bit signed integers -32768..32767)

Dim bc As ByteConverter
'''bc.LittleEndian = True / False   'depending on your data, eg: [URL]https://www.nicklandis.com/blog/little-endian-vs-big-endian[/URL]
Dim samples() As Short = bc.ShortsFromBytes(AudioBytes())

Dim rms As Double = 0
Dim peak As Float = 0

For I = 0 to samples.length - 1
    Dim ThisSample As Float = samples(I) / 32768.0    'normalise to +/- 1.0
   
    Dim AbsSample = Abs(ThisSample)
    If AbsSample > peak then
        peak = AbsSample
    End If
   
    rms = rms + ThisSample * ThisSample
Next

rms = Sqrt(rms)

If LastPeak > Peak Then    'not sure about this re: * 0.875
    Peak = LastPeak * 0.875
End If
LastPeak = Peak

'in fact, that whole peak thing should probably just be based on rms value

'this would be your department:
'setMeterOnEDT(rms, peak);

from original code at https://stackoverflow.com/questions...he-level-amplitude-db-of-audio-signal-in-java
Java:
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 to samples here
    for(int i = 0, s = 0; i < b;) {
        int sample = 0;

        sample |= buf[i++] & 0xFF; // (reverse these two lines
        sample |= buf[i++] << 8;   //  if the format is big endian)

        // normalize to 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);
 
Last edited:
Upvote 0

kimstudio

Active Member
Licensed User
Longtime User
Typo: ThisSample = Sample?

This makes the peak bar (line) in UI drops down gradually:
If LastPeak > Peak Then 'not sure about this re: * 0.875
Peak = LastPeak * 0.875
End If
LastPeak = Peak

If the DB number is really needed as title says instead of a general volume meter, suggest to use the formulas I provided... or I think the above code by emexes is totally fine.
If you want Hz, search FFT lib in forum.
 
Upvote 0

emexes

Expert
Licensed User
This makes the peak bar (line) in UI drops down gradually:
B4X:
If LastPeak > Peak Then    'not sure about this re: * 0.875
    Peak = LastPeak * 0.875
End If
LastPeak = Peak
I feel that it will act oddly if Peak is inside the range of LastPeak * 0.875 to LastPeak

but I suspect it is a momentary thing that users don't notice or don't care about
 
Upvote 0
Top