Skip to content

Commit 2f67706

Browse files
authored
Fix crash when loading multichannel string streams (#164)
* Fix crash when loading multichannel string streams * Add changelog entry
1 parent 01425d6 commit 2f67706

5 files changed

Lines changed: 35 additions & 11 deletions

File tree

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## [UNRELEASED] · YYYY-MM-DD
2+
### 🔧 Fixed
3+
- Fix multi-channel string/marker stream parsing ([#164](https://github.com/cbrnr/sigviewer/pull/164) by [Clemens Brunner](https://github.com/cbrnr))
4+
- Fix crash when loading XDF files containing a stream with only one sample ([#164](https://github.com/cbrnr/sigviewer/pull/164) by [Clemens Brunner](https://github.com/cbrnr))
5+
16
## [0.7.1] · 2026-04-06
27
### ✨ Added
38
- Add DMG background and Applications shortcut for macOS installer

CMakeLists.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
cmake_minimum_required(VERSION 3.21)
22

33
project(sigviewer
4-
VERSION 0.7.1
4+
VERSION 0.7.2
55
LANGUAGES CXX C
66
)
77

88
# -- Pinned versions of external dependencies --------------------------------
99
# These are the ONLY accepted versions. Change them here (and rebuild the
1010
# pre-built artifacts) when upgrading a dependency.
11-
set(LIBXDF_VERSION "0.99.10")
12-
set(LIBBIOSIG_VERSION "3.9.4")
11+
set(LIBXDF_VERSION "1.0.0")
12+
set(LIBBIOSIG_VERSION "3.9.5")
1313

1414
# -- Language standards ------------------------------------------------------
1515
set(CMAKE_CXX_STANDARD 17)

external/build_deps.cmake

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@
3939
cmake_minimum_required(VERSION 3.21)
4040

4141
# -- Pinned versions (must match CMakeLists.txt) -----------------------------
42-
set(LIBXDF_VERSION "0.99.10")
43-
set(LIBBIOSIG_VERSION "3.9.4")
42+
set(LIBXDF_VERSION "1.0.0")
43+
set(LIBBIOSIG_VERSION "3.9.5")
4444

4545
# -- Resolve the destination directory ---------------------------------------
4646
if(NOT DEFINED DEPS_DIR)

src/file_handling/xdf_reader.cpp

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -155,13 +155,24 @@ QString XDFReader::loadFixedHeader(const QString& file_path)
155155
{
156156
/* If and only if the file contains only one sample rate, we use effective
157157
sample rate to more accurately display events. Effective sample rates
158-
can be slightly different across streams, so we calculate the mean here */
158+
can be slightly different across streams, so we calculate the mean here.
159+
Streams with only one sample have a zero-length time span, which makes
160+
their effective sample rate infinite; such values must be excluded or
161+
they poison the mean (and the event positions computed from it). */
162+
163+
double sum = 0.0;
164+
int validCount = 0;
165+
for (double rate : XDFdata->effectiveSampleRateVector)
166+
{
167+
if (std::isfinite(rate))
168+
{
169+
sum += rate;
170+
validCount++;
171+
}
172+
}
159173

160-
double init = 0.0;
161-
XDFdata->fileEffectiveSampleRate =
162-
std::accumulate(XDFdata->effectiveSampleRateVector.begin(),
163-
XDFdata->effectiveSampleRateVector.end(), init)
164-
/ XDFdata->effectiveSampleRateVector.size();
174+
if (validCount)
175+
XDFdata->fileEffectiveSampleRate = sum / validCount;
165176
}
166177
}
167178
break;

src/gui/signal_browser/adapt_browser_view_widget.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,16 @@ AdaptBrowserViewWidget::AdaptBrowserViewWidget (SignalVisualisationView const* s
4040
throw (Exception (tr("connect failed: y_axis_checkbox_").toStdString()));
4141
if (!connect (ui_.labels_checkbox_, SIGNAL(toggled(bool)), SIGNAL(labelsVisibilityChanged(bool))))
4242
throw (Exception (tr("connect failed: labels_checkbox_").toStdString()));
43+
// Qt's setMaximum() clamps and re-emits valueChanged() when the spinbox's
44+
// current value exceeds the new maximum (e.g. for a very short recording).
45+
// At this point in construction, the containing SignalBrowserView hasn't
46+
// registered itself with its SignalBrowserModel yet, so a resulting
47+
// on_..._valueChanged -> SignalBrowserModel::update() call would crash on
48+
// a null view pointer. Suppress it with the same guard updateValues() uses.
49+
updating_values_ = true;
4350
ui_.channelsPerPageSpinbox->setMaximum (setting->getChannelManager().getNumberChannels());
4451
ui_.secsPerPageSpinbox->setMaximum (settings_->getChannelManager().getDurationInSec());
52+
updating_values_ = false;
4553
connect (settings_.data(), SIGNAL(channelHeightChanged()), SLOT(updateValues()));
4654
connect (settings_.data(), SIGNAL(gridFragmentationChanged()), SLOT(updateValues()));
4755
connect (settings_.data(), SIGNAL(pixelsPerSampleChanged()), SLOT(updateValues()));

0 commit comments

Comments
 (0)