libmpg123: Volume control and volume > 1.0 - audio

I have problems understanding how libmpg123 "does" volume control.
Starting with this barebones player code (based on the mpg123 example code using assert() instead of proper error handling for brevity):
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include "mpg123.h"
#include "out123.h"
int main()
{
mpg123_handle * mh;
out123_handle * oh;
long rate;
int channels, encoding;
size_t position, buffer_size;
unsigned char * buffer;
double base, real, rva_db;
assert( mpg123_init() == MPG123_OK );
assert( ( mh = mpg123_new( NULL, NULL ) ) != NULL );
assert( ( oh = out123_new() ) != NULL );
assert( mpg123_open( mh, "Example.mp3" ) == MPG123_OK );
assert( mpg123_getformat( mh, &rate, &channels, &encoding ) == MPG123_OK );
assert( out123_open( oh, NULL, NULL ) == OUT123_OK );
assert( mpg123_format_none( mh ) == MPG123_OK );
assert( mpg123_format( mh, rate, channels, encoding ) == MPG123_OK );
assert( out123_start( oh, rate, channels, encoding ) == OUT123_OK );
buffer_size = mpg123_outblock( mh );
assert( ( buffer = malloc( buffer_size ) ) != NULL );
// vvv THIS PART HERE IS INTERESTING
assert( mpg123_getvolume( mh, &base, &real, &rva_db ) == MPG123_OK );
printf( "Volume: base %lf -- real %lf -- rva_db %lf\n", base, real, rva_db );
// ˆˆˆ THIS PART HERE IS INTERESTING
do
{
mpg123_read( mh, buffer, buffer_size, &position );
out123_play( oh, buffer, position );
} while ( position );
out123_close( oh );
mpg123_close( mh );
out123_del( oh );
mpg123_delete( mh );
mpg123_exit();
}
As is, I get this output (aside from the MP3 playing back):
Volume: base 1.000000 -- real 1.000000 -- rva_db 0.000000
I would interpret that as "playing back at 100% volume".
Now, I can change the volume, both absolute...
mpg123_volume( mh, 0.1 );
mpg123_getvolume( mh, &base, &real, &rva_db );
...and relative...
mpg123_volume_change( mh, -0.9 );
mpg123_getvolume( mh, &base, &real, &rva_db );
...in both cases giving me this output:
Volume: base 0.100000 -- real 0.100000 -- rva_db 0.000000
I would interpret that as "playing at 10% volume", which is consistent with what I am hearing.
If I keep mpg123_volume_change() downward, eventually I get an output of 0.000000 (and no audio). The value does not decrease into the negative.
However, I can still increase the volume beyond 1.0:
mpg123_volume_change( mh, 0.1 );
mpg123_getvolume( mh, &base, &real, &rva_db );
...giving me this output:
Volume: base 1.100000 -- real 1.100000 -- rva_db 0.000000
I have not tried how far this goes, because I am a bit worried about the implications of running my audio output at "over 100%".
What is going on here, what is the actual potential range I am working with here, could I increase the volume to "fry the chips / speakers" levels here by a single mistyped number (I guess not but I do not want to try...), and what is "rva_db" about?

Related

How to get the Free Huge Page Count from a C program?

I'm looking for a function to call from a C program that returns the number of free huge pages.
I've found functions to return the huge page size(s), lots of information on how to use pseudo file system entries, but no man page for a function that returns the same information you get from running:
cat /proc/meminfo | grep '^Huge'
Is there such a thing?
I tried lots of web searches, got lots of information on use of huge pages, but no information on how to write a program that makes a system call to get said information.
This c code will open the file /proc/meminfo and read the values.
Here is output showing 2 Huge values extracted.
Notice that the entire line of text is read from the file. The line buffer here is static but other efforts can modify to buffer the entire file or other approaches for reading file data.
Notice that the sscanf returns number of assignments made by the format specified. The format specified separates the values to match. For example the text "HugePages_Total" must match or no assignments are made.
Good luck!
gcc -o main main.c
./main
HugePages_Total: 0
Hugepagesize: 2048 kB
main.c
// gcc -o main main.c
#include <string.h>
#include <stdio.h>
int main()
{
FILE* fptr = fopen( "/proc/meminfo", "r" );
if ( fptr )
{
while ( !feof( fptr ) )
{
long unsigned number = 10;
char units[10] = {0};
char line[4096] = {0};
fgets(line, sizeof(line), fptr );
if ( sscanf( line, "HugePages_Total: %lu", &number ) == 1 )
{
printf( "HugePages_Total: %lu\n", number );
}
else if ( sscanf( line, "Hugepagesize: %lu %s", &number, units ) == 2 )
{
printf( "Hugepagesize: %lu %s\n", number, units );
continue;
}
}
}
return 0;
}

