changeset 166:1495bdfa13e9 danieleb

Updated grassmanian function (restored old computation of the dictionary) and added functions to the audio class
author Daniele Barchiesi <daniele.barchiesi@eecs.qmul.ac.uk>
date Mon, 19 Sep 2011 14:53:23 +0100
parents 88578ec2f94a
children 8324c7ea6602
files util/classes/@audio/audio.m util/classes/@audio/buffer.m util/classes/@audio/plot.m util/classes/@audio/unbuffer.m util/classes/dictionaryMatrices/grassmannian.m
diffstat 5 files changed, 197 insertions(+), 94 deletions(-) [+]
line wrap: on
line diff
--- a/util/classes/@audio/audio.m	Wed Aug 31 13:52:23 2011 +0100
+++ b/util/classes/@audio/audio.m	Mon Sep 19 14:53:23 2011 +0100
@@ -1,54 +1,63 @@
 classdef audio
-    %% Audio object
-    properties
-        s  %vector containing the audio signal
-        fs %sampling frequency 
-        nBits % number of bits per sample
-        name % string containing the name of the audio file
-        format % string containing the format of the audio file
-    end
-    
-    methods
-        %% Constructor
-        function obj = audio(varargin)
-            error(nargchk(1,5,nargin));
-            if ischar(varargin{1})
-                [~, obj.name obj.format] = fileparts(varargin{1});
-                switch obj.format
-                    case '.wav'
-                        [obj.s obj.fs obj.nBits] = wavread(varargin{1});
-                    otherwise
-                        error('Unsupported audio format')
-                end
-            else
-                obj.s = varargin{1};
-                if nargin>1, obj.fs = varargin{2}; else obj.fs = []; end
-                if nargin>2, obj.nBits = varargin{3}; else obj.nBits = []; end
-                if nargin>3, obj.name = varargin{4}; else obj.name = []; end
-                if nargin>4, obj.format = varargin{5}; else obj.format = []; end
-            end
-        end
-        
-        %% Playback functions
-        function player = play(obj, player)
-            if ~exist('player','var') || isempty(player)
-                player = audioplayer(obj.s,obj.fs);
-            end
-            play(player);
-        end
-        
-        function player = stop(obj, player)
-            if ~exist('player','var') || isempty(player)
-                player = audioplayer(obj.s,obj.fs);
-            end
-            stop(player)
-        end
-        
-        function player = pause(obj, player)
-            if ~exist('player','var') || isempty(player)
-                player = audioplayer(obj.s,obj.fs);
-            end
-            pause(player)
-        end
-    end
+	%% Audio object
+	properties
+		s  %vector containing the audio signal
+		S  %matrix containing frames of audio for subsequent processing
+		fs %sampling frequency
+		nBits %number of bits per sample
+		name %string containing the name of the audio file
+		format %string containing the format of the audio file
+		bufferOperator %struct containing the parameters of the buffer operator (used by unbuffer to invert it)
+	end
+	
+	methods
+		%% Constructor
+		function obj = audio(varargin)
+			% if no arguments are specified, prompt for the choice of an
+			% audio file
+			if ~nargin
+				[fileName,pathname] = uigetfile({'*.wav; *.aiff;'},'Select an audio file');
+				varargin{1} = strcat(pathname,filesep,fileName);
+			end
+			if ischar(varargin{1})
+				[~, obj.name obj.format] = fileparts(varargin{1});
+				switch obj.format
+					case '.wav'
+						[obj.s obj.fs obj.nBits] = wavread(varargin{1});
+					otherwise
+						error('Unsupported audio format')
+				end
+			else
+				obj.s = varargin{1};
+				if nargin>1, obj.fs = varargin{2}; else obj.fs = []; end
+				if nargin>2, obj.nBits = varargin{3}; else obj.nBits = []; end
+				if nargin>3, obj.name = varargin{4}; else obj.name = []; end
+				if nargin>4, obj.format = varargin{5}; else obj.format = []; end
+			end
+			obj.S = [];
+			obj.bufferOperator = [];
+		end
+		
+		%% Playback functions
+		function player = play(obj, player)
+			if ~exist('player','var') || isempty(player)
+				player = audioplayer(obj.s,obj.fs);
+			end
+			play(player);
+		end
+		
+		function player = stop(obj, player)
+			if ~exist('player','var') || isempty(player)
+				player = audioplayer(obj.s,obj.fs);
+			end
+			stop(player)
+		end
+		
+		function player = pause(obj, player)
+			if ~exist('player','var') || isempty(player)
+				player = audioplayer(obj.s,obj.fs);
+			end
+			pause(player)
+		end
+	end
 end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util/classes/@audio/buffer.m	Mon Sep 19 14:53:23 2011 +0100
