File indexing completed on 2025-02-23 04:35:42

0001 /*
0002     SPDX-FileCopyrightText: 2010-2022 Mladen Milinkovic <max@smoothware.net>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "zoombuffer.h"
0008 
0009 #include <list>
0010 
0011 struct DataRange {
0012     quint32 start;
0013     quint32 end;
0014 };
0015 typedef std::list<DataRange> RangeList;
0016 
0017 using namespace SubtitleComposer;
0018 
0019 ZoomBuffer::ZoomBuffer(WaveBuffer *parent)
0020     : QThread(parent),
0021       m_waveBuffer(parent),
0022       m_samplesPerPixel(0),
0023       m_waveformZoomed(nullptr),
0024       m_waveformZoomedSize(0),
0025       m_waveform(nullptr)
0026 {
0027 }
0028 
0029 ZoomBuffer::~ZoomBuffer()
0030 {
0031     stopAndClear();
0032 }
0033 
0034 void
0035 ZoomBuffer::stopAndClear()
0036 {
0037     requestInterruption();
0038     wait();
0039 
0040     if(m_waveformZoomed) {
0041         m_waveformZoomedSize = 0;
0042         for(quint16 ch = 0; ch < m_waveBuffer->channels(); ch++)
0043             delete[] m_waveformZoomed[ch];
0044         delete[] m_waveformZoomed;
0045         m_waveformZoomed = nullptr;
0046         m_reqLen = nullptr;
0047     }
0048 }
0049 
0050 void
0051 ZoomBuffer::start()
0052 {
0053     if(!m_samplesPerPixel || !m_waveform)
0054         return;
0055 
0056     Q_ASSERT(m_waveformZoomed == nullptr);
0057 
0058     // alloc memory for zoomed pixel data
0059     m_waveformZoomedSize = (m_waveBuffer->lengthSamples() + m_samplesPerPixel - 1) / m_samplesPerPixel;
0060     m_waveformZoomed = new WaveZoomData *[m_waveBuffer->channels()];
0061     for(quint32 i = 0; i < m_waveBuffer->channels(); i++)
0062         m_waveformZoomed[i] = new WaveZoomData[m_waveformZoomedSize];
0063     emit zoomedBufferReady();
0064 
0065     QThread::start();
0066 }
0067 
0068 void
0069 ZoomBuffer::run()
0070 {
0071     Q_ASSERT(m_waveform != nullptr);
0072     Q_ASSERT(m_waveformZoomed != nullptr);
0073     Q_ASSERT(m_samplesPerPixel > 0);
0074     Q_ASSERT(m_waveBuffer->lengthSamples() > 0);
0075 
0076     m_restartProcessing = false;
0077 
0078     RangeList ranges;
0079     quint32 lastProcessed = 0;
0080     RangeList::iterator range = ranges.end();
0081     for(;;) {
0082         // wait for more samples if there aren't any
0083         if(ranges.empty()) {
0084             while(!isInterruptionRequested()) {
0085                 const bool decoding = m_waveBuffer->isDecoding();
0086                 const quint32 lastAvailable = m_waveBuffer->samplesAvailable() / m_samplesPerPixel;
0087                 if(lastProcessed != lastAvailable) {
0088                     ranges.push_back(DataRange{lastProcessed, lastAvailable});
0089                     break;
0090                 }
0091                 if(!decoding)
0092                     break;
0093                 msleep(100);
0094             }
0095         }
0096 
0097         // process requested range
0098         if(m_reqLen) {
0099             QMutexLocker l(&m_reqMutex);
0100 
0101             m_restartProcessing = false;
0102 
0103             RangeList::iterator reqRange = ranges.begin();
0104             while(reqRange != ranges.end()) {
0105                 if(reqRange->start >= m_reqEnd || m_reqStart >= reqRange->end) {
0106                     ++reqRange;
0107                     continue;
0108                 }
0109                 if(reqRange->start < m_reqStart) {
0110                     // there are samples before requested range
0111                     ranges.insert(reqRange, DataRange{reqRange->start, m_reqStart});
0112                     reqRange->start = m_reqStart;
0113                 }
0114                 if(reqRange->end > m_reqEnd) {
0115                     // there are samples after requested range
0116                     ranges.insert(std::next(reqRange), DataRange{m_reqEnd, reqRange->end});
0117                     reqRange->end = m_reqEnd;
0118                 }
0119                 *m_reqLen = reqRange->start - m_reqStart;
0120                 emit zoomedBufferReady();
0121                 break;
0122             }
0123 
0124             if(reqRange == ranges.end()) {
0125                 const quint32 lastAvailable = m_waveBuffer->samplesAvailable() / m_samplesPerPixel;
0126                 if(lastAvailable < m_reqEnd) {
0127                     *m_reqLen = lastAvailable - qMin(m_reqStart, lastAvailable);
0128                 } else {
0129                     // got whole range... do not check no more
0130                     *m_reqLen = m_reqEnd - m_reqStart;
0131                     m_reqLen = nullptr;
0132                 }
0133                 emit zoomedBufferReady();
0134             } else {
0135                 range = reqRange;
0136             }
0137         }
0138 
0139         // there's nothing left
0140         if(ranges.empty() || isInterruptionRequested())
0141             break;
0142 
0143         // otherwise process what is left
0144         if(range == ranges.end())
0145             range = ranges.begin();
0146 
0147         Q_ASSERT(range != ranges.end());
0148 
0149         updateZoomRange(&range->start, range->end);
0150         lastProcessed = range->start;
0151 
0152         // whole range was processed
0153         if(range->start == range->end)
0154             range = ranges.erase(range);
0155     }
0156 }
0157 
0158 void
0159 ZoomBuffer::updateZoomRange(quint32 *start, quint32 end)
0160 {
0161     Q_ASSERT(end <= m_waveformZoomedSize);
0162 
0163     const quint16 channels = m_waveBuffer->channels();
0164 
0165     while(*start < end) {
0166         quint32 i = *start * m_samplesPerPixel;
0167 
0168         for(quint16 ch = 0; ch < channels; ch++) {
0169             const quint32 val = qAbs(qint32(m_waveform[ch][i]) - SAMPLE_MIN - (SAMPLE_MAX - SAMPLE_MIN) / 2);
0170             m_waveformZoomed[ch][*start].min = val / m_samplesPerPixel;
0171             m_waveformZoomed[ch][*start].max = val;
0172         }
0173 
0174         const quint32 iEnd = i + m_samplesPerPixel;
0175         while(++i < iEnd) {
0176             for(quint16 ch = 0; ch < channels; ch++) {
0177                 const quint32 val = qAbs(qint32(m_waveform[ch][i]) - SAMPLE_MIN - (SAMPLE_MAX - SAMPLE_MIN) / 2);
0178                 m_waveformZoomed[ch][*start].min += val / m_samplesPerPixel;
0179                 if(m_waveformZoomed[ch][*start].max < val)
0180                     m_waveformZoomed[ch][*start].max = val;
0181             }
0182         }
0183 
0184         (*start)++;
0185 
0186         if(isInterruptionRequested() || m_restartProcessing)
0187             break;
0188     }
0189 }
0190 
0191 void
0192 ZoomBuffer::setWaveform(const SAMPLE_TYPE * const *waveform)
0193 {
0194     QMutexLocker l(&m_publicMutex);
0195 
0196     stopAndClear();
0197 
0198     m_waveform = waveform;
0199 
0200     start();
0201 }
0202 
0203 void
0204 ZoomBuffer::setZoomScale(quint32 samplesPerPixel)
0205 {
0206     QMutexLocker l(&m_publicMutex);
0207 
0208     if(m_samplesPerPixel == samplesPerPixel)
0209         return;
0210 
0211     stopAndClear();
0212 
0213     m_samplesPerPixel = samplesPerPixel;
0214 
0215     start();
0216 }
0217 
0218 void
0219 ZoomBuffer::zoomedBuffer(quint32 timeStart, quint32 timeEnd, WaveZoomData **buffers, quint32 *bufLen)
0220 {
0221     *bufLen = 0;
0222 
0223     if(!m_waveform || !m_waveformZoomed)
0224         return;
0225 
0226     QMutexLocker l(&m_reqMutex);
0227 
0228     m_reqStart = qMin(quint64(timeStart) * m_waveBuffer->sampleRate() / m_samplesPerPixel / 1000, quint64(m_waveformZoomedSize));
0229     m_reqEnd = qMin(quint64(timeEnd) * m_waveBuffer->sampleRate() / m_samplesPerPixel / 1000, quint64(m_waveformZoomedSize));
0230     m_reqLen = bufLen;
0231 
0232     for(quint16 ch = 0; ch < m_waveBuffer->channels(); ch++)
0233         buffers[ch] = &m_waveformZoomed[ch][m_reqStart];
0234 
0235     if(isFinished()) {
0236         const quint32 lastAvailable = m_waveBuffer->samplesAvailable() / m_samplesPerPixel;
0237         *bufLen = qMin(m_reqEnd, lastAvailable) - qMin(m_reqStart, lastAvailable);
0238     } else {
0239         *bufLen = 0;
0240         m_restartProcessing = true;
0241     }
0242 }