get sample instance actual amplitude (volume)
wootrop

hello! :D i'm new in the fantastic world of allegro! For exercise, i'm making a little sample player (like a keyboard drum).

I'd like to show each sample volume intensity with a rectangle that modify his height with the amplitude of the sample. Like a real time v-meter of the sample.

There is some function (al_get_sample_instance_amplitude?) that return with the volume of the sample? (not the gain)

Thank you so much!! ;D I will really appreciate your help!
(sorry for my bad english, i'm italian)

SiegeLord

Use al_get_sample_data to get at the actual waveform (use al_get_sample_instance_position to see where it is playing currently and al_get_sample_depth and al_get_sample_channels to see what format the waveform data is in).

wootrop

thank you SiegeLord!!! But i can't make it work! Can you show me an example? thank you so much! :)

SiegeLord

Here's a sample program. To get the volume it computes the root mean square over several milliseconds. You'll want to actually implement the get_wave_power function to handle various audio formats and channel numbers. I've attached a test sound that the code works on.

#SelectExpand
1#include <allegro5/allegro.h> 2#include <allegro5/allegro_audio.h> 3#include <allegro5/allegro_acodec.h> 4#include <math.h> 5#include <stdio.h> 6 7float get_wave_power(ALLEGRO_SAMPLE* spl, unsigned int pos) 8{ 9 /* Handle more formats and channels */ 10 assert(al_get_sample_depth(spl) == ALLEGRO_AUDIO_DEPTH_INT16); 11 assert(al_get_sample_channels(spl) == ALLEGRO_CHANNEL_CONF_1); 12 return float(((short*)al_get_sample_data(spl))[pos]) / 32767.0f; 13} 14 15int main() 16{ 17 al_init(); 18 al_install_audio(); 19 al_reserve_samples(1); 20 al_init_acodec_addon(); 21 22 ALLEGRO_SAMPLE* sample = al_load_sample("test.ogg"); 23 assert(sample); 24 ALLEGRO_SAMPLE_INSTANCE* inst = al_create_sample_instance(sample); 25 al_attach_sample_instance_to_mixer(inst, al_get_default_mixer()); 26 al_play_sample_instance(inst); 27 28 while(al_get_sample_instance_playing(inst)) 29 { 30 al_rest(0.1); 31 unsigned int pos = al_get_sample_instance_position(inst); 32 float rms = 0; 33 const float seconds_to_average = 0.05f; 34 const int samples_to_average = (int)(al_get_sample_frequency(sample) * seconds_to_average); 35 unsigned int start; 36 if(pos < samples_to_average) 37 start = 0; 38 else 39 start = pos - samples_to_average; 40 41 for(unsigned int ii = start; ii < pos; ii++) 42 { 43 float power = get_wave_power(sample, ii); 44 rms += power * power; 45 } 46 rms = sqrt(rms / (pos - start)); 47 printf("Volume: %d%%\n", (int)(100 * rms)); 48 } 49 50 return 0; 51}

wootrop

Great!!! Now i'm not at home but i will try the code when possible and then i will inform you! :)

Dizzy Egg

Nice one!

wootrop

Wow very good!!!! ;D you must implement this function to allegro library! :) one question, what is the formula that you used? (What is the 32767.0f number?) thank you SiegeLord!! 8-) i will post my exercise code when i've implemented a general formula for this! :-*

SiegeLord
wootrop said:

What is the 32767.0f number?

It's implied by ALLEGRO_AUDIO_DEPTH_INT16. Look at ALLEGRO_AUDIO_DEPTH. Here's a link for RMS: http://en.wikipedia.org/wiki/Root_mean_square . I used RMS since it seemed a reasonable thing to use as a proxy to volume. In a real application it's also probably best to high pass filter the data before computing the RMS so you don't get a positive RMS for non-zero silence.

wootrop

There are some issues in Allegro 5.0.7 audio functions i think:

Info source: Adobe Audition
File: test.wav
Sample Rate (sample_frequency): 48000Hz
Channels (sample_channels): Mono
Bit Depth (sample_depth): 16-bits

Info source: Allegro 5.0.7
File: test.wav
al_get_sample_frequency (sample rate): 48000
al_get_sample_channels: 32(?)
al_get_sample_depth: 1(?)

--------------------------------------

Info source: Adobe Audition
File: test_stereo.wav
Sample Rate (sample_frequency): 48000Hz
Channels (sample_channels): Stereo
Bit Depth (sample_depth): 16-bits

Info source: Allegro 5.0.7
File: test_stereo.wav
al_get_sample_frequency (sample rate): 48000
al_get_sample_channels: 32(?)
al_get_sample_depth: 1(?)

IDLE: Codeblocks 10.05
Compiler: Mingw 4.6.1 tdm
Allegro Version: allegro-5.0.7-mingw-4.6.1-tdm
Allegro Audio Version: 83887873

EDIT
Anyway my interest is only to get the actual amplitude of the waveform, and not the RMS, so thanks to SiegeLord i edit his function to get only the amplitude:

#SelectExpand
1float get_sample_amplitude (ALLEGRO_SAMPLE *sample, int position) 2{ 3 // Return a float value from 0 to 1. 4 short *spl_data = (short*)al_get_sample_data(sample); 5 return float(sqrt(pow(spl_data[position], 2))/32768.0f); 6}

Use:
get_sample_amplitude(sample, al_get_sample_instance_position(sample_instance);

So this is my demo:

{"name":"spep.jpg","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/c\/d\/cdc3f9e5d9d16d5562484104d0703d71.jpg","w":1366,"h":768,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/c\/d\/cdc3f9e5d9d16d5562484104d0703d71"}spep.jpg
Download attached file 7z file for source and exe!

SiegeLord
wootrop said:

al_get_sample_channels: 32(?)
al_get_sample_depth: 1(?)

Read the docs for those functions. They don't return values whose numerical interpretation is meaningful.

Also...
sqrt(pow(spl_data[position], 2)) is exactly equal to just spl_data[position].

wootrop

Ok, so i will read the documentation! ;)

SiegeLord said:

sqrt(pow(spl_data[position], 2)) is exactly equal to just spl_data[position].

Isn't the same thing, because i get a positive value with the pow, and then i make a square root to get back the original value. Result: absolute value. (i've just now discovered the abs function :P) so this is more correct:

#SelectExpand
1float get_sample_peak (ALLEGRO_SAMPLE *sample, int position) 2{ 3 // Return a float value from 0 to 1. 4 short *spl_data = (short*)al_get_sample_data(sample); 5 return float(abs(spl_data[position])/32768.0f); 6}

EDIT Sorry I have another question... Why my program compiled with Codeblocks and Mingw take up more space (about 500kb) and compiled with VC2010 is only about 100kb? (are both dinamic linked)

Codeblocks Release settings: liballegro-5.0.7-monolith-mt.a (to the linker) and -s (Strip all symbols from binary (minimizes size)) and -O3 (Optimize fully (for speed))

Visual Studio 2010 Release settings: allegro-5.0.7-monolith-mt.lib (to the linker) and generation code is setted to /MT (multithread).

EDIT2
All right, for minimize size on windows you must compile your programs with VC compiler (also on codeblocks) :)

Thread #610890. Printed from Allegro.cc