Mono WAV playing on both channels - c

I created a random mono WAV, but when I play it, I can hear the audio through both channels (left & right). Here's my code:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
struct wav{
char ChunkID[4];
unsigned int ChunkSize;
char Format[4];
char Subchunk1ID[4];
unsigned int Subchunk1Size;
unsigned short int AudioFormat;
unsigned short int NumChannels;
unsigned int SampleRate;
unsigned int ByteRate;
unsigned short int BlockAlign;
unsigned short int BitsPerSample;
char SubChunk2ID[4];
unsigned int Subchunk2Size;
};
int main(){
struct wav wavHdr;
FILE *fp;
fp = fopen("MonoSound.wav", "wb");
strcpy(wavHdr.ChunkID, "RIFF");
strcpy(wavHdr.Format, "WAVE");
strcpy(wavHdr.Subchunk1ID, "fmt ");
wavHdr.Subchunk1Size = 16;
wavHdr.AudioFormat = 1;
wavHdr.NumChannels = 1;
wavHdr.SampleRate = 220505;
wavHdr.ByteRate = 441010; //(SampleRate*NumChannels*BitsPerSample/8)
wavHdr.BlockAlign = 2; //(NumChannels*BitsPerSample/8)
wavHdr.BitsPerSample = 16;
strcpy(wavHdr.SubChunk2ID, "data");
/* multiplied by 5 because there's 5 seconds of audio */
wavHdr.Subchunk2Size = (5 * wavHdr.ByteRate);
wavHdr.ChunkSize = (wavHdr.Subchunk2Size + 36);
fwrite(&wavHdr, 44, 1, fp);
int i, randVal;
unsigned int audio;
float freq = 50.0;
int amp = 32600;
float w;
srand(time(NULL));
for(i = 0; i < (5 * wavHdr.SampleRate); i++){
randVal = (rand() % 1) + 1;
amp += randVal;
w = 2.0 * 3.141592 * freq;
audio = amp * sin(w * i / 220505.0);
fwrite(&audio, 2, 1, fp);
}
return 0;
}
What have I done wrong here? The audio should only come out through one of the speakers. Thanks in advance for the help.

"The audio should only come out through one of the speakers"
Not really. When you have mono file i.e. you had one microphone when you were recording the audio, you will get same data on both output channels. If you want to hear audio only from one channel make 2 channel wav, with one channel all zeros

The audio should only come out through one of the speakers
Why do you you think so? Probably the audio driver tries to be smart and plays mono signals through both speakers (like all other consumer audio hardware does).
If you want to be sure that a signal is played on the left channel only, you have to create a stereo signal with the right channel set to silence (all zeros).

To achieve you goal you can either trick you audio card (which is by default playing the mono file into both speakers channels), or you can create a stereo file with one empty channel.
In order to do so you have to change the number of channels (set to 2 using wavHdr.NumChannels) and you have to write a the empty channel alternating with the good one (see the second command fwrite at the end of the code.)
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <cstring>
struct wav{
char ChunkID[4];
unsigned int ChunkSize;
char Format[4];
char Subchunk1ID[4];
unsigned int Subchunk1Size;
unsigned short int AudioFormat;
unsigned short int NumChannels;
unsigned int SampleRate;
unsigned int ByteRate;
unsigned short int BlockAlign;
unsigned short int BitsPerSample;
char SubChunk2ID[4];
unsigned int Subchunk2Size;
};
int main(){
struct wav wavHdr;
FILE *fp;
fp = fopen("MonoSound.wav", "wb");
strcpy(wavHdr.ChunkID, "RIFF");
strcpy(wavHdr.Format, "WAVE");
strcpy(wavHdr.Subchunk1ID, "fmt ");
wavHdr.Subchunk1Size = 16;
wavHdr.AudioFormat = 1;
wavHdr.NumChannels = 2;
wavHdr.BitsPerSample = 16;
wavHdr.SampleRate = 220505;
wavHdr.ByteRate = wavHdr.SampleRate * wavHdr.NumChannels * wavHdr.BitsPerSample/8;
wavHdr.BlockAlign = wavHdr.NumChannels * wavHdr.BitsPerSample/8;
strcpy(wavHdr.SubChunk2ID, "data");
/* multiplied by 5 because there's 5 seconds of audio */
wavHdr.Subchunk2Size = (5 * wavHdr.ByteRate);
wavHdr.ChunkSize = (wavHdr.Subchunk2Size + 36);
fwrite(&wavHdr, 44, 1, fp);
int i, randVal;
unsigned int audio, empty=0;
float freq = 50.0;
int amp = 32600;
float w;
srand(time(NULL));
for(i = 0; i < (5 * wavHdr.SampleRate); i++){
randVal = (rand() % 1) + 1;
amp += randVal;
w = 2.0 * 3.141592 * freq;
audio = amp * sin(w * i / 220505.0);
// write LEFT channel
fwrite(&audio, 2, 1, fp);
// write RIGHT channel
fwrite(&empty, 2, 1, fp);
}
return 0;
}
The order in which you write the two channel matters. If you want the empty channel to be the left one, you have to invert the two fwrite commands.
Moreover, you have to change ByteRate and BlockAlign to take into account the new channel.

