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 }