1
/*******************************************/
2
/* MatWvIn Input Class, */
3
/* by Gary P. Scavone, 1999 */
5
/* This object inherits from WvIn and is */
6
/* used to open Matlab MAT-file data */
7
/* (doubles) files for playback. In */
8
/* order for this class to work, the */
9
/* MAT-file must contain a single array */
10
/* (matrix) of double-precision floating */
11
/* point values (can be multi-channel). */
12
/* It does not work for any other data */
15
/* MAT-file data is either big- or */
16
/* little-endian, which can be determined */
17
/* from the header. */
18
/*******************************************/
23
MatWvIn :: MatWvIn(char *fileName, char *mode)
28
if ( strcmp(mode,"oneshot") && strcmp(mode,"looping") ) {
29
sprintf(msg, "MatWvIn: constructor parameter 'mode' must be oneshot or looping only.\n");
30
throw StkError(msg, StkError::FUNCTION_SYNTAX);
33
// Open the file and get header info
34
fd = fopen(fileName,"rb");
36
sprintf(msg, "MatWvIn: Couldn't open or find MAT-file (%s).\n", fileName);
37
throw StkError(msg, StkError::FILE_NOT_FOUND);
40
// Make sure this is a version 5 MAT-file format and find its endian-ness
43
fread(&head,4,1,fd); // If any of the first 4 characters of the header = 0,
44
if (strstr(head,"0")) { // then this is a Version 4 MAT-file.
46
sprintf(msg, "MatWvIn: %s appears to be a Version 4 \nMAT-file, which is not currently supported.\n",
48
throw StkError(msg, StkError::FILE_ERROR);
52
fseek(fd,126,SEEK_SET); // Locate "M" and "I" characters in header
54
#ifdef __LITTLE_ENDIAN__
55
if (!strncmp(mi,"MI",2)) {
57
} else if (strncmp(mi,"IM",2)) {
59
sprintf(msg, "MatWvIn: %s doesn't appear to be a MAT-file.\n", fileName);
60
throw StkError(msg, StkError::FILE_ERROR);
63
if (!strncmp(mi,"IM",2)) {
65
} else if (strncmp(mi,"MI",2)) {
67
sprintf(msg, "MatWvIn: %s doesn't appear to be a MAT-file.\n", fileName);
68
throw StkError(msg, StkError::FILE_ERROR);
72
// Check the data element type
74
fread(&datatype,4,1,fd);
75
if (doSwap) swap32((unsigned char *)&datatype);
78
sprintf(msg, "MatWvIn: I'm expecting a single array (or matrix) data element.\n");
79
throw StkError(msg, StkError::FILE_ERROR);
82
// Check the array data type
85
fseek(fd,168,SEEK_SET);
87
if (doSwap) swap32((unsigned char *)&tmp);
88
if (tmp == 1) { // array name > 4 characters
89
fread(&tmp,4,1,fd); // get array name length
90
if (doSwap) swap32((unsigned char *)&tmp);
91
size = (INT32) ceil((float)tmp/8);
92
fseek(fd,size*8,SEEK_CUR); // jump over array name
94
else { // array name <= 4 characters, compressed data element
98
if (doSwap) swap32((unsigned char *)&tmp);
101
sprintf(msg, "MatWvIn: I'm expecting the array data to be in double precision floating-point format.\n");
102
throw StkError(msg, StkError::FILE_ERROR);
105
// Get number of rows from the header
107
fseek(fd,160,SEEK_SET);
109
if (doSwap) swap32((unsigned char *)&rows);
111
// Get number of columns from the header
113
fread(&columns,4,1,fd); // columns
114
if (doSwap) swap32((unsigned char *)&columns);
116
// Make channels = smaller of rows or columns
117
if (rows < columns) {
127
bufferSize = fileSize;
129
if ((fileSize*channels) > MAX_FILE_LOAD_SIZE) {
130
printf("\nMatWvIn: The MAT-file (%s) has more than %d samples and\n",
131
fileName, MAX_FILE_LOAD_SIZE);
132
printf("will be loaded incrementally from disk. Normalization will be disabled.\n");
134
bufferSize = LOAD_BUFFER_SIZE;
137
// Setup for looping or one-shot playback
138
if (!strcmp(mode,"looping"))
140
else // default = oneshot
143
data = (MY_FLOAT *) new MY_FLOAT[(bufferSize+1)*channels];
145
// Move read pointer to the data in the file
147
fseek(fd,132,SEEK_SET);
148
fread(&headsize,4,1,fd); // file size from 132nd byte
149
if (doSwap) swap32((unsigned char *)&headsize);
150
headsize -= fileSize * 8 * channels;
151
fseek(fd,headsize,SEEK_CUR);
152
dataOffset = ftell(fd);
154
this->getData(0); // Read samples into data[]
156
rate = (MY_FLOAT) 1.0;
158
phaseOffset = (MY_FLOAT) 0.0;
159
lastOutput = (MY_FLOAT *) new MY_FLOAT[channels];
163
MatWvIn :: ~MatWvIn()
167
void MatWvIn :: getData(long index)
169
/* Compare index to current readPointer and modify as needed.
170
* The following while() loops will only execute on calls subsequent
171
* to class instantiation ... and thus, only when "chunking".
173
while (index < readPointer) {
174
readPointer -= LOAD_BUFFER_SIZE;
175
bufferSize = LOAD_BUFFER_SIZE;
176
if (readPointer < 0) {
177
bufferSize += readPointer;
181
while (index >= readPointer+bufferSize) {
182
readPointer += LOAD_BUFFER_SIZE;
183
bufferSize = LOAD_BUFFER_SIZE;
184
if (readPointer+LOAD_BUFFER_SIZE >= fileSize) {
185
bufferSize = fileSize - readPointer;
189
long length = bufferSize;
190
int end_of_file = (readPointer+bufferSize == fileSize);
191
if (!end_of_file) length += 1;
193
// Read samples into data[]. Use MY _FLOAT data structure to store doubles
194
double *buf = (double *)data;
196
fseek(fd, dataOffset+(long)(readPointer*channels*8), SEEK_SET);
197
fread(data, 8, length*channels, fd);
198
for (int i=length*channels-1; i>=0; i--) {
200
swap64((unsigned char *)(buf+i));
208
fseek(fd, dataOffset+(long)(readPointer*8), SEEK_SET);
209
while (j < channels) {
211
if (doSwap) swap64((unsigned char *)&temp);
212
data[channels*i+j] = (MY_FLOAT) temp;
217
fseek(fd, dataOffset+(long)(((j*fileSize)+readPointer)*8), SEEK_SET);
222
// fill in the extra sample frame for interpolation
224
for (int j=0; j<channels; j++)
226
data[bufferSize*channels+j] = data[j];
228
data[bufferSize*channels+j] = data[(bufferSize-1)*channels+j];