libsndfile usage joining and mixing .wav files - audio

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.

Related

sending audio via bluetooth a2dp source esp32

I am trying to send measured i2s analogue signal (e.g. from mic) to the sink device via Bluetooth instead of the default noise.
Currently I am trying to change the bt_app_a2d_data_cb()
static int32_t bt_app_a2d_data_cb(uint8_t *data, int32_t i2s_read_len)
{
if (i2s_read_len < 0 || data == NULL) {
return 0;
}
char* i2s_read_buff = (char*) calloc(i2s_read_len, sizeof(char));
bytes_read = 0;
i2s_adc_enable(I2S_NUM_0);
while(bytes_read == 0)
{
i2s_read(I2S_NUM_0, i2s_read_buff, i2s_read_len,&bytes_read, portMAX_DELAY);
}
i2s_adc_disable(I2S_NUM_0);
// taking care of the watchdog//
TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
TIMERG0.wdt_feed=1;
TIMERG0.wdt_wprotect=0;
uint32_t j = 0;
uint16_t dac_value = 0;
// change 16bit input signal to 8bit
for (int i = 0; i < i2s_read_len; i += 2) {
dac_value = ((((uint16_t) (i2s_read_buff[i + 1] & 0xf) << 8) | ((i2s_read_buff[i + 0]))));
data[j] = (uint8_t) dac_value * 256 / 4096;
j++;
}
// testing for loop
//uint8_t da = 0;
//for (int i = 0; i < i2s_read_len; i++) {
// data[i] = (uint8_t) (i2s_read_buff[i] >> 8);// & 0xff;
// da++;
// if(da>254) da=0;
//}
free(i2s_read_buff);
i2s_read_buff = NULL;
return i2s_read_len;
}
I can hear the sawtooth sound from the sink device.
Any ideas what to do?
your data can be an array of some float digits representing analog signals or analog signal variations, for example, a 32khz sound signal contains 320000 float numbers to define captures sound for every second. if your data have been expected to transmit in offline mode you can prepare your outcoming data in the form of a buffer plus a terminator sign then send buffer by Bluetooth module of sender device which is connected to the proper microcontroller. for the receiving device, if you got terminator character like "\r" you can process incoming buffer e.g. for my case, I had to send a string array of numbers but I often received at most one or two unknown characters and to avoid it I reject it while fulfill receiving container.
how to trim unknown first characters of string in code vision
if you want it in online mode i.e. your data must be transmitted and played concurrently. you must consider delays and reasonable time to process for all microcontrollers and devices like Bluetooth, EEprom iCs and...
I'm also working on a project "a2dp source esp32".
I'm playing a wav-file from spiffs.
If the wav-file is 44100, 16-bit, stereo then you can directly write a stream of bytes from the file to the array data[ ].
When I tried to write less data than in the len-variable and return less (for example 88), I got an error, now I'm trying to figure out how to reduce this buffer because of big latency (len=512).
Also, the data in the array data[ ] is stored as stereo.
Example: read data from file to data[ ]-array:
size_t read;
read = fread((void*) data, 1, len, fwave);//fwave is a file
if(read<len){//If get EOF, go to begin of the file
fseek(fwave , 0x2C , SEEK_SET);//skip wav-header 44bytesт
read = fread((void*) (&(data[read])), 1, len-read, fwave);//read up
}
If file mono, I convert it to stereo like this (I read half and then double data):
int32_t lenHalf=len/2;
read = fread((void*) data, 1, lenHalf, fwave);
if(read<lenHalf){
fseek(fwave , 0x2C , SEEK_SET);//skip wav-header 44bytesт
read = fread((void*) (&(data[read])), 1, lenHalf-read, fwave);//read up
}
//copy to the second channel
uint16_t *data16=(uint16_t*)data;
for (int i = lenHalf/2-1; i >= 0; i--) {
data16[(i << 1)] = data16[i];
data16[(i << 1) + 1] = data16[i];
}
I think you have got sawtooth sound because:
your data is mono?
in your "return i2s_read_len;" i2s_read_len less than len
you // change 16bit input signal to 8bit, in the array data[ ] data as 16-bit: 2ByteLeft-2ByteRight-2ByteLeft-2ByteRight-...
I'm not sure, it's a guess.

Using Lame function hip_decode in Android NDK to decode mp3 return 0

