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); }