11 #include <QMutexLocker>
21 using namespace std::chrono_literals;
23 #define LOC QString("AOG: ")
36 std::chrono::milliseconds
Next()
const {
return m_tcNext; }
37 std::chrono::milliseconds
First()
const {
return m_tcFirst; }
39 using Range = std::pair<std::chrono::milliseconds, std::chrono::milliseconds>;
42 if (Timecode == 0ms || Timecode == -1ms)
45 std::chrono::milliseconds first = Timecode - Samples2MS(m_maxSamples / 2);
46 if (first < m_tcFirst)
49 std::chrono::milliseconds second = first + Samples2MS(m_maxSamples);
50 if (second > m_tcNext)
53 if (second < first + Samples2MS(m_maxSamples))
55 first = second - Samples2MS(m_maxSamples);
56 if (first < m_tcFirst)
60 return {first, second};
65 return MS2Samples(Available.second - Available.first);
70 m_tcFirst = m_tcNext = 0ms;
71 m_bits = m_channels = 0;
75 void Append(
const void *
Buffer,
unsigned long Length, std::chrono::milliseconds Timecode,
76 int Channels,
int Bits)
78 if (m_bits != Bits || m_channels != Channels)
80 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"%1, %2 channels, %3 bits")
81 .arg(Timecode.count()).arg(Channels).arg(Bits));
82 Resize(Channels, Bits);
83 m_tcNext = m_tcFirst = Timecode;
86 auto samples = Bytes2Samples(
static_cast<unsigned>(Length));
87 std::chrono::milliseconds tcNext = Timecode + Samples2MS(
samples);
89 if (qAbs((Timecode - m_tcNext).count()) <= 1)
91 Append(
Buffer, Length, Bits);
94 else if (Timecode >= m_tcFirst && tcNext <= m_tcNext)
101 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Discontinuity %1 -> %2")
102 .arg(m_tcNext.count()).arg(Timecode.count()));
104 Resize(Channels, Bits);
105 Append(
Buffer, Length, Bits);
106 m_tcFirst = Timecode;
110 auto overflow = size() - m_sizeMax;
114 m_tcFirst = m_tcNext - Samples2MS(Bytes2Samples(
static_cast<unsigned>(m_sizeMax)));
120 auto start = MS2Samples(Available.first - m_tcFirst);
121 return reinterpret_cast<const int16_t*
>(constData() + (
static_cast<ptrdiff_t
>(start) * BytesPerSample()));
127 return static_cast<uint>(m_channels * ((m_bits + 7) / 8));
132 return (m_channels && m_bits) ? Bytes / BytesPerSample() : 0;
137 return m_sampleRate ? std::chrono::milliseconds((Samples * 1000UL + m_sampleRate - 1) / m_sampleRate) : 0ms;
142 return Msecs > 0ms ?
static_cast<int>((Msecs.count() * m_sampleRate) / 1000) : 0;
154 resize(n +
static_cast<int>(
sizeof(int16_t) * count));
155 const auto * src =
reinterpret_cast<const uchar*
>(
Buffer);
156 auto * dst =
reinterpret_cast<int16_t*
>(data() + n);
158 *dst++ =
static_cast<int16_t
>((
static_cast<int16_t
>(*src++) - CHAR_MAX) << (16 - CHAR_BIT));
162 append(
reinterpret_cast<const char*
>(
Buffer),
static_cast<int>(Length));
167 unsigned long count = Length /
sizeof(float);
169 resize(n +
static_cast<int>(
sizeof(int16_t) * count));
170 const float f((1 << 15) - 1);
171 const auto * src =
reinterpret_cast<const float*
>(
Buffer);
172 auto * dst =
reinterpret_cast<int16_t*
>(data() + n);
174 *dst++ =
static_cast<int16_t
>(f * (*src++));
178 append(
reinterpret_cast<const char*
>(
Buffer),
static_cast<int>(Length));
187 m_channels = Channels;
188 m_sizeMax =
static_cast<int>(((m_sampleRate *
kBufferMilliSecs) / 1000) * BytesPerSample());
193 std::chrono::milliseconds m_tcFirst { 0ms };
194 std::chrono::milliseconds m_tcNext { 0ms };
198 int m_channels { 0 };
220 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Set sample rate %1)").arg(
SampleRate));
227 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Set sample count %1").arg(SampleCount));
237 std::chrono::milliseconds Timecode,
int Channnels,
int Bits)
245 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Reset");
255 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
256 QString(
"GetImage for timecode %1 using [%2..%3] available [%4..%5]")
257 .arg(Timecode.count()).arg(avail.first.count()).arg(avail.second.count())
265 const auto threshold = 20 * log10(1.0 / range);
266 auto height =
static_cast<int>(-ceil(threshold));
274 const auto * max =
reinterpret_cast<const int16_t*
>(
m_buffer->constData() +
m_buffer->size());
278 if ((data + (channels *
static_cast<ptrdiff_t
>(width))) >= max)
280 LOG(VB_GENERAL, LOG_WARNING,
LOC +
"Buffer overflow. Clipping samples.");
281 width =
static_cast<int>(max - data) / channels;
284 QImage image(width, height, QImage::Format_ARGB32);
287 for (
int x = 0; x < width; ++x)
290 auto right = channels > 1 ? data[1] : left;
293 auto avg = qAbs(left) + qAbs(right);
294 double db = 20 * log10(
static_cast<double>(
avg ?
avg : 1) / range);
295 auto idb =
static_cast<int>(ceil(db));
296 auto rgb { qRgb(255, 0, 0) };
298 rgb = qRgb(255, 255, 255);
300 rgb = qRgb( 0, 255, 255);
302 rgb = qRgb( 0, 255, 0);
304 rgb = qRgb(255, 255, 0);
306 int v = height -
static_cast<int>(height * (db / threshold));
309 for (
int y = 0; y <= v; ++y)
310 image.setPixel(x, height - 1 - y, rgb);
314 result->Assign(image);