dicklyon@604: % Copyright 2013, Google, Inc. dicklyon@604: % Author: Richard F. Lyon dicklyon@604: % dicklyon@604: % This Matlab file is part of an implementation of Lyon's cochlear model: dicklyon@604: % "Cascade of Asymmetric Resonators with Fast-Acting Compression" dicklyon@604: % to supplement Lyon's upcoming book "Human and Machine Hearing" dicklyon@604: % dicklyon@604: % Licensed under the Apache License, Version 2.0 (the "License"); dicklyon@604: % you may not use this file except in compliance with the License. dicklyon@604: % You may obtain a copy of the License at dicklyon@604: % dicklyon@604: % http://www.apache.org/licenses/LICENSE-2.0 dicklyon@604: % dicklyon@604: % Unless required by applicable law or agreed to in writing, software dicklyon@604: % distributed under the License is distributed on an "AS IS" BASIS, dicklyon@604: % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. dicklyon@604: % See the License for the specific language governing permissions and dicklyon@604: % limitations under the License. dicklyon@604: dicklyon@604: function layer_array = SAI_UpdateBuffers(layer_array, seg_naps, seg_num) dicklyon@604: % function layer_array = SAI_UpdateBuffers(layer_array, seg_naps, seg_num) dicklyon@604: % dicklyon@604: % Input/Output: layer_array contains all the coefficients and state for dicklyon@604: % the layer of different time scales of SAI; dicklyon@604: % we might want to separate these as in CARFAC. dicklyon@604: % dicklyon@604: % seg_naps is a new segmeent of NAP from the CAR-FAC to shift into the dicklyon@604: % first layer. Each subsequent layer gets input off the input end of the dicklyon@604: % previous layer, with smoothing and decimation. dicklyon@604: % dicklyon@604: % The segment index seg_num is used to control sub-sampled updates of dicklyon@604: % the larger-scale layers. dicklyon@604: dicklyon@604: n_layers = length(layer_array); dicklyon@604: [seg_len, n_nap_ch] = size(seg_naps); dicklyon@604: dicklyon@604: % Array of what to shift in to first or next layer. dicklyon@604: new_chunk = seg_naps; dicklyon@604: dicklyon@608: gain = 1.05; % gain from layer to layer; could be layer dependent. dicklyon@604: dicklyon@604: %% dicklyon@604: % Decimate using a 2-3-4-filter and partial differencing emphasize onsets: dicklyon@604: kernel = filter([1 1]/2, 1, filter([1 1 1]/3, 1, [1 1 1 1 0 0 0 0]/4)); dicklyon@623: % kernel = kernel + 2*diff([0, kernel]); dicklyon@604: % figure(1) dicklyon@604: % plot(kernel) dicklyon@604: dicklyon@604: %% dicklyon@604: for layer = 1:n_layers dicklyon@604: [n_lags, n_ch] = size(layer_array(layer).nap_buffer); dicklyon@604: if (n_nap_ch ~= n_ch) dicklyon@604: error('Wrong number of channels in nap_buffer.'); dicklyon@604: end dicklyon@604: dicklyon@604: interval = layer_array(layer).update_interval; dicklyon@604: if (0 == mod(seg_num, interval)) dicklyon@604: % Account for 2X decimation and infrequent updates; find number of time dicklyon@604: % points to shift in. Tolerate slip of a fraction of a sample. dicklyon@604: n_shift = seg_len * interval / (2.0^(layer - 1)); dicklyon@604: if layer > 1 dicklyon@604: % Add the leftover fraction before floor. dicklyon@604: n_shift = n_shift + layer_array(layer).nap_fraction; dicklyon@604: layer_array(layer).nap_fraction = n_shift - floor(n_shift); dicklyon@604: n_shift = floor(n_shift); dicklyon@604: % Grab new stuff from new end (big time indices) of previous layer. dicklyon@604: % Take twice as many times as we need, + 5, for decimation, and do dicklyon@623: % smoothing to get new points. dicklyon@604: new_chunk = ... dicklyon@604: layer_array(layer - 1).nap_buffer((end - 2*n_shift - 4):end, :); dicklyon@604: new_chunk = filter(kernel, 1, new_chunk); dicklyon@623: % new_chunk = gain * new_chunk(7:2:end, :); dicklyon@623: % try a little extra smoothing: dicklyon@623: new_chunk = gain * (new_chunk(7:2:end, :) + new_chunk(6:2:(end-1), :))/2; dicklyon@604: dicklyon@604: end dicklyon@604: % Put new stuff in at latest time indices. dicklyon@604: layer_array(layer).nap_buffer = ... dicklyon@604: [layer_array(layer).nap_buffer((1 + n_shift):end, :); ... dicklyon@604: new_chunk]; % this should fit just right if we have n_shift new times. dicklyon@604: end dicklyon@604: end dicklyon@604: dicklyon@604: return dicklyon@604: