Reputation: 3064
I have the following piece of code to convert a raw audio file to wav file:
int MainWindow::rawToWav(const char *rawfn, const char *wavfn, long samplingRate)
{
long chunksize=0x10;
int statusCollect = 0;
struct
{
unsigned short wFormatTag;
unsigned short wChannels;
unsigned long dwSamplesPerSec;
unsigned long dwAvgBytesPerSec;
unsigned short wBlockAlign;
unsigned short wBitsPerSample;
} fmt;
errno_t err;
FILE *raw;
err = fopen_s(&raw, rawfn, "rb");
if(!raw)
return -2;
fseek(raw, 0, SEEK_END);
long bytes = ftell(raw);
fseek(raw, 0, SEEK_SET);
long samplecount = bytes/2;
long riffsize = samplecount*2+0x24;
long datasize = samplecount*2;
FILE *wav;
err = fopen_s(&wav, wavfn, "wb");
if(!wav)
{
fclose(raw);
return -3;
}
fwrite( "RIFF", 1, 4, wav );
fwrite( &riffsize, 4, 1, wav );
fwrite( "WAVEfmt ", 1, 8, wav );
fwrite( &chunksize, 4, 1, wav );
int bitsPerSample = 16;
int bytesPerSample = bitsPerSample/8;
int channel = 2;
fmt.wFormatTag = 1; // PCM
fmt.wChannels = channel; // MONO
fmt.dwSamplesPerSec = samplingRate;
fmt.dwAvgBytesPerSec = samplingRate*channel*bytesPerSample; // 16 bit
fmt.wBlockAlign = channel*bytesPerSample;
fmt.wBitsPerSample = bitsPerSample;
fwrite( &fmt, sizeof(fmt), 1, wav );
fwrite( "data", 1, 4, wav );
fwrite( &datasize, 4, 1, wav );
short buff[1024];
while( !feof(raw) )
{
int cnt=fread(buff,2,1024,raw);
if( cnt == 0 )
break;
fwrite(buff,2,cnt,wav);
}
statusCollect = fclose( raw );
statusCollect += fclose( wav );
return statusCollect;
}
I want to the exactly same operation not on a FILE type data but on a QByteArray type.
So I am trying the following way. First I try to add the wav header on a QByteArray object. Then I upload the raw audio file on the program. Then I add that raw data to the QByteArray object on which I have already added the wav header. Then I save the QByteArray as a wav file.
void MainWindow::rawToWavQT(QByteArray* arr, long samplingRate, long sizeOfRawFile)
{
long chunksize=0x10;
struct
{
unsigned short wFormatTag;
unsigned short wChannels;
unsigned long dwSamplesPerSec;
unsigned long dwAvgBytesPerSec;
unsigned short wBlockAlign;
unsigned short wBitsPerSample;
} fmt;
long samplecount = sizeOfRawFile/2;
long riffsize = samplecount*2+0x24;
long datasize = samplecount*2;
arr->append("RIFF");// fwrite( "RIFF", 1, 4, wav );
arr->append((const char*)&riffsize);// fwrite( &riffsize, 4, 1, wav );
arr->append("WAVEfmt ");// fwrite( "WAVEfmt ", 1, 8, wav );
arr->append((const char*)&chunksize);// fwrite( &chunksize, 4, 1, wav );
int bitsPerSample = 16;
int bytesPerSample = bitsPerSample/8;
int channel = 2;
fmt.wFormatTag = 1; // PCM
fmt.wChannels = channel; // MONO
fmt.dwSamplesPerSec = samplingRate;
fmt.dwAvgBytesPerSec = samplingRate*channel*bytesPerSample; // 16 bit
fmt.wBlockAlign = channel*bytesPerSample;
fmt.wBitsPerSample = bitsPerSample;
arr->append((const char*)&fmt);// fwrite( &fmt, sizeof(fmt), 1, wav );
arr->append("data");// fwrite( "data", 1, 4, wav );
arr->append((const char*)&datasize);// fwrite( &datasize, 4, 1, wav );
}
But this way of adding header to the QByteArray and then adding the raw data is not producing the correct type of wav file as it is not able to be played. What do you think I am doing wrong judging from the second function in which I am doing the same operation as that of on the first function but on QByteArray object rather than on FILE object?
Thanks.
Upvotes: 2
Views: 372
Reputation: 4873
Your data concatenation functions just stop at the first null byte, losing important data and disrupting alignment. Instead, you want to specify a length to append as well, in a similar manner to fwrite
.
Solution: Replace your append()
statements from single const char *
arguments to QByteArray
s constructed using both your data and the length of your data.
Change
arr->append((const char*)&riffsize);
to
arr->append(QByteArray((const char*)&riffsize, 4));
and similarly for the other raw data append
statements.
Upvotes: 2