diff --git a/MATLAB/readSpro.m b/MATLAB/readSpro.m
new file mode 100644
index 0000000..bc5c90f
--- /dev/null
+++ b/MATLAB/readSpro.m
@@ -0,0 +1,128 @@
+function [data, header, varLenHeader] = readSpro(filename)
+%% [data, header, varLenHeader] = READSPRO(filename)
+% Reads spro4 or spro5 feature file.
+% data: An NxM matrix where N is the number of feature vectors, and M is
+% dimension of feature vectors.
+% header: A structure containing three fields:
+% - header.featureSize: M
+% - header.contentFlags: bit letter description of Spro flags
+% - header.frameRate: number of feature vectors per second. 1/(d/1000),
+% where d is "frame shift in ms" in sfbcep command. Default d is 10
+% varLenHeader: A matrix of cells representing variable length header (if
+% provided). Each row of varLenHeader is a 1x2 cell array containing a pair
+% of key-value header field.
+%
+% Here is the list of possible flags within headero.contentFlags:
+% `E' feature vector contains log-energy.
+% `Z' mean has been removed
+% `N' static log-energy has been suppressed (always with `E' and `D')
+% `D' feature vector contains delta coefficients
+% `A' feature vector contains delta-delta coefficients (always with `D')
+% `R' variance has been normalized (always with `Z')
+% reference: http://www.irisa.fr/metiss/guig/spro/spro-4.0.1/spro_3.html#SEC17
+
+
+ %% IMPORTANT: there is a bug in 2010 original implementation of SPro,
+ %% which is actually not consistent with documentation. The bug is that
+ %% contentFlag is 64 bits instead of 32 bits. if you are working with
+ %% original implementation, set BUG_CONTENTFLAGS_64BITS to 1
+ BUG_CONTENTFLAGS_64BITS = 0;
+
+ %% Open stream
+ % From Spro documentations: To avoid byte-order problems, binary parts
+ % of the feature streams, such as the fixed length header and the feature
+ % vectors, are always stored in little-endian format (Intel-like processor)
+ machineFormat = 'l'; % Little-endian
+ fid = fopen(filename,'r',machineFormat);
+ if fid<0
+ error('Cannot open file "%s"',filename);
+ end
+
+ %% Read variable length header (if provided)
+ firstBytes = fread(fid,8,'char');
+ varLenHeaderStr = '';
+ if firstBytes' == uint8('')
+ tmpStr = char(fread(fid,9,'char')');
+ while ~strcmp(tmpStr, '')
+ varLenHeaderStr = strcat(varLenHeaderStr,tmpStr(end));
+ fseek(fid,-8,'cof');
+ tmpStr = char(fread(fid,9,'char')');
+ end
+ varLenHeaderStr = varLenHeaderStr(1:end-length('');
+ fseek(fid,-1,'cof');
+ end
+ else
+ fseek(fid,0,'bof');
+ warning('Missing tag. Can cause problem in working with scopy');
+ end
+ varLenHeader = {};
+ if ~isempty(varLenHeaderStr)
+ vlh_lines = strsplit(varLenHeaderStr,'\n');
+ for lineNum=1:length(vlh_lines)
+ line = vlh_lines{lineNum};
+ lineSegs = strsplit(line,'#');
+ line = lineSegs{1}; % remove possible comment
+ eques = strsplit(line,';');
+ for equNum=1:length(eques)
+ equ = strsplit(eques{equNum},'=');
+ if length(equ)>1
+ varLenHeader{end+1,1} = strtrim(equ{1});
+ varLenHeader{end,2} = strtrim(equ{2});
+ end
+ end
+ end
+ end
+ %% Read Header
+ feaSize = fread(fid,1,'short');
+ if feaSize < 0
+ error('Corrupted Spro header file');
+ end
+ contentFlags = fread(fid,1,'uint32');
+ if BUG_CONTENTFLAGS_64BITS == 1
+ fseek(fid,4,'cof');
+ end
+ frameRate = fread(fid,1,'float32');
+ %% Check data size before reading data
+ dataPos = ftell(fid);
+ fseek(fid,0,'eof');
+ endPos = ftell(fid);
+ if rem(endPos - dataPos,feaSize) ~= 0
+ errorStr = 'Invalid data size. ';
+ if rem(endPos - dataPos,feaSize) == 4
+ errorStr = strcat(errorStr, ...
+ 'it seems you should switch BUG_CONTENTFLAGS_64BITS in code');
+ end
+ error(errorStr);
+ end
+ fseek(fid,dataPos,'bof');
+ %% Read content Flags
+ header.contentFlags = '';
+ if nargout > 1
+ header.featureSize = feaSize;
+ if bitand(contentFlags,hex2dec('01'))
+ header.contentFlags = strcat(header.contentFlags, 'E');
+ end
+ if bitand(contentFlags,hex2dec('02'))
+ header.contentFlags = strcat(header.contentFlags, 'Z');
+ end
+ if bitand(contentFlags,hex2dec('04'))
+ header.contentFlags = strcat(header.contentFlags, 'N');
+ end
+ if bitand(contentFlags,hex2dec('08'))
+ header.contentFlags = strcat(header.contentFlags, 'D');
+ end
+ if bitand(contentFlags,hex2dec('01'))
+ header.contentFlags = strcat(header.contentFlags, 'A');
+ end
+ if bitand(contentFlags,hex2dec('20'))
+ header.contentFlags = strcat(header.contentFlags, 'R');
+ end
+ header.frameRate = frameRate;
+ end
+ %% Read data
+ data = fread(fid,[feaSize Inf],'float32')';
+ %% close stream
+ fclose(fid);
+end
diff --git a/scopy.c b/scopy.c
index a5b0566..156aa2a 100644
--- a/scopy.c
+++ b/scopy.c
@@ -555,9 +555,9 @@ FILE *init_output(const char *ofn, unsigned long nsamples, unsigned short dim, l
_flag = 0;
#ifdef WORDS_BIGENDIAN
- swap_bytes(&_dim, 1, SIZEOF_SHORT);
- swap_bytes(&_flag, 1, SIZEOF_LONG);
- swap_bytes(&_rate, 1, sizeof(float));
+ swap_bytes(&_dim, 1, 2);
+ swap_bytes(&_flag, 1, 4);
+ swap_bytes(&_rate, 1, 4);
#endif
if (vh)
@@ -567,7 +567,7 @@ FILE *init_output(const char *ofn, unsigned long nsamples, unsigned short dim, l
return(NULL);
}
- if (fwrite(&_dim, SIZEOF_SHORT, 1, f) != 1 || fwrite(&_flag, SIZEOF_LONG, 1, f) != 1 || fwrite(&_rate, sizeof(float), 1, f) != 1) {
+ if (fwrite(&_dim, 2, 1, f) != 1 || fwrite(&_flag, 4, 1, f) != 1 || fwrite(&_rate, 4, 1, f) != 1) {
if (f != stdout) fclose(f);
fprintf(stderr, "scopy error -- cannot write header to file %s\n", ofn);
return(NULL);
diff --git a/spf.c b/spf.c
index 323a803..4db2270 100644
--- a/spf.c
+++ b/spf.c
@@ -373,15 +373,15 @@ spfstream_t *spf_input_stream_open(const char *fn, long flag, size_t nbytes)
return(NULL);
}
- if (fread(&(s->idim), SIZEOF_SHORT, 1, s->f) != 1 || fread(&(s->iflag), SIZEOF_LONG, 1, s->f) != 1 || fread(&(s->Fs), sizeof(float), 1, s->f) != 1) {
+ if (fread(&(s->idim), 2, 1, s->f) != 1 || fread(&(s->iflag), 4, 1, s->f) != 1 || fread(&(s->Fs), 4, 1, s->f) != 1) {
fprintf(stderr, "spf_header_read(): cannot read fixed header\n");
spf_stream_close(s);
return(NULL);
}
#ifdef WORDS_BIGENDIAN
- sp_swap(&(s->idim), SIZEOF_SHORT);
- sp_swap(&(s->iflag), SIZEOF_LONG);
- sp_swap(&(s->Fs), sizeof(float));
+ sp_swap(&(s->idim), 2);
+ sp_swap(&(s->iflag), 4);
+ sp_swap(&(s->Fs), 4);
#endif
/* initialize output dimension */
@@ -504,14 +504,14 @@ spfstream_t *spf_output_stream_open(const char *fn, unsigned short idim, long if
rate = s->Fs;
#ifdef WORDS_BIGENDIAN
- sp_swap(&dim, SIZEOF_SHORT);
- sp_swap(&flag, SIZEOF_LONG);
- sp_swap(&rate, sizeof(float));
+ sp_swap(&dim, 2);
+ sp_swap(&flag, 4);
+ sp_swap(&rate, 4);
#endif
- if (fwrite(&dim, SIZEOF_SHORT, 1, s->f) != 1 ||
- fwrite(&flag, SIZEOF_LONG, 1, s->f) != 1 ||
- fwrite(&rate, sizeof(float), 1, s->f) != 1) {
+ if (fwrite(&dim, 2, 1, s->f) != 1 ||
+ fwrite(&flag, 4, 1, s->f) != 1 ||
+ fwrite(&rate, 4, 1, s->f) != 1) {
fprintf(stderr, "spf_output_stream_open() -- cannot write fixed header to %s\n", (fn) ? (fn) : "stdout");
return(NULL);
}