QAudioBuffer providing different data of the same song in different computers - qt

I'm creating a music player for PC. I want to visualize the FFT of the song. I've crated an entire class that buffers 1024 points of data does the FFT and displays it (this is handled by another class). My program was developed in my laptop which uses Debian Testing x64. My work pc uses Centos 7 x64. When I compiled my program (both use Qt 5.7.0) on my work PC the FFT visualization was garbage. Snooping into my code I found that the sample type provided by QAudioBuffer from QAudioProbe was Signed (in my work PC) while it was float in my Laptop. Here is the code that is called whenever QAudioProbe emits that data has been buffered:
void SpectrumController::setAudioBuffer(QAudioBuffer buffer){
// Used to momentarily stop the process.
if (!enableBuffering) return;
// Only process stereo frames
if (buffer.format().channelCount() != 2) return;
if (buffer.format().sampleType() == QAudioFormat::SignedInt){
//qWarning() << "Signed";
QAudioBuffer::S16S *data = buffer.data<QAudioBuffer::S16S>();
bufferData(data,buffer.frameCount());
}
else if (buffer.format().sampleType() == QAudioFormat::UnSignedInt){
//qWarning() << "Unsigned";
QAudioBuffer::S16U *data = buffer.data<QAudioBuffer::S16U>();
bufferData(data,buffer.frameCount());
}
else if(buffer.format().sampleType() == QAudioFormat::Float){
//qWarning() << "Float";
QAudioBuffer::S32F *data = buffer.data<QAudioBuffer::S32F>();
bufferData(data,buffer.frameCount());
}
}
template<typename T>
void SpectrumController::bufferData(T *data, qint32 N){
for (qint32 i = 0; i < N; i++){
//if (qAbs(data[i].left) > largest){largest = qAbs(data[i].left); qDebug() << "Largest" << largest;}
//currentBuffer << ((qreal)data[i].left/(largest));
//qWarning() << "Added data" << currentBuffer.last();
currentBuffer << data[i].left;
if (datcounter < 100000){
*writer << data[i].left;
*writer << "\n";
datcounter++;
}
else if (writeFile->isOpen()){
qWarning() << "Closed file";
writeFile->close();
}
if (currentBuffer.size() == FFT_SIZE){
dataBuffer << currentBuffer;
currentBuffer.clear();
if (!isRunning) run();
}
What I ended up doing is writing, to a file, the first 100.000 points of data gathered by both my laptop and my work PC in order to plot them.
This is what I've got
What I think is that difference is in the base system's handling of the the mp3, which, in turn, is what Qt uses. I think is gstreamer. Centos uses a much older version. The plot on the right corresponds to my laptop while the plot on the left corresponds to my work pc.
Any ideas on how to fix this? Or am I just stuck with no way of accessising the raw audio data correctly?
UPDATE:
Even though this is not a Fix or anything like that, the data in the other channel (data[i].right) did have more appropiate data. I'm using the right channnel, for now.

Related

Unexplained time offset in QApplication event loop

I'm currently working with a program for predicting the locations of satellites in real-time. Something similar to this. The underlying library uses system time as input.
time_t now(time(0));
This program accurately predicts the real-time position of satellites when I run it on a C++ console application using Qt Creator.
The problem is when I use it in a fully-fledged Qt Gui application with a QApplication object in the main function. In the program, the prediction function is periodically by the timer event function. That way I update the positions every 2 seconds. Unfortunately, The output doesn't match (either on the GUI or when I print it). It is like the orbital propagator is using a different time when calculating the satellite positions.
void TrackingManager::timerEvent(QTimerEvent *event)
{
int nNumSats = m_Satellites.size() ;
//std::cout << __func__ << " - Number of satellites = " << nNumSats << std::endl;
std::vector<SatPosition> vSatPositions;
if (nNumSats >= 0)
{
time_t now(time(0));
std::cout << __func__ << "time(0) = " << asctime(gmtime(&now)) << std::endl;
for(int i = 0; i < nNumSats; i++)
{
// Get satellite names and calculate position, altitude etc
SatPosition spPos;
GetInstantPredict(m_Satellites[i], now, spPos);
vSatPositions.push_back(spPos);
}
emit UpdateSatPosition(vSatPositions);
}
}
Even more confusing, the program works fine when I run the debugger (GDB on Ubuntu). It is as if GDB somehow manages to "fix" the problem. Does this make any sense?

QSharedMemory not the same size

QSharedMemory is changing sizes on me.
create:
...
int size = buffer->size();
qDebug() << "buffer->size()" << size << "points" << points->size() << "share name" << sharedMemoryName;
if (!m_sharedMemory->create(size)) {
qCritical() << tr("Unable to create shared memory segment.");
return;
}
m_sharedMemory->lock();
char *to = (char*)m_sharedMemory->data();
memcpy(to, buffer->data(), qMin(m_sharedMemory->size(), size));
m_sharedMemory->unlock();
read:
QSharedMemory sharedMemory(sharedMemoryName);
if (!sharedMemory.attach(QSharedMemory::AccessMode::ReadOnly)) {
qCritical() << "Unable to attach to shared memory segment.";
return nullptr;
}
qDebug() << sharedMemoryName << sharedMemory.size();
Not the same size.
when create the size is 658824
when read the size is 659456
ok - sounds crazy now, but I run the read multiple times and all the sudden the size was correct. Then I restarted everything (same size on create) and the error came back.
edit:
I just realized that the size of the QSharedMemory is not necessarily then same as the QBuffer
memcpy(to, buffer->data(), qMin(m_sharedMemory->size(), size));
why is that and how can I know "on the other side" the correct size (without making an ugly workaround)
edit 2:
I may found it. looks like QSharedMemory reserves the memory in 4096 blocks.
solution for me is to check the QByteArray for empty
if(in.at(i) == QChar(0))
break;

Qt : How to create a video from multiple QImages

How to create a .mp4 video out of multiple QImages in a Qt application.
Looking at QMediaRecorder examples, it only knows how to grab frames from camera. There seems to be no way to pass multiple QImages or some other image data type into QMediaRecorder simply to make a video out of them which has nothing to do with the camera.
Development Environment:
Using Qt 5.9.1 commercial version with app working on Android, iOS & OSX.
It is hard to ascertain exactly what you need to do here, considering it is not clear just how many images you are processing.
That being said, this is possible if you use a tool such as ffmpeg to generate the video, however it will require you to at the very least, write those images to disc.
Here is a working example I use to generate slideshows videos for youtube. The concatenation of images is ascertained by their naming scheme as saved on the drive.
sl << "-i" << md.sku(true) + "##%03d.png"; // Images input,
as such,
mysku##001.png // First Slide
mysku##002.png // Second Slide
mysku##003.png // Third Slide
mysku##004.png // Fourth Slide
VideoConvert::VideoConvert(Metadata &md, QFile &oggFile, QObject *parent) : QObject(parent)
{
QStringList sl;
tt.warning(md.duration());
tt.warning(md.length());
QString framerate = md.duration(true);
int hour = QString(md.length()).split(":").at(0).toInt();
int minute = QString(md.length()).split(":").at(1).toInt();
int second = QString(md.length()).split(":").at(2).toInt();
framerate.remove(".");
framerate.remove(QRegularExpression("^[0]*"));
sl << "-y"; // overwrite
sl << "-framerate" << QString::number(md.images().length())
+ "/" + QString::number(((hour * 60) * 60) + (minute * 60) + second);
sl << "-i" << md.sku(true) + "##%03d.png"; // Images input,
sl << "-i" << oggFile.fileName();
sl << "-c" << "copy";
sl << "/home/akiva/FrogCast/" + md.title(true) + " ⟪Wiki🔊Book⟫.mp4";
md.setName(sl.last());
QEventLoop convertEvent;
m_Convert.setReadChannelMode(QProcess::MergedChannels);
connect(&m_Convert, SIGNAL(readyRead()), this, SLOT(convert()));
connect(this, SIGNAL(converted()), &convertEvent, SLOT(quit()));
tt.process("Converting Video File");
for (int i=0; i < sl.length(); i++) {
QTextStream(stdout) << "\t" << sl.at(i) << endl;
}
if (QFile("/home/akiva/FrogCast/Cereproc/ffmpeg").exists()) {
m_Convert.start("/home/akiva/FrogCast/Cereproc/ffmpeg", sl);
} else {
m_Convert.start("ffmpeg", sl);
}
convertEvent.exec();
disconnect(&m_Convert, SIGNAL(finished(int)), this, SLOT(convert()));
disconnect(this, SIGNAL(converted()), &convertEvent, SLOT(quit()));
m_Convert.waitForFinished();
}

Is this code send hex data in correct way in Qt C++?

I am new to Qt.I am working on finger print madoule with this document. I want to send my data to serial port in this format:
I wrote my code in this format, but I think my data has mistake, because this code turn on the LED in some device:
QByteArray ba;
ba.resize(24);
ba[0]=0x55;
ba[1]=0xAA;
ba[2]=0x24;
ba[3]=0x01;
ba[4]=0x01;
ba[5]=0x00;
ba[6]=0x00;
ba[7]=0x00;
ba[8]=0x00;
ba[9]=0x00;
ba[10]=0x00;
ba[11]=0x00;
ba[12]=0x00;
ba[13]=0x00;
ba[14]=0x00;
ba[15]=0x00;
ba[16]=0x00;
ba[17]=0x00;
ba[18]=0x00;
ba[19]=0x00;
ba[20]=0x00;
ba[21]=0x00;
ba[22]=0x27;
ba[23]=0x01;
p->writedata(ba);
Is this data correct?
You're just copying a drawing into code. It won't work without understanding what the drawing means. You seem to miss that:
The LEN field seems to be a little-endian integer that gives the number of bytes in the DATA field - perhaps it's the number of bytes that carry useful information if the packet has a fixed size.
The CKS field seems to be a checksum of some sort. You need to calculate it based on the contents of the packet. The protocol documentation should indicate whether it's across the entire packet or not, and how to compute the value.
It seems like you are talking to a fingerprint identification module like FPM-1502, SM-12, ADST11SD300/310 or similar. If so, then you could obtain a valid command packet as follows:
QByteArray cmdPacket(quint16 cmd, const char *data, int size) {
Q_ASSERT(size <= 16);
QByteArray result(24, '\0');
QDataStream s(&result, QIODevice::WriteOnly);
s.setByteOrder(QDataStream::LittleEndian);
s << quint16(0xAA55) << cmd << quint16(size);
s.writeRawData(data, size);
s.skipRawData(22 - s.device()->pos());
quint16 sum = 0;
for (int i = 0; i < 22; ++i)
sum += result[i];
s << sum;
qDebug() << result.toHex();
return result;
}
QByteArray cmdPacket(quint16 cmd, const QByteArray& data) {
return cmdPacket(cmd, data.data(), data.size());
}
The command packet to turn the sensor led on/off can be obtained as follows:
QByteArray cmdSensorLed(bool on) {
char data[2] = {'\0', '\0'};
if (on) data[0] = 1;
return cmdPacket(0x124, data, sizeof(data));
}

If I reuse a QProcess variable, can there be leftover data in the stdout/stderr channels?

I have the following scenario:
QProcess*p;
// later
p->start();
//later
p->terminate(); // there might be unread data in stdout
//later
p->start();
I read the process stdout. After I call p->start() the second time, could there still be unread data left in the stdout buffers from the first p->start()? That would be a problem for me. Do I need to flush the buffers or something?
Okay, I've checked the sources. The QProcess::start() method explicitly clears both output buffers, so it should be okay, at least in this sense:
void QProcess::start(const QString &program, const QStringList &arguments, OpenMode mode)
{
Q_D(QProcess);
if (d->processState != NotRunning) {
qWarning("QProcess::start: Process is already running");
return;
}
#if defined QPROCESS_DEBUG
qDebug() << "QProcess::start(" << program << "," << arguments << "," << mode << ")";
#endif
d->outputReadBuffer.clear();
d->errorReadBuffer.clear();
I still think it's a bad style to reuse the same object, though.

Resources