Files
stk/MatWvOut.cpp
Gary Scavone ea749b71d2 Version 2.01
2013-09-29 22:39:45 +02:00

215 lines
5.8 KiB
C++

/*******************************************/
/* Matlab MAT File Output Class, */
/* by Gary P. Scavone, 1998. */
/* This object creates a Matlab MAT-file */
/* structure and fills it with buffers of */
/* samples (doubles). */
/* */
/* The Matlab MAT-file format is not */
/* available to the general public. I */
/* spent several days reverse-engineering */
/* the file format to create this class. */
/* I couldn't figure out what a few of */
/* the header fields correspond to, but */
/* for the purposes of STK, this */
/* shouldn't create any problems. */
/*******************************************/
#include "MatWvOut.h"
/******** Matlab Matfile Header Struct *******/
struct matheaderform {
char heading[124];
short a[2];
long b[10];
/* There's more, but it's of variable length */
};
FILE *openMatFile(int chans,char *fileName) {
struct matheaderform hdr;
FILE *fd;
char tempName[128];
int i, namelen;
long longtmp, headsize;
strcpy(hdr.heading,"MATLAB 5.0 MAT-file, Generated by STK98. This file format was hacked by Gary P. Scavone, CCRMA, Stanford University, 1998.");
for (i=strlen(hdr.heading);i<124;i++) hdr.heading[i] = ' ';
hdr.a[0] = (short) 256;
hdr.a[1] = (short) 'M';
hdr.a[1] <<= 8;
hdr.a[1] += 'I';
hdr.b[0] = (long) 14;
hdr.b[1] = (long) 0; /* Size of file after this point to end (in bytes) */
hdr.b[2] = (long) 6;
hdr.b[3] = (long) 8;
hdr.b[4] = (long) 6;
hdr.b[5] = (long) 0;
hdr.b[6] = (long) 5;
hdr.b[7] = (long) 8;
hdr.b[8] = (long) chans; /* This is the number of rows */
hdr.b[9] = (long) 0; /* This is the number of columns */
strcpy(tempName,fileName);
strcat(tempName,".mat");
fd = fopen(tempName,"w+b");
if (!fd) {
printf("Couldn't create matfile %s !!!!!!!!\n",fileName);
exit(0);
}
printf("Creating matfile %s.\n", tempName);
fwrite(&hdr,sizeof(char),168,fd); /* Write the fixed portion of the header */
/* The next 4 bytes can be viewed as two shorts, but they are byteswapped
as a long. The first short value seems to always be one; the second
short will be the length of the variable name IF IT IS <= 4; if the
variable name length is >4, this short is zero and the length is put
in the next 4 bytes. The variable name length is limited to 31
characters (32 with a '\n'). The actual variable name then follows.
The variable name is "zero-padded" out to the following minimum
lengths (in bits): 4, 8, 16, 24, 32.
*/
namelen = strlen(fileName);
if (namelen > 31) { /* Check length of variable name (file name) */
fprintf(stderr, "File name too long ... should be 31 characters or less.\n");
fclose(fd);
exit(0);
}
if (namelen > 4) {
longtmp = 1;
fwrite(&longtmp,sizeof(long),1,fd);
fwrite(&namelen,sizeof(long),1,fd);
headsize = 44 + namelen;
} else {
longtmp = namelen;
longtmp <<= 16;
longtmp += 1;
fwrite(&longtmp,sizeof(long),1,fd);
headsize = 40 + namelen;
}
fwrite(fileName,sizeof(char),namelen,fd); /* Write the variable (file) name */
if (namelen < 5)
longtmp = 4 - namelen;
else if (namelen < 9)
longtmp = 8 - namelen;
else if (namelen < 17)
longtmp = 16 - namelen;
else if (namelen < 25)
longtmp = 24 - namelen;
else longtmp = 32 - namelen;
headsize += longtmp + 8; /* Add length (8) of following bytes */
fseek(fd,longtmp,SEEK_CUR);
longtmp = 9;
fwrite(&longtmp,sizeof(long),1,fd);
longtmp = 0; /* Size of data in bytes (8 per sample) */
fwrite(&longtmp,sizeof(long),1,fd);
fseek(fd,132,SEEK_SET);
fwrite(&headsize,sizeof(long),1,fd); /* Write header size ... will update at end */
fseek(fd,0,SEEK_END);
return fd;
}
MatWvOut :: MatWvOut(char *fileName)
{
chans = 1;
pan = 0.5;
fd = openMatFile(chans,fileName);
counter = 0;
totalCount = 0;
}
MatWvOut :: MatWvOut(int channels, char *fileName)
{
chans = channels;
pan = 0.5;
fd = openMatFile(chans,fileName);
counter = 0;
totalCount = 0;
}
MatWvOut :: ~MatWvOut()
{
double temp;
long headsize, temp1;
fwrite(data,sizeof(double),counter,fd);
temp = (double) totalCount * ONE_OVER_SRATE;
printf("%f Seconds Computed\n",temp);
fseek(fd,164,SEEK_SET);
fwrite(&totalCount,sizeof(long),1,fd); /* Write number of columns */
fseek(fd,132,SEEK_SET);
fread(&headsize,sizeof(long),1,fd);
temp1 = headsize;
headsize += (long) (totalCount * 8 * 2);
fseek(fd,132,SEEK_SET);
fwrite(&headsize,sizeof(long),1,fd); /* Write file size (minus some header info) */
fseek(fd,temp1+128,SEEK_SET);
temp1 = totalCount * 8 * 2;
fwrite(&temp1,sizeof(long),1,fd); /* Write data size (in bytes) */
fclose(fd);
}
long MatWvOut :: getCounter()
{
return totalCount;
}
MY_FLOAT MatWvOut :: getTime()
{
return (MY_FLOAT) totalCount * ONE_OVER_SRATE;
}
void MatWvOut :: tick(MY_FLOAT sample)
{
if (chans==1) {
data[counter++] = (double) (sample);
}
else {
data[counter++] = (double) (sample * (1.0 - pan));
data[counter++] = (double) (sample * pan);
}
totalCount += 1;
if (counter == MAT_BUFFER_SIZE) {
fwrite(data,sizeof(double),MAT_BUFFER_SIZE,fd);
counter = 0;
}
}
void MatWvOut :: tick(MY_FLOAT lsamp, MY_FLOAT rsamp)
{
if (chans==1) {
data[counter++] = (double) (lsamp + rsamp);
}
else {
data[counter++] = (double) (lsamp);
data[counter++] = (double) (rsamp);
}
totalCount += 1;
if (counter == MAT_BUFFER_SIZE) {
fwrite(data,sizeof(double),MAT_BUFFER_SIZE,fd);
counter = 0;
}
}
void MatWvOut :: setMonoPan(MY_FLOAT aPan)
{
pan = aPan;
if (aPan < 0.0) {
pan = 0.0;
printf("Pan < 0.0, correcting to 0.0\n");
}
if (aPan > 1.0) {
pan = 1.0;
printf("Pan > 1.0, correcting to 1.0\n");
}
}