I am using Lame's mpglib to decode mp3 to PCM in Android NDK for playing. But when I called hip_decode(), it returen 0 meaning that "need more data before we can complete the decode". I had no idea how to solve it. Can someone helps me? Here is my code:
void CBufferWrapper::ConvertMp3toPCM (AAssetManager* mgr, const char *filename){
Print ("ConvertMp3toPCM:file:%s", filename);
AAsset* asset = AAssetManager_open (mgr, filename, AASSET_MODE_UNKNOWN);
// the asset might not be found
assert (asset != NULL);
// open asset as file descriptor
off_t start, length;
int fd = AAsset_openFileDescriptor (asset, &start, &length);
assert (0 <= fd);
long size = AAsset_getLength (asset);
char* buffer = (char*)malloc (sizeof(char)*size);
memset (buffer, 0, size*sizeof(char));
AAsset_read (asset, buffer, size);
AAsset_close (asset);
hip_t ht = hip_decode_init ();
int count = hip_decode (ht, (unsigned char*)buffer, size, pcm_l, pcm_r);
free (buffer);
Print ("ConvertMp3toPCM: length:%ld,pcmcount=%d",length, count);
}
I used MACRO "HAVE_MPGLIB" to compile Lame in NDK. So I think it should work for decoding literally.
Yesterday I had the same problem. Is the same problem but using lame_enc.dll. I did not know how to resolve this 0 returned, this is the reason to this post.
Create a buffer to put mp3 data: unsigned char mp3Data[4096]
Create two buffers for pcm data, but bigger than mp3 one:
unsigned short[4096 * 100];
Open mp3 file and initialize hip.
Now, enter in a do while loop until read bytes are 0 (the end of file).
Inside the loop read 4096 bytes into mp3Data and call hip_decode with
hip_decode(ht, mp3Data, bytesRead, lpcm, rpcm);
You are right, it returns 0. It is asking you for more data.
You need to repeat the reading of 4096 bytes and the call to hip_decode until it returns a valid samples number.
Here is the important part of my program:
int total = 0;
int hecho = 0;
int leido = 0;
int lon = 0;
int x;
do
{
total = fread(mp3b, 1, MAXIMO, fich);
leido += total;
x = hip_decode(hgf, mp3b, total, izquierda, derecha);
if(x > 0)
{
int tamanio;
int y;
tamanio = 1.45 * x + 9200;
unsigned char * bu = (unsigned char *) malloc(tamanio);
y = lame_encode_buffer(lamglofla, izquierda, derecha, x, bu, tamanio);
fwrite(bu, 1, y, fichs);
free(bu);
}
}while(total > 0);
My program decodes a mp3 file and encodes the output into another mp3 file.
I expect that this could be useful.

CUDA Programming: Compilation Error

