gstreamer read decibel from buffer - audio

I am trying to get the dB level of incoming audio samples. On every video frame, I update the dB level and draw a bar representing a 0 - 100% value (0% being something arbitrary such as -20.0dB and 100% being 0dB.)
gdouble sum, rms;
sum = 0.0;
guint16 *data_16 = (guint16 *)amap.data;
for (gint i = 0; i < amap.size; i = i + 2)
{
gdouble sample = ((guint16)data_16[i]) / 32768.0;
sum += (sample * sample);
}
rms = sqrt(sum / (amap.size / 2));
dB = 10 * log10(rms);
This was adapted to C from a code sample, marked as the answer, from here. I am wondering what it is that I am missing from this very simple equation.
Answered: jacket was correct about the code loosing the sign, so everything ended up being positive. Also the code 10 * log(rms) is incorrect. It should be 20 * log(rms) as I am converting amplitude to decibels (as a measure of outputted power).

The level element is best for this task (as #ensonic already mentioned) its intended for exactly what you need..
So basically you add to your pipe element called "level", then enable the messages triggering.
Level element then emits messages which contains values of RMS Peak and Decay. RMS is what you need.
You can setup callback function connected to such message event:
audio_level = gst_element_factory_make ("level", "audiolevel");
g_object_set(audio_level, "message", TRUE, NULL);
...
g_signal_connect (bus, "message::element", G_CALLBACK (callback_function), this);
bus variable is of type GstBus.. I hope you know how to work with buses
Then in callback function check for the element name and get the RMS like is described here
There is also normalization algorithm with pow() function to convert to value between 0.0 -> 1.0 which you can use to convert to % as you stated in your question.

Related

Redhawk FEI sample rate tolerance check failure?

I'm building a Redhawk 2.1.2 FEI device and encountering a tolerance check failure when I try to do an allocation through the IDE (haven't tried python interface or anything). The request is for 8 MHz and I get a return value of 7999999.93575246725231409 Hz which is waaaay within the 20% tolerance, but I still get this error:
2017-12-24 11:27:10 DEBUG FrontendTunerDevice:484 - allocateCapacity - SR requested: 8000000.000000 SR got: 7999999.935752
2017-12-24 11:27:10 INFO FrontendTunerDevice:490 - allocateCapacity(0): returned sr 7999999.935752 does not meet tolerance criteria of 20.000000 percent
The offending code from frontendInterfaces/libsrc/cpp/fe_tuner_device.cpp:
// check tolerances
if( (floatingPointCompare(frontend_tuner_allocation.sample_rate,0)!=0) &&
(floatingPointCompare(frontend_tuner_status[tuner_id].sample_rate,frontend_tuner_allocation.sample_rate)<0 ||
floatingPointCompare(frontend_tuner_status[tuner_id].sample_rate,frontend_tuner_allocation.sample_rate+frontend_tuner_allocation.sample_rate * frontend_tuner_allocation.sample_rate_tolerance/100.0)>0 ))
{
std::ostringstream eout;
eout<<std::fixed<<"allocateCapacity("<<int(tuner_id)<<"): returned sr "<<frontend_tuner_status[tuner_id].sample_rate<<" does not meet tolerance criteria of "<<frontend_tuner_allocation.sample_rate_tolerance<<" percent";
LOG_INFO(FrontendTunerDevice<TunerStatusStructType>, eout.str());
throw std::logic_error(eout.str().c_str());
}
And the function from frontendInterfaces/libsrc/cpp/fe_tuner_device.h:
inline double floatingPointCompare(double lhs, double rhs, size_t places = 1){
return round((lhs-rhs)*pow(10,places));
/*if(round((lhs-rhs)*(pow(10,places))) == 0)
return 0; // equal
if(lhs<rhs)
return -1; // lhs < rhs
return 1; // lhs > rhs*/
}
I actually copied into a non-Redhawk C++ program that I use to test the devices interfaces and the checks pass. I broke everything out to find the difference and noticed that in Redhawk the sample rate being returned from the Device (or at least printed to the screen) is slightly different than the one outside Redhawk - by like a tiny fraction of a Hz:
// in Redhawk using cout::precision(17)
Sample Rate: 7999999.93575246725231409
// outside Redhawk using cout::precision(17)
Sample Rate: 7999999.96948242187500000
I don't know why there's a difference in the actual sample rates returned but in the Redhawk version it's just enough to make the second part of the check fail:
floatingPointCompare(7999999.93575246725231409,8000000.00000000000000000)<0
1
Basically because:
double a = 7999999.93575246725231409 - 8000000.00000000000000000; // = -0.06424753274768591
double b = pow(10,1); // = 10.00000000000000000
double c = a*b; // = -0.6424753274
double d = round(c); // = -1.00000000000000000
So if a returned sample rate is less than the request by more than 0.049999 Hz then it will fail the allocation regardless of the tolerance %? Maybe I'm just missing something here.
The tolerance checks are specified to be the minimum amount plus a delta and not a variance (plus or minus) from the requested amount.
There should be a document somewhere that describes this in detail but I went to the FMRdsSimulator device's source.
// For FEI tolerance, it is not a +/- it's give me this or better.
float minAcceptableSampleRate = request.sample_rate;
float maxAcceptableSampleRate = (1 + request.sample_rate_tolerance/100.0) * request.sample_rate;
So that should explain why the allocation was failing.

