Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 12 additions & 9 deletions docs/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,20 +69,23 @@ Returns:

---

## Matlab API (`src/matlab/pyraview_mex.c`)
## Matlab API (`src/matlab/+pyraview/`)

### `status = pyraview_mex(data, prefix, steps, nativeRate, [append], [numThreads])`
### `status = pyraview.pyraview(data, prefix, steps, nativeRate, [append], [numThreads])`
Processes raw data into multi-resolution pyramid files.

Arguments:
- `data`: Numeric matrix. Supports: `int8`, `uint8`, `int16`, `uint16`, `int32`, `uint32`, `int64`, `uint64`, `single`, `double`.
- `prefix`: String.
- `steps`: Vector of integers.
- `nativeRate`: Scalar double.
- `append`: Logical/Scalar (optional).
- `numThreads`: Scalar (optional).
- `data`: (Samples x Channels) matrix.
- Supported types: `int8`, `uint8`, `int16`, `uint16`, `int32`, `uint32`, `int64`, `uint64`, `single`, `double`.
- `prefix`: String specifying the base path and name for the output files.
- Generates files named `<prefix>_L1.bin`, `<prefix>_L2.bin`, etc.
- `steps`: Vector of integers specifying decimation factors for each level (relative to previous level).
- `nativeRate`: Scalar double (Hz). Original sampling rate of the raw data.
- `append`: (Optional) Logical/Scalar. Default `false`. If true, appends to existing files.
- `numThreads`: (Optional) Scalar integer. Default `0` (Auto). Number of worker threads.

Returns:
- `status`: 0 on success. Throws error on failure.
- `status`: 0 on success. Negative values indicate errors.

### `D = pyraview.readFile(filename, s0, s1)`
Reads a specific range of samples from a level file.
Expand Down
71 changes: 71 additions & 0 deletions src/matlab/+pyraview/pyraview.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
%PYRAVIEW Process raw data into multi-resolution pyramid files.
%
% STATUS = pyraview.pyraview(DATA, PREFIX, STEPS, NATIVERATE, STARTTIME)
% STATUS = pyraview.pyraview(DATA, PREFIX, STEPS, NATIVERATE, STARTTIME, APPEND)
% STATUS = pyraview.pyraview(DATA, PREFIX, STEPS, NATIVERATE, STARTTIME, APPEND, NUMTHREADS)
%
% This function processes a chunk of raw data (DATA) and writes it into
% a set of decimated binary files (Level Files) suitable for efficient
% multi-scale visualization.
%
% Inputs:
% DATA - Numeric matrix of size (Samples x Channels).
% Supported types: int8, uint8, int16, uint16, int32, uint32,
% int64, uint64, single, double.
% Data is assumed to be interleaved by sample if provided
% as Samples x Channels (standard MATLAB convention).
%
% PREFIX - String or character vector specifying the base path and
% name for the output files. The function will generate
% files named:
% <PREFIX>_L1.bin
% <PREFIX>_L2.bin
% ...
% <PREFIX>_LN.bin
%
% STEPS - Vector of integers specifying the decimation factor for
% each level relative to the previous level.
% Example: [100, 10, 10] means:
% Level 1: Decimated by 100 relative to Raw.
% Level 2: Decimated by 10 relative to Level 1 (1000 total).
% Level 3: Decimated by 10 relative to Level 2 (10000 total).
%
% NATIVERATE - Scalar double. The sampling rate of the original raw data
% in Hz. This is stored in the file header.
%
% STARTTIME - Scalar double. The start time of the recording in seconds.
% This is stored in the file header.
%
% APPEND - (Optional) Logical/Scalar. Default is false (0).
% If true (1), the function appends the processed data to
% existing level files.
% If false (0), existing files are overwritten.
%
% NUMTHREADS - (Optional) Scalar integer. Default is 0 (Auto).
% Specifies the number of worker threads to use for parallel
% processing. If 0, the function automatically detects the
% number of available hardware concurrency.
%
% Outputs:
% STATUS - Scalar double.
% 0 on success.
% Negative values indicate errors (e.g., I/O error, type mismatch).
% If the function fails, it may also throw a MATLAB error.
%
% File Format:
% The generated files are binary files with a 1024-byte header followed
% by the data. The data is stored in a planar layout (all samples for
% Channel 1, then Channel 2, etc.). Each "sample" in the level file
% consists of a Minimum and Maximum value pair to preserve signal
% envelope information during decimation.
%
% Example:
% % Process 10 seconds of 1kHz data into 3 levels
% fs = 1000;
% data = randn(10000, 2); % 10s, 2 channels
% steps = [10, 10]; % L1=10x, L2=100x
%
% % Generates 'mydata_L1.bin' and 'mydata_L2.bin'
% status = pyraview.pyraview(data, 'mydata', steps, fs, 0);
%
% See also PYRAVIEW.READFILE, PYRAVIEW.DATASET
6 changes: 3 additions & 3 deletions src/matlab/build_pyraview.m
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@
% Note: mex will compile .cpp file as C++.
% It will link with .c file (compiled as C).
% No OpenMP flags needed as we use C++11 std::thread
fprintf('Building pyraview_mex...\n');
mex('-v', '-outdir', out_dir, '-output', 'pyraview_mex', include_path, src_path, mex_src);
fprintf('Build pyraview_mex successful.\n');
fprintf('Building pyraview...\n');
mex('-v', '-outdir', out_dir, '-output', 'pyraview', include_path, src_path, mex_src);
fprintf('Build pyraview successful.\n');

fprintf('Building pyraview_get_header_mex...\n');
mex('-v', '-outdir', out_dir, '-output', 'pyraview_get_header_mex', include_path, src_path, header_src);
Expand Down
16 changes: 10 additions & 6 deletions src/matlab/test_pyraview.m
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,25 @@
end

function setupOnce(testCase)
% Verify MEX file exists
% Verify MEX file exists in +pyraview
[~, mexName] = fileparts('pyraview');
mexExt = mexext;
fullMexPath = fullfile(pwd, 'src', 'matlab', ['pyraview.' mexExt]);
% Expected path: src/matlab/+pyraview/pyraview.mex*
fullMexPath = fullfile(pwd, 'src', 'matlab', '+pyraview', ['pyraview.' mexExt]);

% If run via run-tests action, current folder might be repo root.
if ~exist(fullMexPath, 'file')
% Try relative to where this file is?
currentFileDir = fileparts(mfilename('fullpath'));
fullMexPath = fullfile(currentFileDir, ['pyraview.' mexExt]);
% Assuming this test is in src/matlab, the mex is in +pyraview/
fullMexPath = fullfile(currentFileDir, '+pyraview', ['pyraview.' mexExt]);
if ~exist(fullMexPath, 'file')
% Fallback for direct path?
error('MEX file not found: %s', fullMexPath);
end
addpath(currentFileDir);
addpath(currentFileDir); % Add src/matlab to path
else
addpath(fileparts(fullMexPath));
addpath(fileparts(fileparts(fullMexPath))); % Add src/matlab to path
end

fprintf('Using MEX: %s\n', fullMexPath);
Expand All @@ -45,7 +48,8 @@ function test_comprehensive(testCase)
c = onCleanup(@() cleanupFile(outfile));

try
status = pyraview(data, prefix, [10], 1000.0);
% Call pyraview.pyraview
status = pyraview.pyraview(data, prefix, [10], 1000.0, 0);
testCase.verifyEqual(status, 0, 'Status should be 0');

testCase.verifyTrue(exist(outfile, 'file') == 2, 'Output file should exist');
Expand Down
4 changes: 2 additions & 2 deletions src/matlab/tests/+pyraview/+unittest/TestDataset.m
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ function createData(testCase)
steps = [10, 10];
start_time = 100.0;

% Call MEX
pyraview.pyraview_mex(data, prefix, steps, Fs, start_time);
% Call pyraview.pyraview
pyraview.pyraview(data, prefix, steps, Fs, start_time);
end
end

Expand Down