Related

how to store string of numbers into unsigned integer in C

Actually, I have to convert from command arguments which are three strings to bit field(three unsigned integers inside). This program is going to convert from bits into float. I firstly thought about using array to store the three arguments,but I don't really know how to convert from array to unsigned int. Should I just use atoi to change arg into int and then directly into unsigned int? It doesn't word on my computer. Got no idea.
Union32 getBits(char *sign, char *exp, char *frac)
{
Union32 new;
// this line is just to keep gcc happy
// delete it when you have implemented the function
//new.bits.sign = new.bits.exp = new.bits.frac = 0;
new.bits.sign = *(unsigned int *)atoi(sign);
new.bits.exp = *(unsigned int *)atoi(exp);
new.bits.frac = *(unsigned int *)atoi(frac);
//int i ;
//int balah[8] = {};
//for(i = 0; i < 8; i++){
//balah[i] = sign[i];
//}
//int j ;
//int bili[23] = {};
//for(j = 0; j < 23; j++){
//bili[j] = sign[j];
//}
//convert array into unsigned integer?
printf("%u %u %u\n", new.bits.sign, new.bits.exp, new.bits.frac);
// convert char *sign into a single bit in new.bits
// convert char *exp into an 8-bit value in new.bits
// convert char *frac into a 23-bit value in new.bits
enter code here
return new;
}
The following are the details about the typedef and unions that needed in this program, also the four functions in this program.
typedef uint32_t Word;
struct _float {
// define bit_fields for sign, exp and frac
// obviously they need to be larger than 1-bit each
// and may need to be defined in a different order
unsigned int sign:1, exp:8, frac:23;
};
typedef struct _float Float32;
union _bits32 {
float fval; // interpret the bits as a float
Word xval; // interpret as a single 32-bit word
Float32 bits; // manipulate individual bits
};
typedef union _bits32 Union32;
void checkArgs(int, char **);
Union32 getBits(char *, char *, char *);
char *showBits(Word, char *);
int justBits(char *, int);
getBits asks us to convert bits into float,
and showBits asks us to convert float into bits.
assuming the correct typedefs in your code:
new.bits.sign = (unsigned int)atoi(sign);
new.bits.exp = (unsigned int)atoi(exp);
new.bits.frac = (unsigned int)atoi(frac);

Accessing the memory location correctly to print the elements of an integer array using union in c

I am not how to use the unions to print the integer array here. Please correct me to get the out.
val.str is being printed correctly - as '+100-100-100+760' and the first element of the output array seems to be loaded the value correctly. Then the same memory is overridden and printing some garbage value and this is something I don't know how to solve.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
//Variable Decalartion
int i = 0, x = 100, y = -100, z = -100, p = 760;
int len_str;
char temp[4];
union Data{
char str[16];
unsigned int buff[8];
};
void Init(union Data val, unsigned int *dest);
int main(void){
union Data val;
unsigned int x[8];
Init(val,x);
for (i = 0; i < 8; i++)
{
printf("0x%04X ",x[i]);
}
return 0;
}
void Init(union Data val, unsigned int *dest)
{
len_str = sizeof(val.str);
sprintf(temp,"%+04d",x);
strcpy(val.str,temp);
sprintf(temp,"%+04d",y);
strcat(val.str,temp);
sprintf(temp,"%+04d",z);
strcat(val.str,temp);
sprintf(temp,"%+04d",p);
strcat(val.str,temp);
printf("%s\n",val.str);
printf("\n");
for (i = 0; i < len_str+1; i += 2)
{
val.buff[i / 2] = ((unsigned int)(unsigned char)val.str[i] << 8) |
(unsigned int)(unsigned char)val.str[i + 1];
dest[i / 2] = val.buff[i / 2];
}
}
The output that is displayed is,
+100-100-100+760
0x2B31 0x401111C8 0x8049A58 0x8048782 0x0001 0xBFFB5E74 0xBFFB5E7C 0x401B0E4D
Thanks,
Akhil
There are many serious errors in this code.
As user694733 noted, char temp[4]; is too small. you have a buffer overflow there.
You make this call: Init(val,x); with unititialized data in val.
Note that the sizeof int is platform specific. You seem to assume it is 16bits?
It is 32bits on PCs and modern ARM processors. But may be 16bits on lower end processors.