How do I publish multiple pieces of BLE characteristic data using bleno

I'm trying to learn how to implement a BLE peripheral device using bleno. I would like to discover and read from the peripheral using noble. For example sake, I want to know how I would implement a simple smart scale that reports back weight, BMI etc following the Weight Measurement GATT spec.
What I can't figure out is if reading multiple pieces of information from a characteristic is possible. The Weight Measurement GATT spec makes it seem like in a single noble characteristic.read() you can simultaneously retrieve Weight, BMI, Height etc.
For example, this simple bleno characteristic:
'use strict';
const bleno = require('bleno');
const flags = {
IMPERIAL_WEIGHT: 1 << 0,
USER_ID_PRESENT: 1 << 2,
BMI_AND_HEIGHT_PRESENT: 1 << 3
};
module.exports.flags = flags;
module.exports.WeightMeasureCharacteristic = class WeightMeasureCharacteristic extends bleno.Characteristic {
constructor(scale) {
super({
uuid: '2A9D',
properties: ['read'],
descriptors: []
});
this._scale = scale;
}
onReadRequest(offset, callback) {
//Not sure what `offset` means here or how it gets populated...Help!
let data = new Buffer.alloc(8); //1(flags)+2(weightImp)+1(userId)+2(BMI)+2(heightImp)
//Write supported value fields as bit flags
data.writeUInt8(flags.IMPERIAL_WEIGHT | flags.USER_ID_PRESENT | flags.BMI_AND_HEIGHT_PRESENT), 0);
//Write out weight (lbs) - offset 1 byte
data.writeUInt16LE(100.01, 1);
//Write out user id - offset 12 bytes (flags+Imperial, no need to include offset for SI or Timestamp since the flags indicated those are not supported)
data.writeUInt8(69, 3);
//Write out BMI - offset 13 bytes (after UserId)
data.writeUInt16LE(18.6, 4);
//Write out Height Imperial - offset 17 bytes (after Height SI)
data.writeUInt16LE(72.2, 6);
callback(this.RESULT_SUCCESS, data);
}
}
If someone was able to implement/pseudocode onReadRequest() above I think it would help things click in my head.
Questions:
Does the C<number> value in the "Field Requirement" column of the spec indicate the offset value passed into onReadRequest()? If a consumer wanted to get "Weight - SI"(C1) they would somehow construct a noble characteristic.read() that triggers an onReadRequest(1,function())? If so, how is the characteristic.read() constructed?
How do I construct a noble characteristic.read() to get the value of the Flags?
How do I construct a noble characteristic.read() that will return me multiple (or all) properties in one read? Ex: Give me all values this peripheral supports (Weight - SI, BMI etc).
If my peripheral supports imperial weight, user id, bmi, and height how do I populate the data for the callback in onReadRequest(). Is what I have above correct?
How is offset populated & what does it mean in onReadRequest(offset,callback)?
Or, am I doing this all wrong? Should I have a characteristic for each value? Ex: a single characteristic for weight - SI, and another characteristic for BMI? I would like to avoid this, would prefer to save round trips and get multiple values in one call.
An attempt to answer your question:
I am not sure what the C<number> means, but I believe that each field (Weight, BMI, Height, etc.) is represented as a group of one or more octets. Notice how at the bottom of the spec it says
Note: The fields in the above table are in the order of LSO to MSO.
Where LSO = Least Significant Octet and MSO = Most Significant Octet.
Thus, I believe that in order to get the "Weight - SI" field, you would do something like:
characteristic.read((err, data) => {
let char_flags = data.readUint8(0); // read first bit
if (!(char_flags & flags.IMPERIAL_WEIGHT)) // if SI weight
let weightSI = data.readUint16LE(1) // read SI weight starting at second bit
});
Answered above
Answered above, just check whether the property exists in the flags and then read the value from the appropriate offset. Also this might help.
Answered above.

Does Phaser Arcade.Body velocity include deltaTime or not?

