Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QAudioInput recording while serial data receive (signal-slot)



  • Hello! I'm using a Qtimer and QEventLoop for signal-slot connection to start and end audio recording with QAudioInput.

    QEventLoop event_loop(this);                 
    QTimer exit_timer(this);
    exit_timer.setSingleShot(true);               
    connect(&exit_timer, SIGNAL(timeout()), &event_loop, SLOT(quit())); 
    QString path = SAVE_AUDIO_PATH+filename.left( filename.lastIndexOf( '.' ) )+"_"+QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss");
    m_file.setFileName(path+".log");
    m_audio->StartRecording(path+".wav", record_time_sec);
    exit_timer.start((record_time_sec+4)*1000);
    event_loop.exec();
    

    While recording, I'm also receiving a data from microcontroller. How can I change a Signal-Slot connection to make recording while data (via serial/UART) will be received?


  • Qt Champions 2019

    @Fracture said in QAudioInput recording while serial data receive (signal-slot):

    I'm using a Qtimer and QEventLoop for signal-slot connection to start and end audio recording with QAudioInpu

    Why?
    Why not simply use asynchronous APIs properly?
    There is really no need for additional event loop.



  • Hmm, how did it works? Sorry I'm new in QT.
    for Example there are my Audio files,
    all files should have the same length, but something goes wrong:

    https://imgur.com/wHgdGaF

    My code is

    Measure.cpp

    // ************************************************************************************************
    // Measure-Class
    // ************************************************************************************************
    
    //class initialisation
    
    #include "Measure.h"
    #include "Conf.h"
    #include "Audio.h"
    
    // ************************************************************************************************
    Measure::Measure(Audio *audio)
    {
        //member variables init
        m_audio = audio;
    
        //UART-status debug
        if (0 == connectSerial())
        {
            qDebug() << "Serial connection OK!\n";
        }
        else
        {
            qDebug() << "Serial connection Error!\n";
            return;
        }
    
        auto info = QAudioDeviceInfo::availableDevices(QAudio::AudioInput);
        foreach (auto i, info) qDebug() << i.deviceName();
    
        //m_timer = new QTimer(this); double
    
        //set serial connection
        //connect(m_timer, SIGNAL(timeout()), this, SLOT(processMeas()),Qt::QueuedConnection);
    
        measure_cnt = 0;
    
        qDebug()<<"Starting programm";
    
    }
    
    // ************************************************************************************************
    // Start measure
    
    void Measure::start()
    {
        //QTimer *m_timer = new QTimer(this);
        //m_timer->setSingleShot(true);
        //m_timer->start(1000); 555
        processMeas();
    }
    
    // ************************************************************************************************
    // Serial connection initialization and signal-slot connection
    
    uint32_t Measure::connectSerial(void)
    {
    
        //serial connection configuration
        m_serial.setPortName("/dev/ttyACM0");
        m_serial.setBaudRate(QSerialPort::Baud115200);
        m_serial.setDataBits(QSerialPort::Data8);
        m_serial.setParity(QSerialPort::NoParity);
        m_serial.setStopBits(QSerialPort::OneStop);
        m_serial.setFlowControl(QSerialPort::NoFlowControl);
    
        if (!m_serial.open(QIODevice::ReadWrite))
            return 1;
    
        //einable serial connection
        connect(&m_serial, SIGNAL(readyRead()), this, SLOT(readRequest()));
    
        return 0;
    }
    
    // ************************************************************************************************
    // State maschine
    // ************************************************************************************************
    
    void Measure::processMeas()
    {
    
        // Declaration ************************************************************
        static uint32_t i = 0;
        static uint32_t j = 0;
    
        static uint8_t stm = 0;
    
        static uint16_t m1 = 0;
        static uint16_t m2 = 0;
        static uint16_t m3 = 0;
        static uint16_t m4 = 0;
        static uint16_t var;
    
        static QByteArray hextest;
    
        // Read config files ***********************************************************************************
        QDir directory("/home/nikitajarocky/workspace/QT/Software_2.0_QT/Config_files/");
        QStringList config_files = directory.entryList(QStringList() << "*.config", QDir::Files);
        config_files_cnt = config_files.count();
    
        foreach(QString filename, config_files)
        {
            Conf *conf = new Conf(directory.absoluteFilePath(filename));
            qDebug() << "Config file: " << filename << " is processed";
    
            // Error message *************************
            if(conf->getConf_lines().size() == 0)
            {
                qDebug()<<"Error conf file!!";
                return;
            }
            record_time_msec = 0;
        // Prepare measure ****************************************************************
            qDebug()<<"Debug: Prepare measure";
    
            QStringList lines = conf->getConf_lines(); //read all rows of config files
    
            record_time_100ms = lines.count()-9;
            record_time_msec = record_time_100ms * 100;
            QThread::msleep(4000);
            for(i=0; i < (uint32_t)lines.length(); i++) //prepare single rows of config files
            {
    
                //uint32_t j = 0;
                QString uart;
                QString uart_hex;
    
                if(i > 5 && i < lines.length())
                {
                QStringList speed_chunks = lines.at(i).split(","); //split rows by decimal point
    
                m1 = speed_chunks.at(2).toInt();
                m2 = speed_chunks.at(3).toInt();
                m3 = speed_chunks.at(4).toInt();
                m4 = speed_chunks.at(5).toInt();
    
                hextest.resize(10);
                hextest[0]=255;
                hextest[1]=m1>>8;
                hextest[2]=m1;
                hextest[3]=m2>>8;
                hextest[4]=m2;
                hextest[5]=m3>>8;
                hextest[6]=m3;
                hextest[7]=m4>>8;
                hextest[8]=m4;
                hextest[9]=238;
    
                qDebug()<< "Transfer data: " << i << " from " << lines.count()-1 << " rows transmitted";
                qDebug() << "Config file: " << filename << " is processed";
    
                m_serial.write(hextest);
                m_serial.waitForBytesWritten(30000);
                //QThread::usleep(50000);
    
                }//if(lines.at(i).contains(",")) end }//for end
            }//for end
    
    
                // Measurement ******************************************************************
                qDebug()<<"Debug: Measurement in progress";
                QEventLoop event_loop(this);                      //create method class QEventLoop
                QTimer exit_timer(this);                                //create method class QTimer
    
                exit_timer.setSingleShot(true);                     //set timer in mode singleShot
                connect(&exit_timer, SIGNAL(timeout()), &event_loop, SLOT(quit())); //connect exit timer to event loop slot
    
                QString path = SAVE_AUDIO_PATH+filename.left( filename.lastIndexOf( '.' ) )+"_"+QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss");
                m_file.setFileName(path+".log");
                //m_audio->StartRecording(path+".wav");
                m_audio->StartRecording(path+".wav", record_time_msec);
                //exit_timer.start(15000);
                exit_timer.start(record_time_msec+4000);//event loop timer durring measure time
                event_loop.exec();
    
                qDebug()<<"Measurement takes " << record_time_msec+4000 << " seconds";
    
                // Stop measure ************************************
    
                stm=0;
                measure_cnt++;
    
                // All configs files done *********************************
    
                if(measure_cnt>=config_files_cnt)
                {
                    qDebug()<<"All measure done";
                    qApp->quit();
                }
    
        }//foreach
    
    
    
    }//processMeas()
    
    // ************************************************************************************************
    // Data from STM32 receive
    
    void Measure::readRequest()
    {
        m_file.open(QIODevice::WriteOnly | QIODevice::Append);
        m_file.write(m_serial.readAll());
        m_file.close();
    }
    
    // ************************************************************************************************
    // save received data to log File
    
    void Measure::saveFile(QByteArray buffer)
    {
         m_file.write(buffer);
    }
    

    and Audio.cpp

    // ************************************************************************************************
    // Audio-Class
    // ************************************************************************************************
    
    #include "Audio.h"
    #include "Measure.h"
    #include <QAudioInput>
    #include <QTimer>
    
    // ************************************************************************************************
    
    Audio::Audio()
    {
        QTimer *m_timer = new QTimer(this);
        m_timer->setSingleShot(true);
        AudioRecord();
    }
    
    // ************************************************************************************************
    //Initialization and signal-slot connection
    
    void Audio::AudioRecord()
    {
        //Set audio configuration
        QAudioFormat format;
        format.setSampleRate(44100);
        format.setChannelCount(1);
        format.setSampleSize(16);
        format.setCodec("audio/PCM");
        format.setByteOrder(QAudioFormat::LittleEndian);
        format.setSampleType(QAudioFormat::SignedInt);
    
    
        //Wrong configuration detection
        QAudioDeviceInfo info = QAudioDeviceInfo::defaultInputDevice();
        if (!info.isFormatSupported(format))
        {
            qWarning() << "Default format not supported";
            format = info.nearestFormat(format);
        }
    
        //Signal-slot connection to show actual Audio state or errors output
        m_audio = new QAudioInput(format, this);
        connect(m_audio, SIGNAL(stateChanged(QAudio::State)), this, SLOT(handleStateChanged(QAudio::State)));
    }
    
    // ************************************************************************************************
    //Start recording
    
    //void Audio::StartRecording(QString rec_file_path)
    void Audio::StartRecording(QString rec_file_path, quint32 record_time_sec)
    {
        m_file.setFileName(rec_file_path); //audio recording path format
        m_file.open(QIODevice::WriteOnly); //audio access mode initialisation
    
        writeHeader(); //writing header to convert PCM to *.wav (Step 1)
    
        m_audio->start(&m_file); //start recording
    
        //QTimer::singleShot((15000), this, SLOT(StopRecording()));
        QTimer::singleShot((record_time_sec+4000), this, SLOT(StopRecording()));
        QCoreApplication::processEvents();
    
    
        qDebug()<< m_audio->format();
        //qDebug()<< m_file.open();
        QAudioDeviceInfo::defaultInputDevice();
        QAudioDeviceInfo::availableDevices(QAudio::AudioInput);
        //qDebug()<< m_audio->error();
        //qDebug()<< m_audio->notifyInterval();
    }
    
    
    // ************************************************************************************************
    //Write Header
    // ************************************************************************************************
    
    void Audio::writeHeader(){
    
        quint64 data64 = 0;
        quint32 data_Filesize_fill = 0;
        quint32 data_lenght = 16;
        quint16 data_PCM = 1;
        quint16 data_Chanel = 1;
        quint32 data_SamplRate = 44100;
        quint32 data_Value = (44100 * 16 * 1)/8;
        quint16 data_mono = (16 * 1)/8;
        quint16 data_BPS = 16;
        quint32 data_FileSize = 44;
    
    
    
        m_file.write("RIFF",4);
        m_file.write((char*)&data_Filesize_fill, 4);
        m_file.write("WAVE",4);
        m_file.write("fmt ",4);                     // "fmt " chunk size (always 16 for PCM)
        m_file.write((char*)&data_lenght, 4);
        m_file.write((char*)&data_PCM, 2);
        m_file.write((char*)&data_Chanel, 2);
        m_file.write((char*)&data_SamplRate, 4);
        m_file.write((char*)&data_Value, 4);        // bytes per second
        m_file.write((char*)&data_mono, 2);         // Block align
        m_file.write((char*)&data_BPS, 2);          // Bits per sample
        m_file.write("data",4);
        m_file.write((char*)&data_FileSize, 4);
    
        m_file.flush();
    }
    
    // ************************************************************************************************
    //Stop recording
    
    void Audio::StopRecording()
    {
        m_audio->stop();
        qDebug() << "stop";
        writeHeaderFinal();
        m_file.close();
        qDebug() << "close";
    }
    
    // ************************************************************************************************
    //Write Header
    void Audio::writeHeaderFinal(){
    
        quint32 data_Filesize_fill_after = m_file.size() - 8;
        quint32 data_FileSize_after = m_file.size() - 44;
        m_file.seek(4);
        m_file.write((char*)&data_Filesize_fill_after, 4);
        m_file.seek(40);
        m_file.write((char*)&data_FileSize_after, 4);
    }
    // ************************************************************************************************
    //Recording DEBUG output
    
    void Audio::handleStateChanged(QAudio::State newState)
    {
        switch (newState)
        {
            case QAudio::StoppedState:
                if (m_audio->error() != QAudio::NoError)
                {
                    qDebug() << "Error audio recording!!";
                } else
                {
                    qDebug() << "Finished audio recording";
                }
                break;
    
            case QAudio::ActiveState:
                qDebug() << "Started audio recording";
                break;
    
            default:
    
                break;
        }
    }
    
    // ************************************************************************************************
    

    I have multiple config-Files with value of lines for example 300, for every line should be 100ms recording, so 300 lines = 30sek (except 2 sec on beginning and 2 sek on the end - see 2kHz lines in spectrogram), but anytime i get different length of recording . And important is - that the values that I get from microcontroller should by synchronous witch audio-data recordings between 2kHz peaks!
    Do you see what is wrong, or what do you will to change?


  • Qt Champions 2019

    @Fracture said in QAudioInput recording while serial data receive (signal-slot):

    Audio::Audio()
    {
    QTimer *m_timer = new QTimer(this);
    m_timer->setSingleShot(true);

    What is this m_timer used for? You do not connect any slot to it.



  • Oh, it was old connection - in

    void Measure::start()
    {
        //QTimer *m_timer = new QTimer(this);
        //m_timer->setSingleShot(true);
        //m_timer->start(1000); 555
        processMeas();
    }
    

    Sorry, I don't clean my code

    It's also not all cpp-files what I use - i have also conf.cpp, control.cpp and main.cpp - tell me please when you want to see this!

    P.S. But m_timer was not a reason. It just trash part of code...


Log in to reply