2626#include " ../../Settings/DataStream.h"
2727#include " ../../Settings/InfoObject.h"
2828
29+ #include " ../../../CoreServices.h"
2930#include " ../../Events/Spike.h"
3031
3132#define TIC std::chrono::high_resolution_clock::now ()
@@ -95,7 +96,7 @@ void BinaryRecording::openFiles (File rootFolder, int experimentNumber, int reco
9596 if (streamId != lastStreamId)
9697 {
9798 wroteFirstSampleNumber[streamId] = false ;
98-
99+
99100 firstChannels.add (channelInfo);
100101 streamIndex++;
101102
@@ -120,7 +121,7 @@ void BinaryRecording::openFiles (File rootFolder, int experimentNumber, int reco
120121 singleChannelJSON->setProperty (" history" , channelInfo->getHistoryString ());
121122 singleChannelJSON->setProperty (" bit_volts" , channelInfo->getBitVolts ());
122123 singleChannelJSON->setProperty (" units" , channelInfo->getUnits ());
123- singleChannelJSON->setProperty (" type" , static_cast <int >(channelInfo->getChannelType ()));
124+ singleChannelJSON->setProperty (" type" , static_cast <int > (channelInfo->getChannelType ()));
124125 createChannelMetadata (channelInfo, singleChannelJSON);
125126
126127 singleStreamJSON.add (var (singleChannelJSON));
@@ -140,11 +141,14 @@ void BinaryRecording::openFiles (File rootFolder, int experimentNumber, int reco
140141 String datPath = getProcessorString (ch);
141142 String filename = contPath + datPath + " continuous.dat" ;
142143
143- LOGD (" Creating file: " , contPath, datPath, " sample_numbers.npy" );
144- ScopedPointer<NpyFile> tFile = new NpyFile (contPath + datPath + " sample_numbers.npy" , NpyType (BaseType::INT64, 1 ));
144+ String samplesPath = contPath + datPath + " sample_numbers.npy" ;
145+ LOGD (" Creating file: " , samplesPath);
146+ ScopedPointer<NpyFile> tFile = new NpyFile (samplesPath, NpyType (BaseType::INT64, 1 ));
145147 m_dataTimestampFiles.add (tFile.release ());
146148
147- ScopedPointer<NpyFile> syncTimestampFile = new NpyFile (contPath + datPath + " timestamps.npy" , NpyType (BaseType::DOUBLE, 1 ));
149+ String syncTimestampPath = contPath + datPath + " timestamps.npy" ;
150+ LOGD (" Creating file: " , syncTimestampPath);
151+ ScopedPointer<NpyFile> syncTimestampFile = new NpyFile (syncTimestampPath, NpyType (BaseType::DOUBLE, 1 ));
148152 m_dataSyncTimestampFiles.add (syncTimestampFile.release ());
149153
150154 DynamicObject::Ptr fileJSON = new DynamicObject ();
@@ -332,7 +336,113 @@ void BinaryRecording::openFiles (File rootFolder, int experimentNumber, int reco
332336
333337 settingsJSON->writeAsJSON (settingsFileStream, JSON::FormatOptions {}.withIndentLevel (2 ).withSpacing (JSON::Spacing::multiLine).withMaxDecimalPlaces (10 ));
334338
335-
339+ // Validate that all files were opened successfully
340+ if (! validateOpenFiles ())
341+ {
342+ String errorMsg = " Recording stopped! Failed to open one or more recording files. Please check disk space and write permissions." ;
343+
344+ LOGE (" BinaryRecording::openFiles: " , errorMsg);
345+
346+ // Stop recording and show error message on the message thread
347+ CoreServices::setRecordingStatus (false );
348+ MessageManager::callAsync ([]
349+ { CoreServices::sendStatusMessage (" Unable to start recording. Please check the console for errors." ); });
350+ }
351+ }
352+
353+ bool BinaryRecording::validateOpenFiles () const
354+ {
355+ bool allFilesValid = true ;
356+
357+ // Check continuous data files (SequentialBlockFile)
358+ for (int i = 0 ; i < m_continuousFiles.size (); i++)
359+ {
360+ if (m_continuousFiles[i] == nullptr )
361+ {
362+ allFilesValid = false ;
363+ }
364+ }
365+
366+ // Check timestamp files
367+ for (int i = 0 ; i < m_dataTimestampFiles.size (); i++)
368+ {
369+ if (m_dataTimestampFiles[i] == nullptr || ! m_dataTimestampFiles[i]->isOpen ())
370+ {
371+ allFilesValid = false ;
372+ }
373+ }
374+
375+ // Check sync timestamp files
376+ for (int i = 0 ; i < m_dataSyncTimestampFiles.size (); i++)
377+ {
378+ if (m_dataSyncTimestampFiles[i] == nullptr || ! m_dataSyncTimestampFiles[i]->isOpen ())
379+ {
380+ allFilesValid = false ;
381+ }
382+ }
383+
384+ // Check event files
385+ for (int i = 0 ; i < m_eventFiles.size (); i++)
386+ {
387+ EventRecording* rec = m_eventFiles[i];
388+ if (rec != nullptr )
389+ {
390+ if (rec->data == nullptr || ! rec->data ->isOpen ())
391+ {
392+ allFilesValid = false ;
393+ }
394+ if (rec->samples == nullptr || ! rec->samples ->isOpen ())
395+ {
396+ allFilesValid = false ;
397+ }
398+ if (rec->timestamps == nullptr || ! rec->timestamps ->isOpen ())
399+ {
400+ allFilesValid = false ;
401+ }
402+ // extraFile is optional (only for TTL full words)
403+ if (rec->extraFile != nullptr && ! rec->extraFile ->isOpen ())
404+ {
405+ allFilesValid = false ;
406+ }
407+ }
408+ }
409+
410+ // Check spike files
411+ for (int i = 0 ; i < m_spikeFiles.size (); i++)
412+ {
413+ EventRecording* rec = m_spikeFiles[i];
414+ if (rec != nullptr )
415+ {
416+ if (rec->data == nullptr || ! rec->data ->isOpen ())
417+ {
418+ allFilesValid = false ;
419+ }
420+ if (rec->samples == nullptr || ! rec->samples ->isOpen ())
421+ {
422+ allFilesValid = false ;
423+ }
424+ if (rec->timestamps == nullptr || ! rec->timestamps ->isOpen ())
425+ {
426+ allFilesValid = false ;
427+ }
428+ if (rec->channels == nullptr || ! rec->channels ->isOpen ())
429+ {
430+ allFilesValid = false ;
431+ }
432+ if (rec->extraFile == nullptr || ! rec->extraFile ->isOpen ())
433+ {
434+ allFilesValid = false ;
435+ }
436+ }
437+ }
438+
439+ // Check sync text file
440+ if (m_syncTextFile == nullptr )
441+ {
442+ allFilesValid = false ;
443+ }
444+
445+ return allFilesValid;
336446}
337447
338448std::unique_ptr<NpyFile> BinaryRecording::createEventMetadataFile (const MetadataEventObject* channel, String filename, DynamicObject* jsonFile)
@@ -549,6 +659,9 @@ void BinaryRecording::writeContinuousData (int writeChannel,
549659 /* Get the file index that belongs to the current recording channel */
550660 int fileIndex = m_fileIndexes[writeChannel];
551661
662+ if (! m_continuousFiles[fileIndex])
663+ return ;
664+
552665 /* Write the data to that file */
553666 m_continuousFiles[fileIndex]->writeChannel (
554667 m_samplesWritten[writeChannel],
@@ -565,7 +678,7 @@ void BinaryRecording::writeContinuousData (int writeChannel,
565678
566679 uint32 streamId = getContinuousChannel (realChannel)->getStreamId ();
567680
568- if (! wroteFirstSampleNumber[streamId] )
681+ if (! wroteFirstSampleNumber[streamId])
569682 {
570683 firstSampleNumber[streamId] = baseSampleNumber;
571684 wroteFirstSampleNumber[streamId] = true ;
@@ -682,11 +795,11 @@ void BinaryRecording::writeTimestampSyncText (uint64 streamId, int64 sampleNumbe
682795
683796 int64 fsn = firstSampleNumber[streamId];
684797
685- if (streamId > 0 )
798+ if (streamId > 0 )
686799 jassert (fsn == sampleNumber);
687800
688801 m_syncTextFile->writeText (syncString + " \r\n " , false , false , nullptr );
689-
802+
690803 m_syncTextFile->flush ();
691804}
692805
0 commit comments