I am reading a collection file (20 or so small files in one) with fread_s and the content is being written in a struct. Like 99% of the times it reads the data correctly, but one time, at always the same position it seems to ignore the byte size of the element size parameter and just reads 500 or so bytes until it aborts and reports a feof error. The thing is, it doesn't even write the last three bytes of the int to the struct.
When I remove the checks, and let it continue reading, it will read normal again, like nothing happened.
I observed that the _Placeholder variable in the file pointer gets changed to a different value, and then back again, but I guess its just the eof error getting packed in there.
#pragma pack(push, 1)
struct fileHeader {
__int32 typeID;
bool isGFX;
char filename[8];
__int32 offset;
};
#pragma pack(pop)
#define HEADERSIZE 68
#define FILEHEADERSIZE 17
....
FILE *file;
fopen_s(&file, filename.c_str(), "r");
for (int i = 0; i < header.files - 1; i++) {
fseek(file, HEADERSIZE + i * FILEHEADERSIZE, 0);
fileHeader headerFile;
memset(&headerFile, 0, FILEHEADERSIZE);
int oldPointer = ftell(file); //118
int d = fread_s(&headerFile, FILEHEADERSIZE, FILEHEADERSIZE, 1, file); //returns 0
int newPointer = ftell(file); //630
int e = errno; //0
int ea = ferror(file); //0
int ef = feof(file); //1
//getting used here in a function
}
headerFile = {typeID=17 isGFX=true filename=0x00fefd05 "CURSORR" offset = 164} - offset should be 6820
Like Jonathan Leffler said in the comments, the mistake was, that I didn't read in binary mode. a simple change fopen_s(&file, filename.c_str(), "r"); to fopen_s(&file, filename.c_str(), "rb"); fixed the problem.
Related
I have been having some issues with trying to read data out of a binary file that is structured so that the header is the first 1024, or 4069 bytes, and the payloads are all regular blocks after that. Below is a model of the code that I have been using:
Header:
#pragma once
#include <stdio.h>
#include <iostream>
#include <fstream>
class BinaryFile
{
public:
long MagicNumber;
long HeaderSize;
long PayloadSize;
//... about 20 other header details
char* Padding; // unused area of the header that is reserved for future use
std::ifstream BinaryFileStream;
BinaryFile();
int Open_Binary_File(const char* path);
int Load_Payload_Into_Buffer(int payload_index, void* buffer);
};
And the C++ code that I have tried to use:
#include "BinaryFile.h"
BinaryFile:BinaryFile()
{
MagicNumber = 0;
HeaderSize = 1024;
PayloadSize = 62830080;
// ... all the other header items, initalized with default values
std:ifstream BinaryFileStream;
Padding[360];
}
int BinaryFile::Open_Binary_File(const char* path) // This is the one that I would like to be using
{
BinaryFileStream.open(path, std::ifstream::binary);
BinaryFileStream.read((char*)&MagicNumber, (size_t) 4);
BinaryFileStream.read((char*)&HeaderSize, (size_t) 4);
// ... The rest of the header is placed into the object
BinaryFileStream.read((char*)&Padding, (size_t) 360);
// The file pointer should now be 1024 bytes into the file, at the end of the header, and at the start of the first payload
return 0;
}
int Load_Payload_Into_Buffer(int payload_index, void* buffer)
{
buffer = malloc(PayloadSize);
size_t offset = HeaderSize + static_cast<long long>(frame_index) * PayloadSize;
BinaryFileStream.seekg(offset, BinaryFileStream.beg);
BinaryFileStream.read((char*)buffer, PayloadSize);
return 0;
Error:
return 1;
}
Below are some variations that I have tried:
int BinaryFile::Open_Binary_File(const char* path)
{
BinaryFileStream.open(path, std::ifstream::binary);
BinaryFileStream.read((char*)&MagicNumber, (size_t) 4);
BinaryFileStream.read((char*)&HeaderSize, (size_t) 4);
// ... The rest of the header is placed into the object
BinaryFileStream.read((char*)&Padding, (size_t) 360);
BinaryFileStream.clear();
BinaryFileStream._Seekbeg.seekg((size_t)0, BinaryFileStream._Seekbeg);
BinaryFileStream.sync();
// The file pointer should now be 0 bytes into the file, at the start of the header
return 0;
}
int BinaryFile::Open_Binary_File(const char* path)
{
BinaryFileStream.open(path, std::ifstream::binary);
BinaryFileStream.read((char*)&MagicNumber, (size_t) 4);
BinaryFileStream.read((char*)&HeaderSize, (size_t) 4);
// ... The rest of the header is placed into the object
BinaryFileStream.read((char*)&Padding, (size_t) 360);
BinaryFileStream.clear();
BinaryFileStream.seekg((size_t)-1024);
BinaryFileStream.sync();
// The file pointer should now be 0 bytes into the file, at the start of the header
return 0;
}
The issue that I am running into to is, the payload that is being returned to the buffer contains some of the next payload. The setting of the file pointer doesn't seem to be working the way that I expect it to. i.e. if I say
BinaryFileStream._Seekbeg.seekg(position, BinaryFileStream._Seekbeg)
I expect the pointer to return to the start of the file, and then seek along the number of bytes that I have said in position. Is there a different way to do this? or is there something that I am missing?
Turns out, what I needed to do was multiply the HeaderSize by CHAR_BIT so it would look something like this:
int Load_Payload_Into_Buffer(int payload_index, void* buffer)
{
buffer = malloc(PayloadSize);
size_t offset = HeaderSize*CHAR_BIT + static_cast<long long>(frame_index) * PayloadSize;
BinaryFileStream.seekg(offset, BinaryFileStream.beg);
BinaryFileStream.read((char*)buffer, PayloadSize);
return 0;
Error:
return 1;
}
And what I thought was a portion of the next payload , was in fact the same payload, but split at some arbitrary point, and stacked next to it. So the payload was split approx. 3/4 of the way through, and it was then re-arranged, so that the original last quarter was now at in the first position, and the original first 3/4 was now in the 2nd position.
Hopefully that makes some sense, and will help someone in the future!
I am trying to copy a WAV sound in C. the original file is a 2 seconds file, but I want to replicate the data in the destination file several times, so that it plays longer. For example, if I copy it 3 times, it should play for 6 seconds... right?
But for some reason, even though the destination file is bigger than the original file, it still plays for 2 seconds...
Can anyone help please?
Here is my code:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
typedef 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;
} header;
typedef struct header_file* header_p;
int main()
{
FILE * infile = fopen("../files/man1_nb.wav","rb"); // Open wave file in read mode
FILE * outfile = fopen("../files/Output.wav","wb"); // Create output ( wave format) file in write mode
int BUFSIZE = 2; // BUFSIZE can be changed according to the frame size required (eg: 512)
int count = 0; // For counting number of frames in wave file.
short int buff16[BUFSIZE]; // short int used for 16 bit as input data format is 16 bit PCM audio
header_p meta = (header_p)malloc(sizeof(header)); // header_p points to a header struct that contains the wave file metadata fields
int nb; // variable storing number of byes returned
if (infile)
{
fread(meta, 1, sizeof(header), infile); // Read only the header
fwrite(meta,1, sizeof(*meta), outfile); // copy header to destination file
int looper = 0; // number of times sound data is copied
for(looper=0; looper <2; looper++){
while (!feof(infile))
{
nb = fread(buff16,1,BUFSIZE,infile); // Reading data in chunks of BUFSIZE
count++; // Incrementing Number of frames
fwrite(buff16,1,nb,outfile); // Writing read data into output file
}
fseek(infile, 44, SEEK_SET); // Go back to end of header
}
}
fclose(infile); fclose(outfile);
return 0;
}
Both of your read and write code parts are wrong.
wav files have RIFF format and consists of tlv chunks. Each chunk consists of header and data. Typically wav file consists of 3 chunks: format chunk with FOURCC code, format chunk with PCMWAVEFORMAT struct and data chunk with sound data. Also since size of each chunk is limited by 32 bit of length holding field, large files are constructed by concatenating wav files together.
You need to parse file chunk-by-chunk, and write into destination chunk-by-chunk, updating headers accordingly.
When you change size of your data you'll need to update output header as well.
long total_bytes_written_to_outfile = ftell(outfile);
// correct chunk_size and subchunk2_size just before closing outfile:
fseek(outfile, 0, SEEK_SET);
int size = total_bytes_written_to_outfile - sizeof(*meta);
meta->chunk_size = sizeof(header) - sizeof(meta->chunk_id) - sizeof(meta->chunk_size) + size;
meta->subchunk2_size = size;
fwrite(meta, 1, sizeof(*meta), outfile);
fclose(outfile);
Also, to make sure you are reading correct file check that meta->chunk_size == file size of man1_nb.wav - 8
I'm reading a bunch of bit values from a text file which are in binary from because I stored them using fwrite. The problem is that the first value in the file is 5 bytes in size and the next 4800 values are 2 bytes in size. So when I try to cycle through the file and read the values it will give me the wrong results because my program does not know that it should take 5 bytes the first time and then 2 bytes the remaining 4800 times.
Here is how I'm cycling through the file:
long lSize;
unsigned short * buffer;
size_t result;
pFile = fOpen("dataValues.txt", "rb");
lSize = ftell(pFile);
buffer = (unsigned short *) malloc (sizeof(unsigned short)*lSize);
size_t count = lSize/sizeof(short);
for(size_t i = 0; i < count; ++i)
{
result = fread(buffer+i, sizeof(unsigned short), 1, pFile);
print("%u\n", buffer[i]);
}
I'm pretty sure I'm going to need to change my fread statement because the first value is of type time_t so I'll probably need a statement that looks like this:
result = fread(buffer+i, sizeof(time_t), 1, pFile);
However, this did not work work when I tried it and I think it's because I am not changing the starting position properly. I think that while I do read 5 bytes worth of data, I don't move the starting position enough.
Does anyone here have a good understanding of fread? Can you please let me know what I can change to make my program accomplish what I need.
EDIT:
This is how I'm writing to the file.
fwrite(&timer, sizeof(timer), 1, pFile);
fwrite(ptr, sizeof(unsigned short), rawData.size(), pFile);
EDIT2:
I tried to read the file using ifstream
int main()
{
time_t x;
ifstream infile;
infile.open("binaryValues.txt", ios::binary | ios::in);
infile.read((char *) &x, sizeof(x));
return 0;
}
However, now it doesn't compile and just give me a bunch of undefined reference to errors to code that I don't even have written.
I don't see the problem:
uint8_t five_byte_buffer[5];
uint8_t two_byte_buffer[2];
//...
ifstream my_file(/*...*/);
my_file.read(&five_byte_buffer[0], 5);
my_file.read(&two_byte_buffer[0], 2);
So, what is your specific issue?
Edit 1: Reading in a loop
while (my_file.read(&five_byte_buffer[0], 5))
{
my_file.read(&two_byte_buffer[0], 5);
Process_Data();
}
You can't. Streams are byte, almost always octet (8 bit byte) oriented.
You can easily enough build a bit-oriented stream on top of that. You just keep a few bytes in a buffer and keep track of which bit is current. Watch out for getting the last few bits, and attempts to mix byte access with bit access.
Untested but this is the general idea.
struct bitstream
{
unsigned long long rack; // 64 bits rack
FILE *fp; // file opened for reading
int rackpos; // 0 - 63, poisition of bits read.
}
int getbits(struct bitstream *bs, int Nbits)
{
unsigned long long mask = 0x8000 0000 0000 0000;
int answer = 0;
while(bs->rackpos > 8)
{
bs->rack <<= 8;
bs->rack |= fgetc(bs->fp);
bs->rackpos -= 8;
}
mask >>= bs->rackpos;
for(i=0;i<Nbits;i++)
{
answer <<= 1;
answer |= bs->rack & mask;
mask >>= 1;
}
bs->rackpos += Nbits;
return answer;
}
You need to decide how you know when the stream is terminated. As is you'll corrupt the last few bits with the EOF read by fgetc().
I am trying to get sound from simple tapping keyboard. Looks like a little drum machine.
If DirectSound is not a proper way to do this, please suggest something else.
In my code I don't know what's wrong. Here it is without error checking and with translations:
//Declaring the IDirectSound object
IDirectSound* device;
DirectSoundCreate(NULL, &device, NULL);
device->SetCooperativeLevel(hWnd, DSSCL_NORMAL );
/* Declaring secondary buffers */
IDirectSoundBuffer* kickbuf;
IDirectSoundBuffer* snarebuf;
/* Declaring .wav files pointers
And to structures for reading the information int the begining of the .wav file */
FILE* fkick;
FILE* fsnare;
sWaveHeader kickHdr;
sWaveHeader snareHdr;
The structure sWaveHeader is declared this way:
typedef struct sWaveHeader
{
char RiffSig[4]; // 'RIFF'
unsigned long WaveformChunkSize; // 8
char WaveSig[4]; // 'WAVE'
char FormatSig[4]; // 'fmt '
unsigned long FormatChunkSize; // 16
unsigned short FormatTag; // WAVE_FORMAT_PCM
unsigned short Channels; // Channels
unsigned long SampleRate;
unsigned long BytesPerSec;
unsigned short BlockAlign;
unsigned short BitsPerSample;
char DataSig[4]; // 'data'
unsigned long DataSize;
} sWaveHeader;
The .wav file opening
#define KICK "D:/muzic/kick.wav"
#define SNARE "D:/muzic/snare.wav"
fkick = fopen(KICK, "rb")
fsnare = fopen(SNARE, "rb")
Here I make a function that does the common work for snarebuf* and **kickbuf
int read_wav_to_WaveHeader (sWaveHeader* , FILE* , IDirectSoundBuffer* ); // The declaring
But I wil not write this function, just show the way it works with kickbuf, for instance.
fseek(fkick, 0, SEEK_SET); // Zero the position in file
fread(&kickHdr, 1, sizeof(sWaveHeader), fkick); // reading the sWaveHeader structure from file
Here goes a checking for fitting if sWaveHeader structure:
if(memcmp(pwvHdr.RiffSig, "RIFF", 4) ||
memcmp(pwvHdr.WaveSig, "WAVE", 4) ||
memcmp(pwvHdr.FormatSig, "fmt ", 4) ||
memcmp(pwvHdr.DataSig, "data", 4))
return 1;
Declaring the format and descriptor for a buffer and filling them:
DSBUFFERDESC bufDesc;
WAVEFORMATEX wvFormat;
ZeroMemory(&wvFormat, sizeof(WAVEFORMATEX));
wvFormat.wFormatTag = WAVE_FORMAT_PCM;
wvFormat.nChannels = kickHdr.Channels;
wvFormat.nSamplesPerSec = kickHdr.SampleRate;
wvFormat.wBitsPerSample = kickHdr.BitsPerSample;
wvFormat.nBlockAlign = wvFormat.wBitsPerSample / 8 * wvFormat.nChannels;
ZeroMemory(&bufDesc, sizeof(DSBUFFERDESC));
bufDesc.dwSize = sizeof(DSBUFFERDESC);
bufDesc.dwFlags = DSBCAPS_CTRLVOLUME |
DSBCAPS_CTRLPAN |
DSBCAPS_CTRLFREQUENCY;
bufDesc.dwBufferBytes = kickHdr.DataSize;
bufDesc.lpwfxFormat = &wvFormat;
Well, the creating of a buffer:
device->CreateSoundBuffer(&bufDesc, &kickbuf, NULL); // Any mistakes by this point?
Now locking the buffer and loading some data to it.
This data starts after sizeof(sWaveHeader) bytes in a WAVE file, am I wrong?
LPVOID Ptr1; // pointer on a pointer on a First block of data
LPVOID Ptr2; // pointer on a pointer on a Second block of data
DWORD Size1, Size2; // their sizes
Now calling the Lock() method:
kickbuf->Lock((DWORD)LockPos, (DWORD)Size,
&Ptr1, &Size1,
&Ptr2, &Size2, 0);
Loading data (is it ok?):
fseek(fkick, sizeof(sWaveHeader), SEEK_SET);
fread(Ptr1, 1, Size1, fkick);
if(Ptr2 != NULL)
fread(Ptr2, 1, Size2, fkick);
Unlocking the buffer:
kickbuf->Unlock(Ptr1, Size1, Ptr2, Size2);
Setting the volume:
kickbuf->SetVolume(-2500);
Then I make a wile(1) looping:
1. ask for a key pressing
2. if it is pressed:
kickbuf->SetCurrentPosition(0)
kickbuf->Play(0,0,0);
But there's no sound playing, please say, what is not proper in my code or maybe in the whole concept. Thank you.
When you initialize the WAVEFORMATEX, your are forgetting to set the nAvgBytesPerSec member. Add this line after the initialization of wvFormat.nBlockAlign:
wvFormat.nAvgBytesPerSec = wvFormat.nSamplesPerSec * wvFormat.nBlockAlign;
Also, I suspect this could be a problem:
kickbuf->SetVolume(-2500);
I suspect that will just attenuate your sample to absolute silence. Try taking that call out so that it plays at full volume.
But more likely, none of you sample code above shows validation of the return values from any of the DirectSound APIs, nor any of the file I/O values. Have you validated the HRESULTs returned by all the DSound APIs are returning S_OK? Have you tried printing or using OutputDebugString to print the values you computed for the members of WAVEFORMATEX?
Have you debugging the fread calls to validate that you are getting valid data into your buffers?
Hope this helps.
I'm trying to read a big binary file made of 30e6 positions, each with 195 doubles.
Since the file is too big to read all into memory, I'm reading it by chunks of 10000 positions. I then do some calculation with it and read the next chunk....
Since I need random access to the file, I've written a function to read a given chunk (unsigned int chunk) from the file and store it in **chunk_data. the function returns the total number of positions read.
unsigned int read_chunk(double **chunk_data, unsigned int chunk) {
FILE *in_glf_fh;
unsigned int total_bytes_read = 0;
// Define chunk start and end positions
unsigned int start_pos = chunk * 10000;
unsigned int end_pos = start_pos + 10000 - 1;
unsigned int chunk_size = end_pos - start_pos + 1;
// Open input file
in_glf_fh = fopen(in_glf, "rb");
if( in_glf_fh == NULL )
error("ERROR: cannot open file!");
// Search start position
if( fseek(in_glf_fh, start_pos * 195 * sizeof(double), SEEK_SET) != 0 )
error("ERROR: cannot seek file!");
// Read data from file
for(unsigned int c = 0; c < chunk_size; c++) {
unsigned int bytes_read = fread ( (void*) chunk_data[c], sizeof(double), 195, in_glf_fh);
if( bytes_read != 195 && !feof(in_glf_fh) )
error("ERROR: cannot read file!");
total_bytes_read += bytes_read;
}
fclose(in_glf_fh);
return( total_bytes_read/195 );
}
The problem is, after reading some chunks, fread() starts giving the wrong values!
Also, depending on the chunk size, the positions where fread() starts behaving strangely differs:
chunk of 1 pos, wrong at chunk 22025475
chunk of 10000 pos, wrong at chunk 2203
chunk of 100000 pos, wrong at chunk 221
Anyone has any idea of what might be going on?
After determining that 30e6 positions was not hex, and instead 30,000,000: consider the problem of fseek(): The file has 46,800,000,000 bytes. The plain vanilla fseek() (on 16- and 32-bit platforms) is limited to the first 2^32-1 bytes (=4,294,967,295).
Depending on the platform the program runs on, you might have to use lseek64 or its equivalent. On Linux, there are
using lseek() with
#define _FILE_OFFSET_BITS 64
llseek()
lseek64()