crop image with opencv in c

I want to crop 1 pixel from all sides of image.
My code works well in some margins but does not work well in some margins (ex. widthleft=widthright=heightup=heightdown=1).
I should use C not C++.
IplImage* edgecuter_v3(unsigned int height, unsigned int width,
IplImage* p_in_img_grey) {
unsigned int widthleft, widthright, heightup, heightdown, heighteff;
unsigned int widtheff;
widthleft = 1;
widthright = 1;
heightup = 1;
heightdown = 1;
widtheff = width - widthleft - widthright;
heighteff = height - heightup - heightdown;
IplImage *p_out_img;
unsigned char *p_in_img_data;
p_in_img_data = (unsigned char *) p_in_img_grey->imageData;
unsigned char (*p_char_array_in)[width];
p_char_array_in = (unsigned char (*)[width]) p_in_img_data;
p_out_img = cvCreateImage(cvSize(widtheff, heighteff), IPL_DEPTH_8U, 1);
unsigned char *p_out_img_data;
p_out_img_data = (unsigned char *) p_out_img->imageData;
unsigned char (*p_char_array_out)[widtheff];
p_char_array_out = (unsigned char (*)[widtheff]) p_out_img_data;
unsigned int row_indx;
unsigned int col_indx;
for (row_indx = 0; row_indx < heighteff ; row_indx++) {
for (col_indx = 0; col_indx < widtheff; col_indx++) {
p_char_array_out[row_indx ][col_indx ] =
p_char_array_in[row_indx+heightup][col_indx+widthleft];
}
}
cvNamedWindow("one", CV_WINDOW_AUTOSIZE);
cvShowImage("one", p_out_img);
cvWaitKey(0);
return p_out_img;}
I sweep index with other methods and assignments like but not work.
p_char_array_out[row_indx ][col_indx ] =
p_char_array_in[row_indx+heightup][col_indx+widthleft];
thanks lot
I found the solution. maybe useful for others.
Acording to this link 32bit boundary "If the number of cols * pixel size isn't a multiple of 4 then each row if the image will be padded"
The right way for sweep is to use "widthStep" not "width" for considering pad
widthStep_r = p_in_img->widthStep;

I can store only a finite number of lines in a new text file