@@ -0,0 +1,27 @@
+function obj = buffer(obj,wLength,overlap,window,method)
+
+%% Check inputs & Defaults
+error(nargchk(2, 5, nargin, 'struct'));
+
+if ~exist('overlap','var') || isempty(overlap), overlap = 0; end
+if ~exist('method','var') || isempty(method), method = 'standard'; end
+
+%% Buffer audio
+switch lower(method)
+	case 'standard'
+		if ~exist('window','var') || isempty(window), window = @rectwin; end
+		validWindows = {'hanning','hamming','triang','rectwin'};
+		if ~sum(strcmpi(validWindows,func2str(window)));
+			error('The window chosen is not valid because it cannot be inverted!');
+		end
+		obj.S = diag(window(wLength))*buffer(obj.s,wLength,overlap,'nodelay');
+	case 'lot'
+		if ~exist('window','var') || isempty(window), window = 'sin2'; end
+		s_lot = lot(obj.s,wLength,'id',overlap,window);
+		obj.S = buffer(s_lot,wLength);
+	otherwise
+		error('Please specify a valid buffer method');
+end
+
+obj.bufferOperator = struct('wLength',wLength,'overlap',...
+	overlap,'window',window,'method',method);
--- a/util/classes/@audio/plot.m	Wed Aug 31 13:52:23 2011 +0100
+++ b/util/classes/@audio/plot.m	Mon Sep 19 14:53:23 2011 +0100
@@ -1,58 +1,95 @@
 function plot(obj)
 
+figure,
+playbackPanelH = uipanel(gcf,'Units','Normalized','Position',[.3 0 .4 .1]);
+
+buttWidth = 1/6;
+centers = linspace(0,1,7)-buttWidth/2;
+rewButtonH = uicontrol(playbackPanelH,'Style','pushbutton','String','<<','Units',...
+	'Normalized','Position',[centers(2) 0.2 buttWidth 0.6]);
+ffButtonH = uicontrol(playbackPanelH,'Style','togglebutton','String','>>','Units',...
+	'Normalized','Position',[centers(3) 0.2 buttWidth 0.6]);
+stopButtonH = uicontrol(playbackPanelH,'Style','pushbutton','String','stop','Units',...
+	'Normalized','Position',[centers(4) 0.2 buttWidth 0.6]);
+playButtonH = uicontrol(playbackPanelH,'Style','togglebutton','String','play','Units',...
+	'Normalized','Position',[centers(5) 0.2 buttWidth 0.6]);
+pauseButtonH = uicontrol(playbackPanelH,'Style','togglebutton','String','||','Units',...
+	'Normalized','Position',[centers(6) 0.2 buttWidth 0.6]);
+
+waveformPanelH = uipanel(gcf,'Units','Normalized','Position',[.02 .12 .96 .86]);
+waveformAxesH = axes('Parent',waveformPanelH);
+
 %% Plot the time domain signal
 s = obj.s;
 fs = obj.fs;
-figure, plot((1:length(s))/fs,s);
+plot((1:length(s))/fs,s);
 title('Audio signal')
 xlabel('time (s)');
 axis tight
 
 player = audioplayer(s,fs);
+set(player,'TimerPeriod',0.1);
 set(player,'StartFcn',@plotTransportBar);
 set(player,'TimerFcn',@updateTransportBar);
 set(player,'StopFcn',@deleteTransportBar);
 
-%% Add playbaack controls
-playButtonH = uicontrol(gcf,'Style','pushbutton','String','play','Units',...
-    'Normalized','Position',[0.02 + 0.39 0 0.1 0.05]);
-stopButtonH = uicontrol(gcf,'Style','pushbutton','String','stop','Units',...
-    'Normalized','Position',[0.12 + 0.39 0 0.1 0.05]);
-
+%% Add playback controls
 set(playButtonH,'Callback',@play_callback);
 set(stopButtonH,'Callback',@stop_callback);
+set(pauseButtonH,'Callback',@pause_callback);
+set(rewButtonH,'Callback',@rew_callback);
+set(ffButtonH,'Callback',@ff_callback);
 
-    function play_callback(~,~)
-        if strcmpi(get(playButtonH,'String'),'play')
-            play(player,player.CurrentSample);
-            set(playButtonH,'String','pause');
-        else
-            pause(player)
-            set(playButtonH,'String','play');
-        end
-    end
+	function play_callback(~,~)
+		set(player,'SampleRate',fs);
+		play(player,player.CurrentSample);
+		set(pauseButtonH,'Value',0);
+		set(ffButtonH,'Value',0);
+	end
 
-    function stop_callback(~,~)
-        stop(player);
-    end
+	function pause_callback(~,~)
+		pause(player);
+		set(playButtonH,'Value',0);
+		set(ffButtonH,'Value',0);
+	end
+
+	function stop_callback(~,~)
+		stop(player);
+		set(playButtonH,'Value',0);
+		set(pauseButtonH,'Value',0);
+		set(ffButtonH,'Value',0);
+	end
+
+	function ff_callback(~,~)
+		set(player,'SampleRate',1.5*fs);
+		set(pauseButtonH,'Value',0);
+		set(playButtonH,'Value',0);
+	end
+
+	function rew_callback(~,~)
+		stop(player);
+		play(player);
+		set(pauseButtonH,'Value',0);
+		set(playButtonH,'Value',1);
+	end
 
 %% Transport Bar functions
