% FUNCTION ZEROCROSSING(FILENAME, [N_CHANNELS], [FRAME_LENGTH], % [FRAME_SHIFT], [BLOCK_SIZE]) % % Compute zero-crossing rate frames of a multi-channel % waveform. Write out results in a file with same base as % FILENAME and extension '.zc%d' where %d is N_CHANNELS. % % This function treats files in a block-per-block basis, % which allows for dealing with large files. % % INPUT: % filename: string, name of the multi-channel waveform raw file. % n_channels: integer, default 1. % frame_length: integer, length of one frame in samples, default 512. % frame_shift: integer, offset between two consecutive frames in % samples, default floor(frame_length / 2). % block_size: integer, number of frames to treat at a time, % default 1000. % % FORMAT OF INPUT FILE: % Result of fwrite(fid, speech, 'int16', 'l') where speech is a % n_channels-by-n_samples matrix of signed 16-bit integers. % ('l' stands for little endian). % % FORMAT OF OUTPUT FILE: % Result of fwrite(fid, zc, 'float64', 'l') where zc is a % n_channels-by-n_frames matrix of floats. % ('l' stands for little endian). % % ZERO-CROSSING RATE CALCULATION: % Per frame & per channel: number of zero-crossing is divided by % frame_length. Note that we weight the zero-crossing values (0 % or 1) with hamming(frame_length - 1) before summing. This gives % more importance to zero-crossings in the middle of the frame. function zerocrossing(filename, n_channels, frame_length, frame_shift, block_size) % Default parameters a = 2; if nargin < a n_channels = 1; end a = a+1; if nargin < a frame_length = 512; end a = a+1; if nargin < a frame_shift = floor(frame_length / 2); end a = a+1; if nargin < a block_size = 1000; end % Open input file & get size fid_in = fopen(filename, 'r'); if fid_in < 0 error(sprintf ... ('zerocrossing(): could not open waveform file %s.\n', filename)); end fseek(fid_in, 0, 'eof'); n_samples = ftell(fid_in) / n_channels / 2; fseek(fid_in, 0, 'bof'); if n_samples < frame_length error('zerocrossing(): not enough samples for even one frame!'); end % Open output file [p,n] = fileparts(filename); filename_out = fullfile(p, [n '.zc' sprintf('%d', n_channels)]); fid_out = fopen(filename_out, 'w'); if fid_out < 0 error(sprintf ... ('zerocrossing(): could not open output file %s.\n', filename_out)); end % Proceed through data block per block (this allows for dealing % with large files) n_frames = 1 + floor((n_samples - frame_length) / frame_shift); disp(sprintf('%d frames to treat', n_frames)); m = repmat(1 + (0:block_size-1) * frame_shift, frame_length , 1); m = m + repmat((0:frame_length-1)', 1, block_size); w = repmat(hamming(frame_length - 1), 1, block_size); last_frame_shift = []; for a = 1:block_size:n_frames n = min(n_frames, a+block_size-1) - a + 1; disp(sprintf('treating frames %d to %d', a, a+n-1)); % Read block of data aux = frame_length + (n - 1 - (1-isempty(last_frame_shift)) ) * frame_shift; [data, count] = fread(fid_in, [n_channels aux], 'int16', 'l'); if count < aux * 8 error('zerocrossing(): reached EOF before expected'); end data = [last_frame_shift, data]; % For each channel, compute zero-crossing rate of each frame for b = 1:n_channels x = data(b, :) / 32768; y = sign(x(m(:, 1:n))); % frame_length-by-n y = .5 * abs(diff(y, 1, 1)); y = y .* w(:, 1:n); zc(b,1:n) = sum(y, 1) / frame_length; end % Append results to the output file fwrite(fid_out, zc(:,1:n), 'float64', 'l'); % Solve overlap between blocks last_frame_shift = data(:, end-frame_shift+1:end); end % Close files fclose(fid_in); fclose(fid_out);