I have many different pseudo-random number generators written in C that generate an arbitrary number of pairs of random numbers (through the CLI) and store them in a (new) text file: a pair of numbers per column. I want to store 400.000.000 numbers in a text file, but when I look at the number of lines the file has, it has only 82.595.525 lines. This is the code:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "../Calculos/myfunctions.c"
void outputDevRandomOpenFile (FILE * from_file, FILE * to_file, unsigned long long how_many_pairs){
unsigned long long i = 0LL;
int seed;
unsigned long long max_period = 2147483648LL;
for (i = 0LL; i < how_many_pairs; i += 1LL){
fread (&seed, sizeof(int), 1, from_file);
fprintf (to_file, "%.10lf ", fabs (((double) seed) / ((double) max_period)));
fread (&seed, sizeof(int), 1, from_file);
fprintf (to_file, "%.10lf\n", fabs (((double) seed) / ((double) max_period)));
}
}
int main (int argc, char *argv[]){
char * endptr;
unsigned long long how_many_pairs = (unsigned long long) strtoull (argv[1], &endptr, 10);
FILE * urandom = fopen ("/dev/urandom", "r");
FILE * to_file = fopen ("generated_numbers_devrandom.txt", "w");
outputDevRandomOpenFile (urandom, to_file, how_many_pairs);
fclose (urandom);
return 0;
}
At first I suspected that there where some issue in the code (i.e. I could be choosing the wrong types of variables somewhere), but I tested it by including inside the for-loop a if (i > 165191050) printf ("%llu\n", i); (remind that I'm using a 1-D array for storing couples of numbers, not a 2-D one, so in the condition I just multiply 82595525*2) to test whether the problem was that the code was not looping 800.000.000 times, but only 165191050. When I performed the test, after i = 165191050, it just started to print out i values on the shell, so it really looped those 800.000.000 times, but when I looked the number of lines of the generated text file, there were 82595525 lines again. So I'm betting the problem is not in the code (or at least not in the types of variables I used).
I'm also getting the same results with this algorithm (this is just another different pseudo-random number generator):
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define MT_LEN 624
int mt_index;
unsigned long mt_buffer[MT_LEN];
void mt_init() {
int i;
for (i = 0; i < MT_LEN; i++)
mt_buffer[i] = rand();
mt_index = 0;
}
#define MT_IA 397
#define MT_IB (MT_LEN - MT_IA)
#define UPPER_MASK 0x80000000
#define LOWER_MASK 0x7FFFFFFF
#define MATRIX_A 0x9908B0DF
#define TWIST(b,i,j) ((b)[i] & UPPER_MASK) | ((b)[j] & LOWER_MASK)
#define MAGIC(s) (((s)&1)*MATRIX_A)
unsigned long mt_random() {
unsigned long * b = mt_buffer;
int idx = mt_index;
unsigned long s;
int i;
if (idx == MT_LEN*sizeof(unsigned long))
{
idx = 0;
i = 0;
for (; i < MT_IB; i++) {
s = TWIST(b, i, i+1);
b[i] = b[i + MT_IA] ^ (s >> 1) ^ MAGIC(s);
}
for (; i < MT_LEN-1; i++) {
s = TWIST(b, i, i+1);
b[i] = b[i - MT_IB] ^ (s >> 1) ^ MAGIC(s);
}
s = TWIST(b, MT_LEN-1, 0);
b[MT_LEN-1] = b[MT_IA-1] ^ (s >> 1) ^ MAGIC(s);
}
mt_index = idx + sizeof(unsigned long);
return *(unsigned long *)((unsigned char *)b + idx);
/* Here there is a commented out block in MB's original program */
}
int main (int argc, char *argv[]){
char * endptr;
const unsigned long long how_many_pairs = (unsigned long long) strtoll (argv[1], &endptr, 10);
unsigned long long i = 0;
FILE * file = fopen ("generated_numbers_mt.txt", "w");
mt_init ();
for (i = 0LL; i < how_many_pairs; i++){
fprintf (file, "%.10lf ", ((double) mt_random () / (double) 4294967295));
fprintf (file, "%.10lf\n", ((double) mt_random () / (double) 4294967295));
}
fclose (file);
return 0;
}
Again, it loops 800.000.000 times, but it only stores 165191050 numbers.
$ ./devrandom 400000000
$ nl generated_numbers_devrandom.txt | tail # Here I'm just asking the shell to number the lines of the text file and to print out the 10 last ones.
82595516 0.8182168589 0.0370640513
82595517 0.1133005517 0.8237414290
82595518 0.9035788113 0.6030153367
82595519 0.9192735264 0.0945496135
82595520 0.0542484536 0.7224835437
82595521 0.1827865853 0.9254508596
82595522 0.0249044443 0.1234162976
82595523 0.0371284033 0.8898798078
82595524 0.5977596357 0.9672102989
82595525 0.5523654688 0.29032228
What is going on here?
Thanks in advance.
Each line is 26 characters long, 82595525 lines x 26 = 2147483650 bytes
If you look closer to the file created, I'm quite sure the last line is truncated and the file size is precisely 2147483647, i.e. 2^31-1.
The reason why you can't write a larger file is either due to a file system limitation but more likely due to the fact you compile a (non large file aware) 32 bit binary, with which a file can't be more than 2147483647 as it is the largest signed integer that can be used.
If that is the case and if your OS is 64 bit, the simplest fix is to set the proper compiler flags to build a 64 bit binary which won't have this limitation.
Otherwise, have a look to abasterfield workaround.
Compile with CFLAGS -D_FILE_OFFSET_BITS=64 or put
#define _FILE_OFFSET_BITS 64
in your code before you include any libc headers

WAV File Synthesis From Scratch - C

Recently I saw a video lecture in my CS 101 class that inspired me to start playing with the WAV File Format in C. My project today has been creating sounds using a simple mathematical sine function. Despite a couple obstacles, my program can now accept several inputs(frequencies of waves, amplitudes of waves, sampling rate, etc.) and create a wav file containing the specified pitches.
However, when playing these tones on my computer speakers, there is a strange, rhythmic popping sound, which varies with the sampling rate. At higher sampling rates, the frequency of the popping sound increases and turns into an annoying whining sound.
The strange part is that the popping sound is consistent across different computers with the same file.
Below I will post the code that I use to generate the WAV file. Any insights into what might be causing this phenomenon will be appreciated. It's probably just a stupid mistake on my part somewhere. :)
#include <stdio.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <string.h>
#include <math.h>
struct WAVHeader {
char ChunkID[4];
uint32_t ChunkSize;
char RIFFType[4];
};
struct FormatHeader {
char ChunkID[4];
uint32_t ChunkSize;
uint16_t CompressionCode;
uint16_t Channels;
uint32_t SampleRate;
uint32_t AvgBytesPerSec;
uint16_t BlockAlign;
uint16_t SigBitsPerSamp;
};
struct DataHeader {
char ChunkID[4];
uint32_t ChunkSize;
};
void main(int argc, char * argv[]) {
//Check for valid number of arguments or display help
if(argc < 8) {
printf("Usage:\n./Tone -l [length] -s [frequency] [amplitude] -o [output-file] -r [sample-rate]\n");
printf("-l length of tone to produce in seconds\n");
printf("-s Creates sine wave. Can be used multiple times. Frequency (Hz) and amplitude (0 - 32767) of each tone. \n");
printf("-o File to write to\n");
printf("-r samples per second (kHz). Note: Must be double highest frequency in tone.\n");
return;
}
//Organize arguments
int length, sinf[10], sina[10], samplerate;
memset(sinf, 0, sizeof(int) * 10);
memset(sina, 0, sizeof(int) * 10);
char * output = NULL;
int i = 0;
int count;
for(count = 1; count < argc; count++){
char first = *argv[count];
int second = *(argv[count] + 1);
if (first == '-') {
switch (second) {
case 's':
sinf[i] = atoi(argv[count+1]);
sina[i] = atoi(argv[count+2]);
i++;
break;
case 'l':
length = atoi(argv[count+1]);
break;
case 'o':
output = argv[count+1];
break;
case 'r':
samplerate = atoi(argv[count+1]) * 1000;
break;
}
}
}
//Allocate memory for wav file
size_t size = sizeof(struct WAVHeader) + sizeof(struct FormatHeader) + sizeof(struct DataHeader) + (length * samplerate * 2);
void * buffer = malloc(size);
//Fill buffer with headers
struct WAVHeader * WAV = (struct WAVHeader *)buffer;
struct FormatHeader * Format = (struct FormatHeader *)(WAV + 1);
struct DataHeader * Data = (struct DataHeader *)(Format + 1);
strcpy(WAV->ChunkID, "RIFF");
WAV->ChunkSize = (uint32_t)size - 8;
strcpy(WAV->RIFFType, "WAVE");
strcpy(Format->ChunkID, "fmt ");
Format->ChunkSize = 16;
Format->CompressionCode = 1;
Format->Channels = 1;
Format->SampleRate = (uint32_t)samplerate;
Format->SigBitsPerSamp = 16;
Format->BlockAlign = 2;
Format->AvgBytesPerSec = Format->BlockAlign * samplerate;
strcpy(Data->ChunkID, "data");
Data->ChunkSize = length * samplerate * 2;
//Generate Sound
printf("Generating sound...\n");
short * sound = (short *)(Data + 1);
short total;
float time;
float increment = 1.0/(float)samplerate;
for (time = 0; time < length; time += increment){
total = 0;
for (i = 0; i < 10; i++) {
total += sina[i] * sin((float)sinf[i] * time * (2 * 3.1415926));
}
*(sound + (int)(time * samplerate)) = total;
//printf("Time: %f Value: %hd\n", time, total);
}
//Write buffer to file
FILE * out = fopen(output, "w");
fwrite(buffer, size, 1, out);
printf("Wrote to %s\n", output);
return;
}
I think this is your core problem:
*(sound + (int)(time * samplerate)) = total;
I suspect that (time*samplerate) doesn't always increase on integer boundaries due to floating point rounding errors. Hence, some sample positions are skipped and/or overwritten due to rounding errors. That's just a guess.
But also, as "time" increases, the multiplication of "time * frequency * 2PI" will overflow within a float. So you should normalize "time" such that it doesn't increase forever.
In any case, I validated this modified loop works (and sounds) just fine:
float TWOPI = 6.28318531f;
unsigned int sample_count = length * samplerate;
for (unsigned int i = 0; i < sample_count; i++)
{
unsigned int j = i % samplerate; // normalize the sample position so that we don't blow up in the subsequent multiplication
float f = 0.0f;
int result;
for (int x = 0; x < 10; x++)
{
f += sina[x] * sin((sinf[x] * j * TWOPI) / samplerate);
}
result = (long)f;
//clamp to 16-bit
if (result > 32767)
{
result = 32767;
}
else if (result < -32768)
{
result = -32768;
}
sound[i] = (short)result;
//printf("%d\n", sound[i]);
}

Resources