-    function plotTransportBar(~,~)
-        global tbH
-        xLim = get(gca,'Xlim');
-        yLim = get(gca,'YLim');
-        tbH = line([xLim(1) xLim(1)],yLim,'Color','k');
-    end
-        
-    function updateTransportBar(hObject,~)
-        global tbH
-        currentSample = hObject.CurrentSample;
-        pos = currentSample/fs;
-        set(tbH,'XData',[pos pos]);
-    end
+	function plotTransportBar(~,~)
+		global tbH
+		xLim = get(gca,'Xlim');
+		yLim = get(gca,'YLim');
+		tbH = line([xLim(1) xLim(1)],yLim,'Color','k');
+	end
 
-    function deleteTransportBar(~,~)
-        global tbH
-        delete(tbH);
-    end
+	function updateTransportBar(hObject,~)
+		global tbH
+		currentSample = hObject.CurrentSample;
+		pos = currentSample/fs;
+		set(tbH,'XData',[pos pos]);
+	end
+
+	function deleteTransportBar(~,~)
+		global tbH
+		delete(tbH);
+	end
 end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util/classes/@audio/unbuffer.m	Mon Sep 19 14:53:23 2011 +0100
@@ -0,0 +1,27 @@
+function s = unbuffer(obj)
+
+%% Check inputs and Defaults
+if ~isprop(obj,'bufferOperator') || isempty(obj.bufferOperator)
+	error('You must buffer a signal before unbuffer it, come on!');
+end
+
+switch lower(obj.bufferOperator.method)
+	%Unbuffer using overlap-add method
+	case 'standard'
+		w = obj.bufferOperator.window(obj.bufferOperator.wLength);
+		S = diag(1./w)*obj.S;
+		%Non overlapping case
+		if obj.bufferOperator.overlap == 0
+			s = S(:);
+		%Overlapping case
+		else
+			Stemp = S(1:obj.bufferOperator.wLength-obj.bufferOperator.overlap,1:end);
+			s = [Stemp(:); S(obj.bufferOperator.wLength-obj.bufferOperator.overlap+1:end,end)];
+		end
+	%Unbuffer using inverse lot with identity local transform
+	case 'lot'
+		s = ilot(obj.S(:),obj.bufferOperator.wLength,'id',...
+			obj.bufferOperator.overlap,obj.bufferOperator.window);
+	otherwise
+		error('Please specify a valid buffer method');
+end
--- a/util/classes/dictionaryMatrices/grassmannian.m	Wed Aug 31 13:52:23 2011 +0100
+++ b/util/classes/dictionaryMatrices/grassmannian.m	Mon Sep 19 14:53:23 2011 +0100
@@ -4,18 +4,21 @@
 %
 % [A G res] = grassmanian(n,m,nIter,dd1,dd2,initA)
 %
-%
+% REFERENCE
+% M. Elad, Sparse and Redundant Representations, Springer 2010.
+
 %% Parameters and Defaults
 error(nargchk(2,7,nargin));
 
 if ~exist('verb','var')  || isempty(verb),  verb = false; end %verbose output
 if ~exist('initA','var') || isempty(initA), initA = randn(n,m); end %initial matrix
-if ~exist('dd2','var')   || isempty(dd2),   dd2 = 0.95; end %shrinking factor
+if ~exist('dd2','var')   || isempty(dd2),   dd2 = 0.99; end %shrinking factor
 if ~exist('dd1','var')   || isempty(dd1),   dd1 = 0.9; end %percentage of coherences to be shrinked
 if ~exist('nIter','var') || isempty(nIter), nIter = 10; end %number of iterations
 
 %% Main algo
 A = normc(initA); %normalise columns
+[Uinit Sigma] = svd(A);
 G = A'*A; %gram matrix
 
 muMin = sqrt((m-n)/(n*(m-1)));              %Lower bound on mutual coherence (equiangular tight frame)
@@ -40,12 +43,12 @@
 end
 
 % [~, Sigma_gram V_gram] = svd(G); %calculate svd decomposition of gramian
-% Sigma_new = sqrt(Sigma_gram(1:n,:)).*sign(Sigma); %calculate singular values of dictionary
-% A = Uinit*Sigma_new*V_gram';	%update dictionary
+
 % A = normc(A);					%normalise dictionary
 
-[U S] = svd(G);				%calculate svd decomposition of gramian
-A = sqrt(S(1:n,1:n))*U(:,1:n)';		%calculate valid frame, s.t. A'*A=G
+[V_gram Sigma_gram] = svd(G);				%calculate svd decomposition of gramian
+Sigma_new = sqrt(Sigma_gram(1:n,:)).*sign(Sigma); %calculate singular values of dictionary
+A = Uinit*Sigma_new*V_gram';	%update dictionary
 
 % %% Debug visualization function
 % function plotcart2d(A)