diff --git a/matlab/+sonpipe/channelinfo.m b/matlab/+sonpipe/channelinfo.m index c59fddb..44a07d7 100644 --- a/matlab/+sonpipe/channelinfo.m +++ b/matlab/+sonpipe/channelinfo.m @@ -9,6 +9,11 @@ % % See also sonpipe.read_SOMSMR_header + arguments + header + channel_number {mustBeNumeric} + end + if isempty(header) || ~isfield(header, 'channelinfo') || isempty(header.channelinfo) error('sonpipe:noChannels', 'The header contains no channels.'); end diff --git a/matlab/+sonpipe/channels.m b/matlab/+sonpipe/channels.m index f519e29..7fcf3dd 100644 --- a/matlab/+sonpipe/channels.m +++ b/matlab/+sonpipe/channels.m @@ -17,7 +17,12 @@ % % See also sonpipe.read_SOMSMR_header - if nargin < 2 || isempty(header) + arguments + filename {mustBeTextScalar} + header = [] % [] or a header struct; read from FILENAME if omitted + end + + if isempty(header) header = sonpipe.read_SOMSMR_header(filename); end diff --git a/matlab/+sonpipe/executable.m b/matlab/+sonpipe/executable.m index 649e798..27b37d3 100644 --- a/matlab/+sonpipe/executable.m +++ b/matlab/+sonpipe/executable.m @@ -17,13 +17,22 @@ % Lookup order when no value is cached: % 1. the SONPIPE environment variable, if set % 2. 'sonpipe' on the system PATH -% 3. 'python3 -m sonpipe' -% 4. 'python -m sonpipe' +% 3. sonpipe at the default install locations (~/.local/bin/sonpipe, the +% install.sh venv, and the Windows %LOCALAPPDATA% venv). These are +% probed by absolute path because a MATLAB GUI on macOS/Windows does not +% inherit the interactive shell PATH, so a working ~/.local/bin install +% is otherwise invisible to step 2. +% 4. 'python3 -m sonpipe' +% 5. 'python -m sonpipe' % % Each candidate is verified by running " --version". % % See also sonpipe.read_SOMSMR_header + arguments + newvalue = '' % command string; nargin distinguishes query() from set('') + end + persistent CACHED if nargin >= 1 @@ -43,6 +52,7 @@ candidates{end+1} = envval; end candidates{end+1} = 'sonpipe'; + candidates = [candidates, defaultInstallCandidates()]; candidates{end+1} = 'python3 -m sonpipe'; candidates{end+1} = 'python -m sonpipe'; @@ -60,3 +70,25 @@ '''pip install sonpipe'', or point MATLAB at it with ' ... 'sonpipe.executable(PATH) or the SONPIPE environment variable.']); end + +function c = defaultInstallCandidates() +% Absolute paths where install.sh / install.ps1 place sonpipe. Only paths that +% exist on disk are returned (each is quoted so spaces in the path are safe). + c = {}; + paths = {}; + home = getenv('HOME'); + if isempty(home), home = getenv('USERPROFILE'); end + if ~isempty(home) + paths{end+1} = fullfile(home, '.local', 'bin', 'sonpipe'); + paths{end+1} = fullfile(home, '.local', 'share', 'sonpipe', 'venv', 'bin', 'sonpipe'); + end + lad = getenv('LOCALAPPDATA'); + if ~isempty(lad) + paths{end+1} = fullfile(lad, 'sonpipe', 'venv', 'Scripts', 'sonpipe.exe'); + end + for i = 1:numel(paths) + if isfile(paths{i}) + c{end+1} = ['"' paths{i} '"']; %#ok + end + end +end diff --git a/matlab/+sonpipe/private/invoke_binary.m b/matlab/+sonpipe/private/invoke_binary.m index 39d40c5..b30901d 100644 --- a/matlab/+sonpipe/private/invoke_binary.m +++ b/matlab/+sonpipe/private/invoke_binary.m @@ -15,6 +15,11 @@ % % This is a private helper for the +sonpipe package. + arguments + args {mustBeTextScalar} + precision {mustBeTextScalar} + end + exe = sonpipe.executable(); tmp = [tempname() '.bin']; cleaner = onCleanup(@() deletefile(tmp)); diff --git a/matlab/+sonpipe/private/invoke_text.m b/matlab/+sonpipe/private/invoke_text.m index 47238ce..1950c44 100644 --- a/matlab/+sonpipe/private/invoke_text.m +++ b/matlab/+sonpipe/private/invoke_text.m @@ -9,6 +9,10 @@ % % This is a private helper for the +sonpipe package. + arguments + args {mustBeTextScalar} + end + exe = sonpipe.executable(); cmd = [exe ' ' args]; [status, txt] = sonpipe.runcmd(cmd); diff --git a/matlab/+sonpipe/read_SOMSMR_datafile.m b/matlab/+sonpipe/read_SOMSMR_datafile.m index 134f77a..d6f0851 100644 --- a/matlab/+sonpipe/read_SOMSMR_datafile.m +++ b/matlab/+sonpipe/read_SOMSMR_datafile.m @@ -32,6 +32,14 @@ % % See also sonpipe.read_SOMSMR_header, sonpipe.read_SOMSMR_sampleinterval + arguments + filename {mustBeTextScalar} + header % [] or a header struct + channel_number {mustBeNumeric} + t0 (1,1) {mustBeNumeric} + t1 (1,1) {mustBeNumeric} + end + data = []; total_samples = []; total_time = []; diff --git a/matlab/+sonpipe/read_SOMSMR_header.m b/matlab/+sonpipe/read_SOMSMR_header.m index d11f217..f835a71 100644 --- a/matlab/+sonpipe/read_SOMSMR_header.m +++ b/matlab/+sonpipe/read_SOMSMR_header.m @@ -37,6 +37,10 @@ % % See also sonpipe.read_SOMSMR_datafile, sonpipe.read_SOMSMR_sampleinterval + arguments + filename {mustBeTextScalar} + end + txt = invoke_text(sprintf('header "%s"', filename)); raw = jsondecode(txt); diff --git a/matlab/+sonpipe/read_SOMSMR_sampleinterval.m b/matlab/+sonpipe/read_SOMSMR_sampleinterval.m index 9f999ce..e5ebfb4 100644 --- a/matlab/+sonpipe/read_SOMSMR_sampleinterval.m +++ b/matlab/+sonpipe/read_SOMSMR_sampleinterval.m @@ -18,6 +18,12 @@ % % See also sonpipe.read_SOMSMR_header, sonpipe.read_SOMSMR_datafile + arguments + filename {mustBeTextScalar} + header % [] or a header struct (unused) + channel_number {mustBeNumeric} + end + txt = invoke_text(sprintf('sampleinterval "%s" -c %d', filename, channel_number)); r = jsondecode(txt); diff --git a/matlab/+sonpipe/runcmd.m b/matlab/+sonpipe/runcmd.m index ce55a3d..88ff67f 100644 --- a/matlab/+sonpipe/runcmd.m +++ b/matlab/+sonpipe/runcmd.m @@ -14,6 +14,10 @@ % % See also sonpipe.executable + arguments + cmd {mustBeTextScalar} + end + if ispc [status, out] = system(cmd); return;