MPI Reading from a text file

I am learning to program in MPI and I came across this question. Lets say I have a .txt file with 100,000 rows/lines, how do I chunk them for processing by 4 processors? i.e. I want to let processor 0 take care of the processing for lines 0-25000, processor 1 to take care of 25001-50000 and so on. I did some searching and did came across MPI_File_seek but I am not sure can it work on .txt and supports fscanf afterwards.
Text isn't a great format for parallel processing exactly because you don't know ahead of time where (say) line 25001 begins. So these sorts of problems are often dealt with ahead of time through some preprocessing step, either building an index or partitioning the file into the appropriate number of chunks for each process to read.
If you really want to do it through MPI, I'd suggest using MPI-IO to read in overlapping chunks of the text file onto the various processors, where the overlap is much longer than you expect your longest line to be, and then have each processor agree on where to start; eg, you could say that the first (or last) new line in the overlap region shared by processes N and N+1 is where process N leaves off and N+1 starts.
To follow this up with some code,
#include <stdio.h>
#include <mpi.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
void parprocess(MPI_File *in, MPI_File *out, const int rank, const int size, const int overlap) {
MPI_Offset globalstart;
int mysize;
char *chunk;
/* read in relevant chunk of file into "chunk",
* which starts at location in the file globalstart
* and has size mysize
*/
{
MPI_Offset globalend;
MPI_Offset filesize;
/* figure out who reads what */
MPI_File_get_size(*in, &filesize);
filesize--; /* get rid of text file eof */
mysize = filesize/size;
globalstart = rank * mysize;
globalend = globalstart + mysize - 1;
if (rank == size-1) globalend = filesize-1;
/* add overlap to the end of everyone's chunk except last proc... */
if (rank != size-1)
globalend += overlap;
mysize = globalend - globalstart + 1;
/* allocate memory */
chunk = malloc( (mysize + 1)*sizeof(char));
/* everyone reads in their part */
MPI_File_read_at_all(*in, globalstart, chunk, mysize, MPI_CHAR, MPI_STATUS_IGNORE);
chunk[mysize] = '\0';
}
/*
* everyone calculate what their start and end *really* are by going
* from the first newline after start to the first newline after the
* overlap region starts (eg, after end - overlap + 1)
*/
int locstart=0, locend=mysize-1;
if (rank != 0) {
while(chunk[locstart] != '\n') locstart++;
locstart++;
}
if (rank != size-1) {
locend-=overlap;
while(chunk[locend] != '\n') locend++;
}
mysize = locend-locstart+1;
/* "Process" our chunk by replacing non-space characters with '1' for
* rank 1, '2' for rank 2, etc...
*/
for (int i=locstart; i<=locend; i++) {
char c = chunk[i];
chunk[i] = ( isspace(c) ? c : '1' + (char)rank );
}
/* output the processed file */
MPI_File_write_at_all(*out, (MPI_Offset)(globalstart+(MPI_Offset)locstart), &(chunk[locstart]), mysize, MPI_CHAR, MPI_STATUS_IGNORE);
return;
}
int main(int argc, char **argv) {
MPI_File in, out;
int rank, size;
int ierr;
const int overlap = 100;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
if (argc != 3) {
if (rank == 0) fprintf(stderr, "Usage: %s infilename outfilename\n", argv[0]);
MPI_Finalize();
exit(1);
}
ierr = MPI_File_open(MPI_COMM_WORLD, argv[1], MPI_MODE_RDONLY, MPI_INFO_NULL, &in);
if (ierr) {
if (rank == 0) fprintf(stderr, "%s: Couldn't open file %s\n", argv[0], argv[1]);
MPI_Finalize();
exit(2);
}
ierr = MPI_File_open(MPI_COMM_WORLD, argv[2], MPI_MODE_CREATE|MPI_MODE_WRONLY, MPI_INFO_NULL, &out);
if (ierr) {
if (rank == 0) fprintf(stderr, "%s: Couldn't open output file %s\n", argv[0], argv[2]);
MPI_Finalize();
exit(3);
}
parprocess(&in, &out, rank, size, overlap);
MPI_File_close(&in);
MPI_File_close(&out);
MPI_Finalize();
return 0;
}
Running this on a narrow version of the text of the question, we get
$ mpirun -n 3 ./textio foo.in foo.out
$ paste foo.in foo.out
Hi guys I am learning to 11 1111 1 11 11111111 11
program in MPI and I came 1111111 11 111 111 1 1111
across this question. Lets 111111 1111 111111111 1111
say I have a .txt file with 111 1 1111 1 1111 1111 1111
100,000 rows/lines, how do 1111111 11111111111 111 11
I chunk them for processing 1 11111 1111 111 1111111111
by 4 processors? i.e. I want 22 2 22222222222 2222 2 2222
to let processor 0 take care 22 222 222222222 2 2222 2222
of the processing for lines 22 222 2222222222 222 22222
0-25000, processor 1 to take 22222222 222222222 2 22 2222
care of 25001-50000 and so 2222 22 22222222222 222 22
on. I did some searching and 333 3 333 3333 333333333 333
did came across MPI_File_seek 333 3333 333333 3333333333333
but I am not sure can it work 333 3 33 333 3333 333 33 3333
on .txt and supports fscanf 33 3333 333 33333333 333333
afterwards. 33333333333

