diff --git a/UserTools/Digitizer/Digitizer.h b/UserTools/Digitizer/Digitizer.h
index 3853c4c..10b0254 100644
--- a/UserTools/Digitizer/Digitizer.h
+++ b/UserTools/Digitizer/Digitizer.h
@@ -22,6 +22,17 @@ class Digitizer: public ToolFramework::Tool {
   protected:
     using Event = std::vector<Hit>;
 
+    template <typename RawEvent>
+    class Chops {
+      public:
+        bool chop_event(size_t cycle, RawEvent& event, bool head);
+        void clear() { chops.clear(); };
+
+      private:
+        std::map<size_t, RawEvent> chops;
+        std::mutex                 mutex;
+    };
+
     // Connects and configures the boards. Returns the number of boards and a
     // pointer to VMEReadout object to store data in. This method is called
     // from Initialise and is wrapped in a try-catch block.
@@ -96,6 +107,22 @@ class Digitizer: public ToolFramework::Tool {
 
 };
 
+template <typename Packet, typename Hit>
+template <typename RawEvent>
+bool Digitizer<Packet, Hit>::Chops<RawEvent>::chop_event(
+    size_t cycle, RawEvent& event, bool head
+) {
+  std::lock_guard<std::mutex> lock(mutex);
+  auto pevent = chops.lower_bound(cycle);
+  if (pevent == chops.end() || pevent->first != cycle) {
+    chops.insert(pevent, { cycle, event });
+    return false;
+  };
+  event.merge(pevent->second, head);
+  chops.erase(pevent);
+  return true;
+};
+
 template <typename Packet, typename Hit>
 void Digitizer<Packet, Hit>::readout() {
   std::vector<std::vector<Packet>> data(nboards);
diff --git a/UserTools/V1290/V1290.cpp b/UserTools/V1290/V1290.cpp
index 8b14b01..d88e540 100644
--- a/UserTools/V1290/V1290.cpp
+++ b/UserTools/V1290/V1290.cpp
@@ -13,18 +13,6 @@ void V1290::RawEvent::merge(RawEvent& event, bool tail) {
   hits.insert(hits.end(), event.hits.begin(), event.hits.end());
 };
 
-bool V1290::chop_event(size_t cycle, RawEvent& event, bool head) {
-  std::lock_guard<std::mutex> lock(chops_mutex);
-  auto pevent = chops.lower_bound(cycle);
-  if (pevent == chops.end() || pevent->first != cycle) {
-    chops.insert(pevent, { cycle, event });
-    return false;
-  };
-  event.merge(pevent->second, head);
-  chops.erase(pevent);
-  return true;
-};
-
 void V1290::connect() {
   auto connections = caen_connections(m_variables);
   boards.reserve(connections.size());
@@ -314,13 +302,13 @@ void V1290::fini() {
 };
 
 void V1290::start_acquisition() {
+  chops.clear();
   for (auto& board : boards) board.tdc.clear();
   Digitizer<caen::V1290::Packet, TDCHit>::start_acquisition();
 };
 
 void V1290::stop_acquisition() {
   Digitizer<caen::V1290::Packet, TDCHit>::stop_acquisition();
-  chops.clear();
 };
 
 void V1290::process(
@@ -372,7 +360,7 @@ void V1290::process(
 
       case caen::V1290::Packet::GlobalTrailer:
         copy_hits(header, packet, nhits);
-        if (header != tdc_data.end() || chop_event(cycle, event, false))
+        if (header != tdc_data.end() || chops.chop_event(cycle, event, false))
           process(get_event, event);
         header = tdc_data.end();
         break;
@@ -380,7 +368,7 @@ void V1290::process(
 
   if (header != tdc_data.end()) {
     copy_hits(header, tdc_data.end(), nhits);
-    if (chop_event(cycle + 1, event, true))
+    if (chops.chop_event(cycle + 1, event, true))
       process(get_event, event);
   };
 };
diff --git a/UserTools/V1290/V1290.h b/UserTools/V1290/V1290.h
index 0e848ad..ab730db 100644
--- a/UserTools/V1290/V1290.h
+++ b/UserTools/V1290/V1290.h
@@ -27,11 +27,10 @@ class V1290: public Digitizer<caen::V1290::Packet, TDCHit> {
       void merge(RawEvent& event, bool tail);
     };
 
-    std::vector<Board> boards;
-    std::mutex tdc_errors_mutex;
+    std::vector<Board>  boards;
+    std::mutex          tdc_errors_mutex;
     caen::V1290::Buffer buffer;
-    std::map<size_t, RawEvent> chops;
-    std::mutex chops_mutex;
+    Chops<RawEvent>     chops;
 
     bool chop_event(size_t cycle, RawEvent&, bool head);
 
diff --git a/UserTools/V792/V792.cpp b/UserTools/V792/V792.cpp
index eedd5a1..12828d3 100644
--- a/UserTools/V792/V792.cpp
+++ b/UserTools/V792/V792.cpp
@@ -6,6 +6,15 @@
 #include "V792.h"
 #include "caen.h"
 
+void V792::RawEvent::merge(RawEvent& event, bool tail) {
+  if (tail)
+    trailer = event.trailer;
+  else
+    header  = event.header;
+  memcpy(hits + nhits, event.hits, event.nhits * sizeof(*hits));
+  nhits += event.nhits;
+};
+
 void V792::connect() {
   auto connections = caen_connections(m_variables);
   boards.reserve(connections.size());
@@ -244,29 +253,93 @@ void V792::process(
 ) {
   if (qdc_data.empty()) return;
 
-  if (qdc_data.front().type() != caen::V792::Packet::Header) {
-    // should never happen
-    std::stringstream ss;
-    ss << "QDC: unexpected packet 0x" << std::dec << qdc_data.front();
-    throw std::runtime_error(ss.str());
+  auto packet = qdc_data.begin();
+
+  auto skip_fillers = [&]() {
+    while (   packet != qdc_data.end()
+           && packet->type() == caen::V792::Packet::Invalid)
+      ++packet;
   };
 
-  std::vector<caen::V792::Packet>::iterator pheader;
-  for (auto packet = qdc_data.begin(); packet != qdc_data.end(); ++packet)
-    switch (packet->type()) {
-      case caen::V792::Packet::Header:
-        pheader = packet;
-        break;
+  skip_fillers();
+  if (packet == qdc_data.end()) return;
+
+  RawEvent* event = nullptr;
+
+  if (packet->type() != caen::V792::Packet::Header) {
+    // alloca is to avoid initialization of event --- all fields will be
+    // overwritten anyway
+    event = reinterpret_cast<RawEvent*>(alloca(sizeof(*event)));
+    event->nhits = 0;
+    while (packet->type() != caen::V792::Packet::EndOfBlock) {
+      if (event->nhits >= 32)
+        throw std::runtime_error("QDC: too many hits in an event");
+      event->hits[event->nhits++] = packet++->as<caen::V792::Data>();
+      if (packet == qdc_data.end())
+        throw std::runtime_error("QDC: unexpected end of a chopped event");
+    };
+    event->trailer = packet->as<caen::V792::EndOfBlock>();
+    if (chops.chop_event(cycle, *event, false))
+      process(get_event, *event);
+    skip_fillers();
+  };
 
-      case caen::V792::Packet::EndOfBlock: {
-        Event& event = get_event(packet->as<caen::V792::EndOfBlock>().event());
+  while (packet != qdc_data.end()) {
+    if (packet->type() != caen::V792::Packet::Header) {
+      std::stringstream ss;
+      ss
+        << "QDC: unexpected packet 0x"
+        << std::hex << *packet
+        << ", expected header";
+      throw std::runtime_error(ss.str());
+    };
+    
+    auto header   = packet->as<caen::V792::Header>();
+    auto ptrailer = packet + header.count() + 1;
+    if (ptrailer < qdc_data.end()) {
+      auto trailer = ptrailer->as<caen::V792::EndOfBlock>();
+      process(
+          get_event, header, static_cast<caen::V792::Data*>(&*packet), trailer
+      );
+      packet = ptrailer;
+      skip_fillers();
+    } else {
+      if (!event) event = reinterpret_cast<RawEvent*>(alloca(sizeof(*event)));
+      event->header = header;
+      event->nhits  = 0;
+      while (++packet != qdc_data.end())
+        event->hits[event->nhits++] = packet->as<caen::V792::Data>();
+      if (chops.chop_event(cycle + 1, *event, true))
+        process(get_event, *event);
+    };
+  };
+};
 
-        auto ptrailer = packet;
-        for (packet = pheader + 1; packet != ptrailer; ++packet)
-          if (packet->type() == caen::V792::Packet::Data)
-            event.push_back(QDCHit(*pheader, *packet, *ptrailer));
+void V792::process(
+    const std::function<Event& (uint32_t)>& get_event,
+    RawEvent&                               event
+) {
+  if (event.nhits != event.header.count()) {
+    std::stringstream ss;
+    ss
+      << "QDC: mismatched chopped event: expected "
+      << static_cast<unsigned>(event.header.count())
+      << " hits, got "
+      << event.nhits;
+    throw std::runtime_error(ss.str());
+  };
+  process(get_event, event.header, event.hits, event.trailer);
+};
 
-        break;
-      };
-    };
+void V792::process(
+    const std::function<Event& (uint32_t)>& get_event,
+    caen::V792::Header                      header,
+    caen::V792::Data*                       hits,
+    caen::V792::EndOfBlock                  trailer
+) {
+  uint8_t n = header.count();
+  Event& event = get_event(trailer.event());
+  event.reserve(event.size() + n);
+  for (uint8_t i = 0; i < n; ++i)
+    event.push_back(QDCHit(header, hits[i], trailer));
 };
diff --git a/UserTools/V792/V792.h b/UserTools/V792/V792.h
index cbc9baf..8499b7c 100644
--- a/UserTools/V792/V792.h
+++ b/UserTools/V792/V792.h
@@ -18,8 +18,20 @@ class V792: public Digitizer<caen::V792::Packet, QDCHit> {
       unsigned event_map[32];
     };
 
+    struct RawEvent {
+      caen::V792::Header     header;
+      caen::V792::EndOfBlock trailer;
+      caen::V792::Data       hits[32];
+      unsigned               nhits;
+
+      void merge(RawEvent& event, bool tail);
+    };
+
     std::vector<Board> boards;
     caen::V792::Buffer buffer;
+    Chops<RawEvent>    chops;
+
+    void chop_event(size_t cycle, RawEvent&, bool head);
 
     void connect();
     void configure() final;
@@ -43,6 +55,18 @@ class V792: public Digitizer<caen::V792::Packet, QDCHit> {
         unsigned                                qdc_index,
         std::vector<caen::V792::Packet>         qdc_data
     ) final;
+
+    void process(
+        const std::function<Event& (uint32_t)>& get_event,
+        RawEvent&
+    );
+
+    void process(
+        const std::function<Event& (uint32_t)>& get_event,
+        caen::V792::Header,
+        caen::V792::Data*,
+        caen::V792::EndOfBlock
+    );
 };
 
 #endif