I am making a CUDA program that implements the data parallel prefix sum calculation operating upon N numbers. My code is also supposed to generate the numbers on the host using a random number generator. However, I seem to always run into a "unrecognized token" and "expected a declaration" error on the ending bracket of int main when attempting to compile. I am running the code on Linux.
#include <stdio.h>
#include <cuda.h>
#include <stdlib.h>
#include <math.h>
__global__ void gpu_cal(int *a,int i, int n) {
int tid = blockIdx.x * blockDim.x + threadIdx.x;
if(tid>=i && tid < n) {
a[tid] = a[tid]+a[tid-i];
}
}
int main(void)
{
int key;
int *dev_a;
int N=10;//size of 1D array
int B=1;//blocks in the grid
int T=10;//threads in a block
do{
printf ("Some limitations:\n");
printf (" Maximum number of threads per block = 1024\n");
printf (" Maximum sizes of x-dimension of thread block = 1024\n");
printf (" Maximum size of each dimension of grid of thread blocks = 65535\n");
printf (" N<=B*T\n");
do{
printf("Enter size of array in one dimension, currently %d\n",N);
scanf("%d",&N);
printf("Enter size of blocks in the grid, currently %d\n",B);
scanf("%d",&B);
printf("Enter size of threads in a block, currently %d\n",T);
scanf("%d",&T);
if(N>B*T)
printf("N>B*T, this will result in an incorrect result generated by GPU, please try again\n");
if(T>1024)
printf("T>1024, this will result in an incorrect result generated by GPU, please try again\n");
}while((N>B*T)||(T>1024));
cudaEvent_t start, stop; // using cuda events to measure time
float elapsed_time_ms1, elapsed_time_ms3;
int a[N],gpu_result[N];//for result generated by GPU
int cpu_result[N];//CPU result
cudaMalloc((void**)&dev_a,N * sizeof(int));//allocate memory on GPU
int i,j;
srand(1); //initialize random number generator
for (i=0; i < N; i++) // load array with some numbers
a[i] = (int)rand() ;
cudaMemcpy(dev_a, a , N*sizeof(int),cudaMemcpyHostToDevice);//load data from host to device
cudaEventCreate(&start); // instrument code to measure start time
cudaEventCreate(&stop);
cudaEventRecord(start, 0);
//GPU computation
for(j=0;j<log(N)/log(2);j++){
gpu_cal<<<B,T>>>(dev_a,pow(2,j),N);
cudaThreadSynchronize();
}
cudaMemcpy(gpu_result,dev_a,N*sizeof(int),cudaMemcpyDeviceToHost);
cudaEventRecord(stop, 0); // instrument code to measue end time
cudaEventSynchronize(stop);
cudaEventElapsedTime(&elapsed_time_ms1, start, stop );
printf("\n\n\nTime to calculate results on GPU: %f ms.\n", elapsed_time_ms1); // print out execution time
//CPU computation
cudaEventRecord(start, 0);
for(i=0;i<N;i++)
{
cpu_result[i]=0;
for(j=0;j<=i;j++)
{
cpu_result[i]=cpu_result[i]+a[j];
}
}
cudaEventRecord(stop, 0); // instrument code to measue end time
cudaEventSynchronize(stop);
cudaEventElapsedTime(&elapsed_time_ms3, start, stop );
printf("Time to calculate results on CPU: %f ms.\n\n", elapsed_time_ms3); // print out execution time
//Error check
for(i=0;i < N;i++) {
if (gpu_result[i] != cpu_result[i] ) {
printf("ERROR!!! CPU and GPU create different answers\n");
break;
}
}
//Calculate speedup
printf("Speedup on GPU compared to CPU= %f\n", (float) elapsed_time_ms3 / (float) elapsed_time_ms1);
printf("\nN=%d",N);
printf("\nB=%d",B);
printf("\nT=%d",T);
printf("\n\n\nEnter '1' to repeat, or other integer to terminate\n");
scanf("%d",&key);
}while(key == 1);
cudaFree(dev_a);//deallocation
return 0;
}​
The very last } in your code is a Unicode character. If you delete this entire line, and retype the }, the error will be gone.
There are two compile errors in your code.
First, Last ending bracket is a unicode character, so you should resave your code as unicode or delete and rewrite the last ending bracket.
Second, int type variable N which used at this line - int a[N],gpu_result[N];//for result generated by GPU
was declared int type, but it's not allowed in c or c++ compiler, so you should change the N declaration as const int N.

Parallel output using MPI IO to a single file

