annotate matlab/bmm/carfac/SAI_RunLayered.m @ 635:0bdd58ee6e92

ffmpeg no longer accepts a qscale value of 0. Changed qscale to 1, which also gives a very high quality output
author sness@sness.net
date Fri, 24 May 2013 22:38:09 +0000
parents 68bc9e908578
children 6206696d42ac
rev   line source
dicklyon@604 1 % Copyright 2013, Google, Inc.
dicklyon@604 2 % Author: Richard F. Lyon
dicklyon@604 3 %
dicklyon@604 4 % This Matlab file is part of an implementation of Lyon's cochlear model:
dicklyon@604 5 % "Cascade of Asymmetric Resonators with Fast-Acting Compression"
dicklyon@604 6 % to supplement Lyon's upcoming book "Human and Machine Hearing"
dicklyon@604 7 %
dicklyon@604 8 % Licensed under the Apache License, Version 2.0 (the "License");
dicklyon@604 9 % you may not use this file except in compliance with the License.
dicklyon@604 10 % You may obtain a copy of the License at
dicklyon@604 11 %
dicklyon@604 12 % http://www.apache.org/licenses/LICENSE-2.0
dicklyon@604 13 %
dicklyon@604 14 % Unless required by applicable law or agreed to in writing, software
dicklyon@604 15 % distributed under the License is distributed on an "AS IS" BASIS,
dicklyon@604 16 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
dicklyon@604 17 % See the License for the specific language governing permissions and
dicklyon@604 18 % limitations under the License.
dicklyon@604 19
dicklyon@604 20 function [frame_rate, num_frames] = SAI_RunLayered(CF, input_waves)
ronw@633 21 % function [CF, SAI_movie] = CARFAC_RunLayered(CF, input_waves)
dicklyon@604 22 % This function runs the CARFAC and generates an SAI movie, dumped as PNG
dicklyon@604 23 % files for now.
ronw@634 24 %
ronw@634 25 % Computes a "layered" SAI composed of images computed at several
ronw@634 26 % time scales.
ronw@634 27 %
dicklyon@604 28 % Layer 1 is not decimated from the 22050 rate; subsequent layers have
ronw@633 29 % smoothing and 2X decimation each. All layers get composited together
dicklyon@604 30 % into movie frames.
dicklyon@604 31
dicklyon@604 32 n_ch = CF.n_ch;
dicklyon@604 33 [n_samp, n_ears] = size(input_waves);
dicklyon@604 34 if n_ears ~= CF.n_ears
dicklyon@604 35 error('bad number of input_waves channels passed to CARFAC_Run')
dicklyon@604 36 end
dicklyon@604 37 fs = CF.fs;
dicklyon@604 38
dicklyon@623 39 seglen = round(fs / 30); % Pick about 30 fps
dicklyon@623 40 frame_rate = fs / seglen;
ronw@634 41 n_segs = ceil(n_samp / seglen);
ronw@634 42
dicklyon@623 43
dicklyon@604 44 % Design the composite log-lag SAI using these parameters and defaults.
dicklyon@623 45 n_layers = 15
dicklyon@623 46 width_per_layer = 36;
dicklyon@623 47 [layer_array, total_width, lags] = ...
dicklyon@623 48 SAI_DesignLayers(n_layers, width_per_layer, seglen);
dicklyon@623 49
dicklyon@623 50 % Find where in the lag curve corresponds to the piano black keys:
dicklyon@623 51 pitches = fs ./ lags;
dicklyon@623 52 key_indices = [];
dicklyon@623 53 df = log(2)/width_per_layer;
dicklyon@623 54 for f = [BlackKeyFrequencies, 8, 4, 2, 1-df, 1, 1+df, 0.5, 0.25, 0.125, ...
dicklyon@623 55 -2000, -1000, -500, -250, -125]; % Augment with beat.
dicklyon@623 56 [dist, index] = min((f - pitches).^2);
dicklyon@623 57 key_indices = [key_indices, index];
dicklyon@623 58 end
dicklyon@623 59 piano = zeros(1, total_width);
dicklyon@623 60 piano(key_indices) = 1;
dicklyon@623 61 piano = [piano; piano; piano];
dicklyon@623 62
dicklyon@604 63
dicklyon@604 64 % Make the composite SAI image array.
dicklyon@604 65 composite_frame = zeros(n_ch, total_width);
dicklyon@604 66
dicklyon@604 67 % Make the history buffers in the layers_array:
dicklyon@604 68 for layer = 1:n_layers
dicklyon@604 69 layer_array(layer).nap_buffer = zeros(layer_array(layer).buffer_width, n_ch);
dicklyon@604 70 layer_array(layer).nap_fraction = 0; % leftover fraction to shift in.
dicklyon@608 71 % The SAI frame is transposed to be image-like.
dicklyon@608 72 layer_array(layer).frame = zeros(n_ch, layer_array(layer).frame_width);
dicklyon@604 73 end
dicklyon@604 74
dicklyon@623 75 n_marginal_rows = 100;
dicklyon@608 76 marginals = [];
dicklyon@623 77 average_composite = 0;
dicklyon@608 78
dicklyon@623 79 future_lags = layer_array(1).future_lags;
dicklyon@623 80 % marginals_frame = zeros(total_width - future_lags + 2*n_ch, total_width);
dicklyon@623 81 marginals_frame = zeros(n_ch, total_width);
dicklyon@623 82
dicklyon@604 83 for seg_num = 1:n_segs
ronw@634 84 % seg_range is the range of input sample indices for this segment
dicklyon@604 85 if seg_num == n_segs
dicklyon@604 86 % The last segment may be short of seglen, but do it anyway:
ronw@634 87 seg_range = (seglen*(seg_num - 1) + 1):n_samp;
dicklyon@604 88 else
ronw@634 89 seg_range = seglen*(seg_num - 1) + (1:seglen);
dicklyon@604 90 end
dicklyon@604 91 % Process a segment to get a slice of decim_naps, and plot AGC state:
ronw@634 92 [seg_naps, CF] = CARFAC_Run_Segment(CF, input_waves(seg_range, :));
dicklyon@604 93
dicklyon@604 94 seg_naps = max(0, seg_naps); % Rectify
dicklyon@604 95
dicklyon@604 96 if seg_num == n_segs % pad out the last result
dicklyon@604 97 seg_naps = [seg_naps; zeros(seglen - size(seg_naps,1), size(seg_naps, 2))];
dicklyon@604 98 end
dicklyon@604 99
dicklyon@604 100 % Shift new data into some or all of the layer buffers:
dicklyon@604 101 layer_array = SAI_UpdateBuffers(layer_array, seg_naps, seg_num);
dicklyon@604 102
dicklyon@623 103 for layer = n_layers:-1:1 % Stabilize and blend from coarse to fine
dicklyon@604 104 update_interval = layer_array(layer).update_interval;
dicklyon@604 105 if 0 == mod(seg_num, update_interval)
dicklyon@608 106 layer_array(layer) = SAI_StabilizeLayer(layer_array(layer));
dicklyon@608 107 composite_frame = SAI_BlendFrameIntoComposite( ...
dicklyon@604 108 layer_array(layer), composite_frame);
dicklyon@604 109 end
dicklyon@604 110 end
dicklyon@623 111
dicklyon@623 112 average_composite = average_composite + ...
dicklyon@623 113 0.01 * (composite_frame - average_composite);
dicklyon@608 114
dicklyon@608 115 if isempty(marginals)
dicklyon@623 116 marginals = zeros(n_marginal_rows, total_width);
dicklyon@608 117 end
dicklyon@608 118 for row = n_marginal_rows:-1:11
dicklyon@608 119 % smooth from row above (lower number)
dicklyon@608 120 marginals(row, :) = marginals(row, :) + ...
dicklyon@623 121 2^((10 - row)/8) * (1.01*marginals(row - 1, :) - marginals(row, :));
dicklyon@608 122 end
dicklyon@604 123 lag_marginal = mean(composite_frame, 1); % means max out near 1 or 2
dicklyon@623 124 lag_marginal = lag_marginal - 0.75*smooth1d(lag_marginal, 30)';
dicklyon@623 125
dicklyon@623 126 freq_marginal = mean(layer_array(1).nap_buffer);
dicklyon@623 127 % emphasize local peaks:
dicklyon@623 128 freq_marginal = freq_marginal - 0.5*smooth1d(freq_marginal, 5)';
dicklyon@623 129
dicklyon@623 130
dicklyon@623 131 % marginals_frame = [marginals_frame(:, 2:end), ...
dicklyon@623 132 % [lag_marginal(1:(end - future_lags)), freq_marginal(ceil((1:(2*end))/2))]'];
dicklyon@623 133 marginals_frame = [marginals_frame(:, 2:end), freq_marginal(1:end)'];
dicklyon@623 134
dicklyon@608 135 for row = 10:-1:1
dicklyon@623 136 marginals(row, :) = lag_marginal - (10 - row) / 40;
dicklyon@604 137 end
dicklyon@604 138
dicklyon@604 139 if 0 == mod(seg_num, update_interval) || seg_num == 1
dicklyon@604 140 coc_gram = layer_array(end).nap_buffer';
dicklyon@604 141 [n_ch, n_width] = size(composite_frame);
dicklyon@604 142 coc_gram = [coc_gram, zeros(n_ch, n_width - size(coc_gram, 2))];
dicklyon@623 143 coc_gram = coc_gram(:, (end-total_width+1):end);
dicklyon@604 144 end
dicklyon@604 145
dicklyon@623 146 display_frame = [ ... % coc_gram; ...
dicklyon@623 147 4 * marginals_frame; ...
dicklyon@623 148 composite_frame(ceil((1:(2*end))/2), :); ...
dicklyon@623 149 piano; ...
dicklyon@623 150 10*max(0,marginals)];
dicklyon@604 151
dicklyon@604 152 cmap = jet;
dicklyon@604 153 cmap = 1 - gray; % jet
dicklyon@604 154 figure(10)
dicklyon@604 155 image(32*display_frame);
dicklyon@604 156 colormap(cmap);
dicklyon@604 157
dicklyon@604 158 drawnow
dicklyon@604 159 imwrite(32*display_frame, cmap, sprintf('frames/frame%05d.png', seg_num));
dicklyon@604 160 end
dicklyon@604 161
dicklyon@604 162 num_frames = seg_num;
dicklyon@604 163
dicklyon@604 164 return
dicklyon@604 165
dicklyon@604 166
dicklyon@623 167 function frequencies = BlackKeyFrequencies
dicklyon@623 168 black_indices = [];
dicklyon@623 169 for index = 0:87
dicklyon@623 170 if any(mod(index, 12) == [1 4 6 9 11])
dicklyon@623 171 black_indices = [black_indices, index];
dicklyon@623 172 end
dicklyon@623 173 end
dicklyon@623 174 frequencies = 27.5 * 2.^(black_indices / 12);
dicklyon@604 175
dicklyon@604 176