mirror of
https://github.com/thestk/stk
synced 2026-01-11 20:11:52 +00:00
215 lines
5.8 KiB
C++
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");
|
|
}
|
|
}
|