I have a very simple task to do, but somehow I am still stuck.
I have one BIG data file ("File_initial.dat"), which should be read by all nodes on the cluster (using MPI), each node will perform some manipulation on part of this BIG file (File_size / number_of_nodes) and finally each node will write its result to one shared BIG file ("File_final.dat"). The number of elements of files remain the same.
By googling I understood, that it is much better to write data file as a binary file (I have only decimal numbers in this file) and not as *.txt" file. Since no human will read this file, but only computers.
I tried to implement myself (but using formatted in/output and NOT binary file) this, but I get incorrect behavior.
My code so far follows:
#include <fstream>
#define NNN 30
int main(int argc, char **argv)
{
ifstream fin;
// setting MPI environment
int rank, nprocs;
MPI_File file;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
// reading the initial file
fin.open("initial.txt");
for (int i=0;i<NNN;i++)
{
fin >> res[i];
cout << res[i] << endl; // to see, what I have in the file
}
fin.close();
// starting position in the "res" array as a function of "rank" of process
int Pstart = (NNN / nprocs) * rank ;
// specifying Offset for writing to file
MPI_Offset offset = sizeof(double)*rank;
MPI_File file;
MPI_Status status;
// opening one shared file
MPI_File_open(MPI_COMM_WORLD, "final.txt", MPI_MODE_CREATE|MPI_MODE_WRONLY,
MPI_INFO_NULL, &file);
// setting local for each node array
double * localArray;
localArray = new double [NNN/nprocs];
// Performing some basic manipulation (squaring each element of array)
for (int i=0;i<(NNN / nprocs);i++)
{
localArray[i] = res[Pstart+i]*res[Pstart+i];
}
// Writing the result of each local array to the shared final file:
MPI_File_seek(file, offset, MPI_SEEK_SET);
MPI_File_write(file, localArray, sizeof(double), MPI_DOUBLE, &status);
MPI_File_close(&file);
MPI_Finalize();
return 0;
}
I understand, that I do something wrong, while trying to write double as a text file.
How one should change the code in order to be able to save
as .txt file (format output)
as .dat file (binary file)
Your binary file output is almost right; but your calculations for your offset within the file and the amount of data to write is incorrect. You want your offset to be
MPI_Offset offset = sizeof(double)*Pstart;
not
MPI_Offset offset = sizeof(double)*rank;
otherwise you'll have each rank overwriting each others data as (say) rank 3 out of nprocs=5 starts writing at double number 3 in the file, not (30/5)*3 = 18.
Also, you want each rank to write NNN/nprocs doubles, not sizeof(double) doubles, meaning you want
MPI_File_write(file, localArray, NNN/nprocs, MPI_DOUBLE, &status);
How to write as a text file is a much bigger issue; you have to convert the data into string internally and then output those strings, making sure you know how many characters each line requires by careful formatting. That is described in this answer on this site.

How to get the size of a gunzipped file in vim

When viewing (or editing) a .gz file, vim knows to locate gunzip and display the file properly.
In such cases, getfsize(expand("%")) would be the size of the gzipped file.
Is there a way to get the size of the expanded file?
[EDIT]
Another way to solve this might be getting the size of current buffer, but there seems to be no such function in vim. Am I missing something?
There's no easy way to get the uncompressed size of a gzipped file, short of uncompressing it and using the getfsize() function. That might not be what you want. I took at a look at RFC 1952 - GZIP File Format Specification, and the only thing that might be useful is the ISIZE field, which contains "...the size of the original (uncompressed) input data modulo 2^32".
EDIT:
I don't know if this helps, but here's some proof-of-concept C code I threw together that retrieves the value of the ISIZE field in a gzip'd file. It works for me using Linux and gcc, but your mileage may vary. If you compile the code, and then pass in a gzip'd filename as a parameter, it will tell you the uncompressed size of the original file.
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
int main(int argc, char *argv[])
{
FILE *fp = NULL;
int i=0;
if ( argc != 2 ) {
fprintf(stderr, "Must specify file to process.\n" );
return -1;
}
// Open the file for reading
if (( fp = fopen( argv[1], "r" )) == NULL ) {
fprintf( stderr, "Unable to open %s for reading: %s\n", argv[1], strerror(errno));
return -1;
}
// Look at the first two bytes and make sure it's a gzip file
int c1 = fgetc(fp);
int c2 = fgetc(fp);
if ( c1 != 0x1f || c2 != 0x8b ) {
fprintf( stderr, "File is not a gzipped file.\n" );
return -1;
}
// Seek to four bytes from the end of the file
fseek(fp, -4L, SEEK_END);
// Array containing the last four bytes
unsigned char read[4];
for (i=0; i<4; ++i ) {
int charRead = 0;
if ((charRead = fgetc(fp)) == EOF ) {
// This shouldn't happen
fprintf( stderr, "Read end-of-file" );
exit(1);
}
else
read[i] = (unsigned char)charRead;
}
// Copy the last four bytes into an int. This could also be done
// using a union.
int intval = 0;
memcpy( &intval, &read, 4 );
printf( "The uncompressed filesize was %d bytes (0x%02x hex)\n", intval, intval );
fclose(fp);
return 0;
}
This appears to work for getting the byte count of a buffer
(line2byte(line("$")+1)-1)
If you're on Unix/linux, try
:%!wc -c
That's in bytes. (It works on windows, if you have e.g. cygwin installed.) Then hit u to get your content back.
HTH
From within vim editor, try this:
<Esc>:!wc -c my_zip_file.gz
That will display you the number of bytes the file is having.

Resources