Here's my code snippet that fails:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct WAV {
char chunkId[4];
unsigned chunkSize;
char format[4];
char subChunk1Id[4];
unsigned subChunk1Size;
unsigned short audioFormat;
unsigned short numChannels;
unsigned sampleRate;
unsigned byteRate;
unsigned short blockAlign;
unsigned short bitsPerSample;
char subChunk2Id[4];
unsigned subChunk2Size;
} WAV;
int main() {
void printwav(const WAV *);
void openwav(FILE *, WAV *);
void makewav(FILE *, const WAV *);
char file[FILENAME_MAX];
size_t i;
short
stereo1,
stereo2,
mono1;
FILE
*fpstereo,
*fpmono;
WAV
stereo,
mono;
openwav(fpstereo, &stereo);
printwav(&stereo);
memcpy(&mono, &stereo, sizeof(WAV));
mono.chunkSize -= stereo.subChunk2Size / 2;
mono.subChunk2Size /= 2;
mono.numChannels /= 2;
mono.byteRate /= 2;
mono.blockAlign /= 2;
makewav(fpmono, &mono);
printwav(&mono);
for (i = 0; i < mono.subChunk2Size / sizeof(short); i++) {
fread(&stereo1, sizeof(short), 1, fpstereo);
fread(&stereo2, sizeof(short), 1, fpstereo);
mono1 = (stereo1 + stereo2) / 2;
fwrite(&mono1, sizeof(short), 1, fpmono);
}
fclose(fpstereo);
fclose(fpmono);
}
And my output for the program is:
Enter filepath to stereo WAV: wav11stereo.wav
RIFF
1966116
WAVE
fmt
16
1
2
44100
176400
4
16
data
1966080
Enter filepath to mono WAV: wav11mono.wav
RIFF
983076
WAVE
fmt
16
1
1
44100
88200
2
16
data
983040
Segmentation fault: 11
After testing with a bunch of printfs, I discovered the segmentation fault occurs in the line fread(&stereo1, sizeof(short), 1, fpstereo); inside the for-loop. I declared stereo1 as a short and not a short *, so I don't understand why that's happening. Can anyone explain why that's wrong?
I guess this is your problem:
void openwav(FILE *, WAV *);
void makewav(FILE *, WAV *);
With this, file open call inside the function will only available inside the function and not returned to the caller.
Normally it should be declared as below:
void openwav(FILE **, WAV *);
void makewav(FILE **, WAV *);
And call like this:
openwav(&fpstereo, &stereo);
makewav(&fpmono, &mono);
Related
The following task is from an exam I took in engineering school (mechanical engineering):
You get an array unsigned char buffer[128]; used to read data from a source byte by byte, containing data of the structure:
struct Pixel {
unsigned char x;
unsigned char y;
unsigned char greyValue;
};
The task is: Create an instance of a pixel and copy the data content from the header of the buffer using "memcpy".
My aproach does not seem to work:
#include <stdio.h>
#include <string.h>
struct Pixel {
unsigned char x;
unsigned char y;
unsigned char greyValue;
};
int main()
{
unsigned char buffer[128] = {2,4,44};
struct Pixel singlePixel;
memcpy(singlePixel, buffer, 3);
printf("singlePixel.x = %d\n", singlePixel.x);
printf("singlePixel.y = %d\n", singlePixel.y);
printf("singlePixel.greyValue = %d\n", singlePixel.greyValue);
return 0;
}
I would expect that singlePixel.x = 2, singlePixel.y = 4 and singlePixel.greyValue = 44.
When debugging I get the error: incompatible type for argument 1 of ‘memcpy’
I'm also not at all sure if my approach is up to the task, since I don't understand exactly how this should works with the buffer...
I'm currently working on a C program that is opening a .wav file , copy the .wav header in the output file and after the header it adds the processed data that is obtained from the input file. The process consist of multiplying each sample with 0.5 in order to reduce the amplitude of the signal.
Here is my code:
program.c
#include <stdio.h>
#include <stdlib.h>
struct header_file
{
char chunk_id[4];
int chunk_size;
char format[4];
char subchunk1_id[4];
int subchunk1_size;
short int audio_format;
short int num_channels;
int sample_rate;
int byte_rate;
short int block_align;
short int bits_per_sample;
char subchunk2_id[4];
int subchunk2_size;
};
struct header_file header;
int main()
{
FILE * inputfile = fopen("maneskin.wav","rb"); // deschidere fisier .wav, modul de citire
FILE * outputfile = fopen("Output.wav","wb"); // creeaza fisierul .wav, modul de scriere
int BUFFSIZE = 10000; // lungimea buffer-ului
int count = 0; // numara cate frame-uri sunt in fisier
short int inputBuffer[BUFFSIZE];
short int outputBuffer[BUFFSIZE];
/* header_p meta = (header_p)malloc(sizeof(header)); */
int nb; // numarul de bytes returnati
int temp;
if (inputfile)
{
fread(&header, sizeof(header),1, inputfile);
fwrite(&header,sizeof(header),1, outputfile);
short int ch2[BUFFSIZE];
for(int i=0; i<BUFFSIZE; i++) \
ch2[i] = 1;
while (!feof(inputfile))//cat timp se citeste fisierul
{
for(int i=0; i<BUFFSIZE && !feof(inputfile); i++)
fread((char*)&inputBuffer[i],sizeof(short int),1, inputfile); // citirea datelor
count++;// incrementarea numarului de frame-uri
for(int z=0; z<BUFFSIZE; z++){
outputBuffer[z]=0.5*inputBuffer[z];
}
for(int k=0; k<BUFFSIZE; k++)
{
fwrite((char*)&outputBuffer[k], sizeof(short int), 1, outputfile);// scriere in fisier
}
}
printf("Numarul de cadre din fisierul wav:%d\n", count);
}
return 0;
}
The problemm that I have is when I'm trying to open the output file with VLC or any other media player it doens't open and gives me an error. I think it might be a problem with the header writing in the output file but I'm not sure. I tried importing the file as raw data in Audacity and played the audio file just fine but if I'm trying to import it as wav file it doesn't work.What could be the problem?
I don't know if this is your only problem, but it's definitely a problem...
In C, generally when you define a structure, the members of that structure do not sit right next to each other in memory. The compiler arranges them to fall on boundaries that are comfortable for the processor, usually in increments of the word size of the processor. So an element of type char surrounded by two ints, is not nestled right between them, but actually has perhaps 7 bytes of space between it and the next element.
This is done for execution efficiency, and usually makes sense.
But in situations like this, you want to pack the structure elements tightly together and for this there is a standard way to tell the compiler that this is what you want:
/* pack in 1 byte increments */
#pragma pack(1)
struct header_file
{
char chunk_id[4];
int chunk_size;
char format[4];
char subchunk1_id[4];
int subchunk1_size;
short int audio_format;
short int num_channels;
int sample_rate;
int byte_rate;
short int block_align;
short int bits_per_sample;
char subchunk2_id[4];
int subchunk2_size;
};
/* reset to default */
#pragma pack()
I would also suggest using size-specific types, for example uint16_t instead of short int, because you do not know the size of int on every platform where your code might be compiled.
In your code, try printing the sizeof header to see if it's what you expect, eg:
printf("sizeof(header)=%d\n", sizeof(header));
If the number does not match what it should be for a WAV header then you have got a problem with the size of one or more elements, or a problem with the packing.
I still cannot access the color bits from a bitmap image. The problem is that, after saving the bitmap's content into a buffer, I do not know:
Where to start the loop (If i start from 0 i think it will erase the headers)?
How to access the bytes and make the changes (transform a color from the BMP into a desired one from the output)?
And, how to insert the buffer into a new bitmap file?
All the images I want to modify have rows which are divisible by 4 (I have to insert 0 when a specific byte is padding) and 24 bits per pixel. Even few tips would be much appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "bmp_header.h"
int main(void)
{
FILE *f;
f = fopen("captcha.bmp","rb");
if ((f = fopen("captcha.bmp", "rb")) == NULL)
{
printf("Error opening file %s.\n", "captcha.bmp");
exit(1);
}
fread(&BMP_header,sizeof(BMP_header),1,f);
fread(&BMP_info_header,sizeof(BMP_info_header),1,f);
fseek(f,BMP_header.imageDataOffset,SEEK_SET);
int rows = (BMP_info_header.bitPix * BMP_info_header.width + 31 ) /32 * 4 ;
char *PixelArray =malloc( rows * abs(BMP_info_header.height)*sizeof(char));
int i;
for( i =sizeof(BMP_header)+sizeof(BMP_info_header); i<=(rows * abs(BMP_info_header.height))-2;i+=3)
{
PixelArray[i]=255; // just a random value to test if this makese any sense
PixelArray[i+1]=255;
PixelArray[i+2]=255;
}
return 0;
}
And, here is bmp_header.h's content:
#pragma pack(1)
struct bmp_fileheader
{
unsigned char fileMarker1; /* 'B' */
unsigned char fileMarker2; /* 'M' */
unsigned int bfSize; /* File's size */
unsigned short unused1;
unsigned short unused2;
unsigned int imageDataOffset; /* Offset to the start of image data */
}BMP_header,BMP_header_out;
struct bmp_infoheader
{
unsigned int biSize; /* Size of the info header - 40 bytes */
signed int width; /* Width of the image */
signed int height; /* Height of the image */
unsigned short planes;
unsigned short bitPix;
unsigned int biCompression;
unsigned int biSizeImage; /* Size of the image data */
int biXPelsPerMeter;
int biYPelsPerMeter;
unsigned int biClrUsed;
unsigned int biClrImportant;
}BMP_info_header,BMP_info_header_out;
#pragma pack()
Alright, I wrote some code to write out a completely black bitmap file with the original dimensions of the old bitmap file.
This will not work with all types of bitmaps. 16-color bitmaps, for instance, have a color palette after the info header that my program does not account for. The bits per pixel also needs to be divisible by 8. If those preconditions are met, as I believe they are in 24-bit bitmaps, then this program should work.
The main code here is in getNewImageData. We calculate the row size for the image with the same formula that Wikipedia uses - it calculates the required bits and then pads that to a multiple of four bytes and then converts bits to bytes. Then we set all of the pixel array memory to zero (mostly me being paranoid about leaving values in the pad bytes). Then we run along each row and edit each pixel. The innermost for loop corresponds to each pixel. One iteration through the middle for loop writes to one pixel.
You can obviously modify this code to read the pixel data into a malloced section of memory and then edit the pixel data in place before writing it back out. This sample code does not read the input pixel data and just writes out a black bitmap of the same dimensions as the input file.
Edit: I guess I should mention what you were doing wrong.
You called fopen twice, leaving an open file pointer hanging somewhere in memory.
rows should probably be renamed to rowSize since it's the size of a row of pixels in bytes
PixelArray is not being freed.
Your for loop starts from an offset (the size of the two headers) and then is bounded by the size of the pixel data. The for loop should start from 0 and go to the size of the pixel data (unless you are reading pixel data in as you do this... which you probably shouldn't do).
Your for loop tries to write to all of the pixel data at once and doesn't account for the fact that there is anywhere between 0 and 31 bits of padding on the end of each row of pixels (my program assumes the padding is only 0, 8, 16, or 24 bits).
Here is the code:
#include <stdio.h>
#include "bmp_header.h"
#include <stdlib.h>
int readBitmapHeaders(char* fileLocation, bmp_fileheader* fileheader, bmp_infoheader* infoheader)
{
FILE* f;
f = fopen(fileLocation, "rb");
if (!f)
{
printf("Error opening file %s.\n", fileLocation);
return 1;
}
fread(fileheader, sizeof(bmp_fileheader), 1, f);
fread(infoheader, sizeof(bmp_infoheader), 1, f);
fclose(f);
return 0;
}
int writeBitmap(char* fileName, bmp_fileheader* fileheader, bmp_infoheader* infoheader, char* pixelArray, size_t pixelArraySize)
{
FILE* out;
out = fopen(fileName, "wb");
if (!out)
{
printf("Error opening file %s.\n", fileName);
return 1;
}
fwrite(fileheader, sizeof(bmp_fileheader), 1, out);
fwrite(infoheader, sizeof(bmp_infoheader), 1, out);
fwrite(pixelArray, pixelArraySize, 1, out);
fclose(out);
return 0;
}
char* getNewImageData(bmp_infoheader* infoheader, size_t* imageSize)
{
//rowsize is padded to 4 bytes
size_t rowSize = (infoheader->bitPix * infoheader->width + 31) / 32 * 4;
size_t pixelArraySize = rowSize * abs(infoheader->height);
char* pixelArray = (char*)malloc(pixelArraySize);
if (!pixelArray)
{
return NULL;
}
memset(pixelArray, 0, pixelArraySize);
size_t bytesPerPixel = infoheader->bitPix / 8;
for (int i = 0; i < infoheader->height; i++)
{
for (int j = 0; j < infoheader->width; j++)
{
size_t offset = rowSize * i + bytesPerPixel * j;
for (size_t k = 0; k < bytesPerPixel; k++)
{
pixelArray[offset + k] = 0;
}
}
}
if (imageSize)
{
*imageSize = pixelArraySize;
}
return pixelArray;
}
int main()
{
char* fileLocation = "test.bmp";
bmp_fileheader header;
bmp_infoheader infoheader;
int readResult = readBitmapHeaders(fileLocation, &header, &infoheader);
if (readResult)
{
return readResult;
}
size_t pixelArraySize;
char* pixelArray = getNewImageData(&infoheader, &pixelArraySize);
if (!pixelArray)
{
printf("%s", "Failed to create the new image data. Exiting with fatal error.\n");
return 1;
}
char* outFile = "out.bmp";
int writeResult = writeBitmap(outFile, &header, &infoheader, pixelArray, pixelArraySize);
free(pixelArray);
return writeResult;
}
I changed the bitmap header file a little to typedef the structs and make life easier (at least for me):
#pragma once
#pragma pack(1)
typedef struct _bmp_fileheader
{
unsigned char fileMarker1; /* 'B' */
unsigned char fileMarker2; /* 'M' */
unsigned int bfSize; /* File's size */
unsigned short unused1;
unsigned short unused2;
unsigned int imageDataOffset; /* Offset to the start of image data */
} bmp_fileheader;
typedef struct _bmp_infoheader
{
unsigned int biSize; /* Size of the info header - 40 bytes */
signed int width; /* Width of the image */
signed int height; /* Height of the image */
unsigned short planes;
unsigned short bitPix;
unsigned int biCompression;
unsigned int biSizeImage; /* Size of the image data */
int biXPelsPerMeter;
int biYPelsPerMeter;
unsigned int biClrUsed;
unsigned int biClrImportant;
} bmp_infoheader;
#pragma pack()
I tried to create a c code that produce 10 sec of C note. But it seem the output .wav file didn't produce any sound.
I'm still new in C programming and it would be helpful if you can point my mistakes.
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
//music note
#define C 261.6256
#define TIME 10
#define POINT 20
#define AMP 10000
#define c 5
//wav file header
typedef struct
{
char ChuckID[4];
unsigned long ChuckSize;
char format[4];
char subChunk1ID[4];
unsigned long SubChunk1Size;
unsigned short AudioFormat;
unsigned short NumChannels;
unsigned long SampleRate;
unsigned long ByteRate;
unsigned short block_allign;
unsigned short bits_per_sample;
char data[4];
unsigned long data_size;
/*char riff_tag[4];
int riff_length;
char wave_tag[4];
char fmt_tag[4];
int fmt_length;
short audio_format;
short num_channels;
int sample_rate;
int byte_rate;
short block_align;
short bits_per_sample;
char data_tag[4];
int data_length;*/
} wavheader;
int main(int argc, char **argv)
{
wavheader wave = {"RIFF",1764036,"WAVE","fmt",16,1,1,44100,176400,4,32,"data",1764000};
float data;
float f = C;
int fs = 44100;
int k;
float *buff;
FILE *out_file = fopen("ongaku.wav","w");
buff = (float*)malloc(sizeof(float)*fs*TIME);
for (k = 0; k<(int)(TIME*fs); k++)
{
data=AMP*sin(2*M_PI*f*k/fs);
//printf("%f\n",data);
}
fwrite(buff,sizeof(float),fs*TIME,out_file);
return 0;
}
I have this working with 8-bit data but unsuccessful with 12/16-bit let alone float data. One thing that's essential, is not to hard code buffer sizes in the header. Other points to watch out for are endian-ness (I happened not to need to adjust), and structure packing (ditto). My use of BPS/8 would also come unstuck when working with 12-bit data.
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#define FREQ 261.6256 // C
//#define FREQ 440.0 // A
#define M_PI 3.14159265358979323846
#define TIME 10
#define AMP 64.0 // don't use max volume
#define MID 128.0 // 8-bit is range 0..255
//#define MID 0.0 // 16-bit is range -32767.. 32767
#define BPS 8
#define CHANNS 1
#define RATE 44100
//wav file header
typedef struct {
char ChuckID[4];
unsigned long ChuckSize;
char format[4];
char subChunk1ID[4];
unsigned long SubChunk1Size;
unsigned short AudioFormat;
unsigned short NumChannels;
unsigned long SampleRate;
unsigned long ByteRate;
unsigned short block_allign;
unsigned short bits_per_sample;
char data[4];
unsigned long data_size;
} wavheader;
int main(int argc, char **argv)
{
int k, samples = RATE * TIME;
double data;
FILE *out_file;
unsigned char *buff;
wavheader wave = {
"RIFF",
36 + samples * CHANNS * BPS/8,
"WAVE",
"fmt ", // "fmt" was error in OP
16,
1,
CHANNS,
RATE,
RATE * CHANNS * BPS/8,
CHANNS * BPS/8,
BPS,
"data",
samples * CHANNS * BPS/8
};
buff = malloc(BPS/8 * samples);
out_file = fopen("ongaku.wav","w");
fwrite(&wave, sizeof(wave), 1, out_file);
for (k=0; k<samples; k++) {
data = MID + AMP * sin(2 * M_PI * FREQ * TIME * k / (double)samples);
buff[k] = (unsigned char)floor(data+0.5);
}
fwrite(buff, BPS/8, samples, out_file);
fclose (out_file);
free (buff);
return 0;
}
Put some data into buff, I guess your data variable is holding that value. and after that
if everything else is working correctly, use
fflush(out_file);
or use
fclose(out_file);
I'm trying to take a BMP file and read it in and then perform an operation on the pixels in it to change its color. My problem is that I am having trouble reading in the data from the file into the two BMP header structures. I'm able to read all the data into the first structure fine, but I get a seg fault when reading into the second. As you can see from the code, the first structure, FILEHEADER, is read to and contains all the correct data it should, but the second struc, BMPInfoHeader, is not being read to correctly. Why is this seg fault occuring?
#include <stdio.h>
#include <stdlib.h>
typedef struct
{ unsigned short int Type; /* Magic identifier */
unsigned int Size; /* File size in bytes */
unsigned short int Reserved1, Reserved2;
unsigned int Offset; /* Offset to data (in B) */
} FILEHEADER; /* 14 Bytes */
typedef struct
{ unsigned int Size; /* Header size in bytes */
int Width, Height; /* Width / Height of image */
unsigned short int Planes; /* Number of colour planes */
unsigned short int Bits; /* Bits per pixel */
unsigned int Compression; /* Compression type */
unsigned int ImageSize; /* Image size in bytes */
int xResolution, yResolution;/* Pixels per meter */
unsigned int Colors; /* Number of colors */
unsigned int ImportantColors;/* Important colors */
} BMPInfoHeader; /* 40 Bytes */
typedef struct
{ unsigned char r; /* Red */
unsigned char b; /* Blue */
unsigned char g; /* Green */
} IMAGE;
int main(int argc, char *argv[]) {
FILE *BMPFile;
FILEHEADER BMPFileHeader;
BMPInfoHeader *InfoHeader;
BMPFile=fopen(argv[1],"rb");
unsigned char *BMPimage;
if (BMPFile==NULL) {
printf("\n\nERROR: File not opened properly\n\n");
return -1;
}
fread(&BMPFileHeader,sizeof(unsigned char),14,BMPFile);
fseek(BMPFile,BMPFileHeader.Offset,SEEK_SET);
fread(InfoHeader,sizeof(unsigned char),40,BMPFile);
if (BMPFileHeader.Type != 0x4D42) {
printf("\n\nERROR with fread\n\n");
return -1;
}
return 0;
}
The problem is that the FILEHEADER you've defined is mis-aligned, so the compiler will insert padding between fields. The normal way to read a bmp header is to split off the 2-byte magic number and read it separately:
typedef struct
{
unsigned int Size; /* File size in bytes */
unsigned short int Reserved1, Reserved2;
unsigned int Offset; /* Offset to data (in B) */
} FILEHEADER; /* 12 Bytes */
:
char Magic[2];
FILEHEADER BMPFileHeader;
fread(Magic, 1, 2, BMPFile);
fread(&BMPFileHeader, 1, 12, BMPFile);
This will still have problems if you run it on a big-endian machine due to byte ordering. For full generality, you need to read the file contents as bytes and construct the multibyte values manually.