I want to move my character along the x axis with constantly speed. I thought move depends on frame rate. So, technically I should write
sprite.body.velocity.x = speed * deltaTime
where deltaTime = game.time.elapsedMS / 1000;
But if I'm doing that - my character moves vvvvverrry slooow, even if speed = 1000.
But if I'm writing
sprite.body.velocity.x = speed
it works fine. My fps = 60;
Phaser Documentation
says:
velocity - The velocity, or rate of change in speed of
the Body. Measured in pixels per second.
no deltatime....
and all demos do not have deltatime
http://phaser.io/examples/v2/arcade-physics/platformer-basics
http://phaser.io/examples/v2/arcade-physics/asteroids-movement
etc.
So, I don't understand: shoud I calculate deltaTime or just use velocity.x?
Well.... I think I'm stupid...
My calculation of the deltaTime was wrong
The correct formula will be
deltaTime = (elapsedMS * fps) / 1000
elapsedMS - The time in ms since the last time update, in milliseconds, based on time.
fps - Frames per second.
(Only calculated if advancedTiming is enabled).
So, that was my problem.
As the result
body.velocity doesn't include calculation of deltaTime and for smooth movement should use deltaTime that calculated by the formula above.
And it will be something like that
function update() { // <-- it is phaser state method...is called every frame
deltaTime = (elapsedMS * fps) / 1000;
sprite.body.velocity.x = velocityX * deltaTime;
sprite.body.velocity.y = velocityY * deltaTime;
}

Where can i find a simple filterbank BP/wavelet filter function, in C#/JS?

I am searching for a filter function which inputs an audio signal (a float[]) and returns the amplitude of the audio signal at a given frequency, i.e.:
void WAVELET (float In , float Freq ):float
{
out = in * coefficients*a1*b1*c1*d1/Freq;
return in;
}
void MAKE_SPECTROGRAM2D(float[] stream)
{
for (var bands = 0, bands < 1024 , bands++)
for (var i = 0, i < AudioStream.Length , i++)
var spectrogram2D[i,j] = WAVELET(AudioStream[i] , bands*22050/1024)
}
I have found some wavelet transformation projects (i.e. 1 and 2). It's very confusing trying to understand the codes. Wavelets seem to be much different to audio filters. A kind of bandpass filter for audio analysis would be fine. I can only find collections of difficult functions that have matrix transformations and seem to be not destined to input an array of data. I haven't managed to find filterbank audio filter functions online. i am simply confused, some information would be very helpful.

How do I attenuate a WAV file by a given decibel value?

If I wanted to reduce a WAV file's amplitude by 25%, I would write something like this:
for (int i = 0; i < data.Length; i++)
{
data[i] *= 0.75;
}
A lot of the articles I read on audio techniques, however, discuss amplitude in terms of decibels. I understand the logarithmic nature of decibel units in principle, but not so much in terms of actual code.
My question is: if I wanted to attenuate the volume of a WAV file by, say, 20 decibels, how would I do this in code like my above example?
Update: formula (based on Nils Pipenbrinck's answer) for attenuating by a given number of decibels (entered as a positive number e.g. 10, 20 etc.):
public void AttenuateAudio(float[] data, int decibels)
{
float gain = (float)Math.Pow(10, (double)-decibels / 20.0);
for (int i = 0; i < data.Length; i++)
{
data[i] *= gain;
}
}
So, if I want to attenuate by 20 decibels, the gain factor is .1.
I think you want to convert from decibel to gain.
The equations for audio are:
decibel to gain:
gain = 10 ^ (attenuation in db / 20)
or in C:
gain = powf(10, attenuation / 20.0f);
The equations to convert from gain to db are:
attenuation_in_db = 20 * log10 (gain)
If you just want to adust some audio, I've had good results with the normalize package from nongnu.org. If you want to study how it's done, the source code is freely available. I've also used wavnorm, whose home page seems to be out at the moment.
One thing to consider: .WAV files have MANY different formats. The code above only works for WAVE_FORMAT_FLOAT. If you're dealing with PCM files, then your samples are going to be 8, 16, 24 or 32 bit integers (8 bit PCM uses unsigned integers from 0..255, 24 bit PCM can be packed or unpacked (packed == 3 byte values packed next to each other, unpacked == 3 byte values in a 4 byte package).
And then there's the issue of alternate encodings - For instance in Win7, all the windows sounds are actually MP3 files in a WAV container.
It's unfortunately not as simple as it sounds :(.
Oops I misunderstood the question… You can see my python implementations of converting from dB to a float (which you can use as a multiplier on the amplitude like you show above) and vice-versa
https://github.com/jiaaro/pydub/blob/master/pydub/utils.py
In a nutshell it's:
10 ^ (db_gain / 10)
so to reduce the volume by 6 dB you would multiply the amplitude of each sample by:
10 ^ (-6 / 10) == 10 ^ (-0.6) == 0.2512

Resources