pthread_cond_timedwait returns one second early

The program below produces this output:
$ ./test_condvar 9000
1343868189.623067126 1343868198.623067126 FIRST
1343868197.623132345 1343868206.623132345 TIMEOUT
1343868205.623190120 1343868214.623190120 TIMEOUT
1343868213.623248184 1343868222.623248184 TIMEOUT
1343868221.623311549 1343868230.623311549 TIMEOUT
1343868229.623369718 1343868238.623369718 TIMEOUT
1343868237.623428856 1343868246.623428856 TIMEOUT
Note that reading across rows shows a time delta of the intended 9 seconds, but reading down columns show that pthread_cond_timedwait returns ETIMEDOUT in 8 seconds.
pthread lib is glibc 2.12. running Red Hat EL6. uname -a shows 2.6.32-131.12.1.el6.x86_64 #1 SMP Tue Aug 23 11:13:45 CDT 2011 x86_64 x86_64 x86_64 GNU/Linux
it looks like pthread_cond_timedwait relies on lll_futex_timed_wait for the timeout behavior.
Any ideas on where else to search for an explanation?
#include <time.h>
#include <sys/time.h>
#include <pthread.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
int main ( int argc, char *argv[] )
{
pthread_mutexattr_t mtx_attr;
pthread_mutex_t mtx;
pthread_condattr_t cond_attr;
pthread_cond_t cond;
int milliseconds;
const char *res = "FIRST";
if ( argc < 2 )
{
fputs ( "must specify interval in milliseconds", stderr );
exit ( EXIT_FAILURE );
}
milliseconds = atoi ( argv[1] );
pthread_mutexattr_init ( &mtx_attr );
pthread_mutexattr_settype ( &mtx_attr, PTHREAD_MUTEX_NORMAL );
pthread_mutexattr_setpshared ( &mtx_attr, PTHREAD_PROCESS_PRIVATE );
pthread_mutex_init ( &mtx, &mtx_attr );
pthread_mutexattr_destroy ( &mtx_attr );
#ifdef USE_CONDATTR
pthread_condattr_init ( &cond_attr );
if ( pthread_condattr_setclock ( &cond_attr, CLOCK_REALTIME ) != 0 )
{
fputs ( "pthread_condattr_setclock failed", stderr );
exit ( EXIT_FAILURE );
}
pthread_cond_init ( &cond, &cond_attr );
pthread_condattr_destroy ( &cond_attr );
#else
pthread_cond_init ( &cond, NULL );
#endif
for (;;)
{
struct timespec now, ts;
clock_gettime ( CLOCK_REALTIME, &now );
ts.tv_sec = now.tv_sec + milliseconds / 1000;
ts.tv_nsec = now.tv_nsec + (milliseconds % 1000) * 1000000;
if (ts.tv_nsec > 1000000000)
{
ts.tv_nsec -= 1000000000;
++ts.tv_sec;
}
printf ( "%ld.%09ld %ld.%09ld %s\n", now.tv_sec, now.tv_nsec,
ts.tv_sec, ts.tv_nsec, res );
pthread_mutex_lock ( &mtx );
if ( pthread_cond_timedwait ( &cond, &mtx, &ts ) == ETIMEDOUT )
res = "TIMEOUT";
else
res = "OTHER";
pthread_mutex_unlock ( &mtx );
}
}
There was a Linux kernel bug triggered by the insertion of a leap second on July 1st this year, which resulted in futexes expiring one second too early until either the machine was rebooted or you ran the workaround:
# date -s "`date`"
It sounds like you've been bitten by that.
I'm not sure that this is related to the specific issue but your line:
if (ts.tv_nsec > 1000000000)
should really be:
if (ts.tv_nsec >= 1000000000)
And, in fact, if you do something unexpected and pass in 10000 (for example), you may want to consider making it:
while (ts.tv_nsec >= 1000000000)
though it's probably better at some point to use modulus arithmetic so that loop doesn't run for too long.
Other than that, this appears to be some sort of issue with your environment. The code works fine for me under Debian, Linux MYBOX 2.6.32-5-686 #1 SMP Sun May 6 04:01:19 UTC 2012 i686 GNU/Linux:
1343871427.442705862 1343871436.442705862 FIRST
1343871436.442773672 1343871445.442773672 TIMEOUT
1343871445.442832158 1343871454.442832158 TIMEOUT
:
One possibility is the fact that the system clock is not sacrosanct - it may be modified periodically by NTP or other time synchronisation processes. I mention that as a possibility but it seems a little strange that it would happen in the short time between the timeout and getting the current time.
One test would be to use a different timeout (such as alternating seven and thirteen seconds) to see if the effect is the same (those numbers were chosen to be prime and unlikely to be a multiple of any other activity on the system.

libsndfile usage joining and mixing .wav files

I need help getting started with libsndfile.
I have four .wav files (all the same sample rate).
I want to join the first two together,then the next two together,
Then mix the resulting 2 .wav files into one.
For mixing two wav files.
#include <cstdio>
#include <sndfile.h>
#include <windows.h>
#include <cstdlib>
#include <cmath>
#define BUFFER_LEN 1024
#define MAX_CHANNELS 6
static void data_processing (double *data, int count, int channels) ;
int main (void) {
static double data [BUFFER_LEN] ;
static double data2 [BUFFER_LEN] ;
static double outdata [BUFFER_LEN] ;
SNDFILE *infile, *outfile, *infile2 ;
SF_INFO sfinfo ;
int readcount ;
SF_INFO sfinfo2 ;
int readcount2 ;
const char *infilename = "inputOne.wav" ;
const char *infilename2 = "inputTwo.wav" ;
const char *outfilename = "output.wav" ;
if (! (infile = sf_open (infilename, SFM_READ, &sfinfo))) {
/* Open failed so print an error message. */
printf ("Not able to open input file %s.\n", infilename) ;
/* Print the error message from libsndfile. */
puts (sf_strerror (NULL)) ;
return 1 ;
} ;
if (sfinfo.channels > MAX_CHANNELS) {
printf ("Not able to process more than %d channels\n", MAX_CHANNELS) ;
return 1 ;
} ;
if (! (infile2 = sf_open (infilename2, SFM_READ, &sfinfo2))) {
/* Open failed so print an error message. */
printf ("Not able to open input file %s.\n", infilename2) ;
/* Print the error message from libsndfile. */
puts (sf_strerror (NULL)) ;
return 1 ;
} ;
if (sfinfo2.channels > MAX_CHANNELS) {
printf ("Not able to process more than %d channels\n", MAX_CHANNELS) ;
return 1 ;
} ;
/* Open the output file. */
if (! (outfile = sf_open (outfilename, SFM_WRITE, &sfinfo))) {
printf ("Not able to open output file %s.\n", outfilename) ;
puts (sf_strerror (NULL)) ;
return 1 ;
} ;
while ((readcount = sf_read_double (infile, data, BUFFER_LEN)) &&
(readcount2 = sf_read_double (infile2, data2, BUFFER_LEN))) {
data_processing (data, readcount, sfinfo.channels) ;
data_processing(data2, readcount2, sfinfo2.channels) ;
for(int i=0; i < 1024;++i) {
outdata[i] = (data[i] + data2[i]) -(data[i])*(data2[i])/65535;
}
sf_write_double (outfile, outdata , readcount) ;
} ;
/* Close input and output files. */
sf_close (infile) ;
sf_close (infile2) ;
sf_close (outfile) ;
system("PAUSE");
return 0 ;
} /* main */
static void data_processing(double *data, int count, int channels) {
double channel_gain [MAX_CHANNELS] = { 0.5, 0.8, 0.1, 0.4, 0.4, 0.9 } ;
int k, chan ;
for (chan = 0 ; chan < channels ; chan ++)
for (k = chan ; k < count ; k+= channels)
data [k] *= channel_gain [chan] ;
return ;
} /* data_processing */
This is how i am mixing two simple wav files which are 16 bit signals.
First of all audio mixing is not easy as one might think. There might be many ambiguities after joining two signals. In my case it is working just fine as much as i need it, but if you need exact results you might need to google more for exact superimposing signals over each other.
For joining two wav files you can just read your first wav file copy the data in the result wav file and finally append the data of the second wav file to the result wav file.
This link might also be useful for you
http://www.vttoth.com/digimix.htm
This is old, but I'm reading it, so somebody else inevitably will do so.
I agree in general with nishantmishra regarding the use of libsndfile, but this mixing algorithm would cause a certain amount of distortion if it was doing as the author expects:
outdata[i] = (data[i] + data2[i]) -(data[i])*(data2[i])/65535;
(In reality, that last term only adds a little bit of low-level noise...before reading V-Toth's article I thought it was an interesting form of dither),
Assuming this was applied in a way that works as intended (floating point audio ranges from -1.0 to 1.0, so dividing by 65535 reduces the product by 96 dB, which makes it inaudible for 16-bit audio). If you actually want to implement this method, then read on in V Toth's posting about doing this for signed data.
Whether signed or unsigned, you will be adding inter-modulation distortion (even if it isn't nasty audible, it will be there). In other words, this would work great for voice, or low bit-rate (telephone) audio where the distortion in the transmission channel far exceeds the intermodulation distortion added by product of channels.
If you are just processing two files, and not doing so in real-time (play-back as you read blocks from the file or stream), you can normalize both files, apply mix gain such that gain1+gain2 = 1.0, and sum them together. These low resolution challenges as mentioned by V Toth are not a large concern with 32-bit float or 64-bit double.
Finally, if you are concerned about one source being too quiet while the other is silent, then you can apply a dynamic range compressor cross-linked to the other channel. Another tactic is to apply the same algorithm, but to the envelopes of the audio, and not to individual samples:
outEnvelope[i] = (envelope1[i] + envelope2[i]) \
-(envelope1[i])*(envelope2[i]);
outdata[i]=outEnvelope[i]*(data[i] + data2[i]);
Where envelope =
envelope1[i]=sqrt(lowPassFilter(data[i]*data[i]));//moving RMS representation
And the low pas filter cutoff frequency is something on the order of <10Hz to minimize harmonic distortion.
Really, I think all you want to do most times is to drop that last term and use this line:
outdata[i] = (data[i] + data2[i]);
As long as the sum of channel_gain[] = 1.0, you will get a good result. The code by nishantmishra works well because that last distortion-adding term is reduced to the noise floor, so you may as well save CPU time and eliminate it.

Setting color brightness on Linux/Xorg

Is there any command (or API) to set X.Org/Linux color brightness?
In other words, I need something as handy as the xgamma command but for changing RGB brightness real-time.
Is this possibile?
Use the XF86VidMode* family of functions.
#include <X11/Xlib.h>
#include <X11/extensions/xf86vmode.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
Display *display;
int screen;
int major, minor;
int i;
XF86VidModeGamma orig;
display = XOpenDisplay(NULL);
if (!display) return -1;
screen = DefaultScreen(display);
if (!XF86VidModeQueryVersion(display, &major, &minor)
|| major < 2 || major == 2 && minor < 0
|| !XF86VidModeGetGamma(display, screen, &orig)) {
XCloseDisplay(display);
return -1;
}
for (i = 0; i <= 32; i++) {
XF86VidModeGamma gamma;
gamma.red = exp2f(2 - fabs(i - 16) / 4);
gamma.green = gamma.red;
gamma.blue = gamma.red;
if (!XF86VidModeSetGamma(display, screen, &gamma)) break;
printf("gamma: %f %f %f", gamma.red, gamma.green, gamma.blue);
if (!XF86VidModeGetGamma(display, screen, &gamma)) break;
printf(" -> %f %f %f\n", gamma.red, gamma.green, gamma.blue);
sleep(1);
}
XF86VidModeSetGamma(display, screen, &orig);
XF86VidModeGetGamma(display, screen, &orig);
XCloseDisplay(display);
return 0;
}
This brings the gamma from 0.25 to 4.0 and back, and then restores the original gamma.
Or you could just repeatedly call system("xgamma -gamma %f"), with pretty much the same results.
xbacklight -set 80
You have to install this software from your repository. Works well on most laptops, at least on ThinkPads :-)
To control LCD brightness:
echo 4 > /proc/acpi/video/GFX0/LCD/brightness
The range is 1 to 8.
May Be You need XRandr?

Resources