audiooutput



  • hello again,
    i have found the audiooutput -example in the examples and want to understand the code but i'm not used to soundcards.As well i would like to change this small app in that way that I can output an intermittend tone.( tone ,pause,tone,pause and so on)
    Therefore I have created a sleeper in the .h file

    class Sleeper : public QThread
    {
    public:
        static void usleep(unsigned long usecs){QThread::usleep(usecs);}
        static void msleep(unsigned long msecs){QThread::msleep(msecs);}
        static void sleep(unsigned long secs){QThread::sleep(secs);}
    };
    

    next I have created a slider and connected its output to a variable:

    
    
       m_sleepSlider = new QSlider(Qt::Horizontal);
        connect(m_sleepSlider, SIGNAL(valueChanged(int)), this, SLOT(rpmChanged(int)));
        volumeBox->addWidget(m_volumeLabel);
        volumeBox->addWidget(m_volumeSlider);
         volumeBox->addWidget(m_sleepSlider);
    

    the slot:

    void AudioTest::rpmChanged(int value)
    {
        if (m_audioOutput)
            drehzahl=m_sleepSlider->value();
    }
    

    and now I want to create a for-loop that ihave a tone with 17 interupts.Where can I place this loop. Here it is not working:

    void Generator::generateData(const QAudioFormat &format, qint64 durationUs, int sampleRate)
    {for (int i=0;i>=17;i++){
        const int channelBytes = format.sampleSize() / 8;
        const int sampleBytes = format.channelCount() * channelBytes;
    
        qint64 length = (format.sampleRate() * format.channelCount() * (format.sampleSize() / 8))
                            * durationUs / 100000;
    
        Q_ASSERT(length % sampleBytes == 0);
        Q_UNUSED(sampleBytes) // suppress warning in release builds
    
        m_buffer.resize(length);
        unsigned char *ptr = reinterpret_cast<unsigned char *>(m_buffer.data());
        int sampleIndex = 0;
    
        while (length) {
    
    
            const qreal x = qSin(2 * M_PI * sampleRate * qreal(sampleIndex % format.sampleRate()) / format.sampleRate());
            for (int i=0; i<format.channelCount(); ++i) {
                if (format.sampleSize() == 8 && format.sampleType() == QAudioFormat::UnSignedInt) {
                    const quint8 value = static_cast<quint8>((1.0 + x) / 2 * 255);
                    *reinterpret_cast<quint8*>(ptr) = value;
                } else if (format.sampleSize() == 8 && format.sampleType() == QAudioFormat::SignedInt) {
                    const qint8 value = static_cast<qint8>(x * 127);
                    *reinterpret_cast<quint8*>(ptr) = value;
                } else if (format.sampleSize() == 16 && format.sampleType() == QAudioFormat::UnSignedInt) {
                    quint16 value = static_cast<quint16>((1.0 + x) / 2 * 65535);
                    if (format.byteOrder() == QAudioFormat::LittleEndian)
                        qToLittleEndian<quint16>(value, ptr);
                    else
                        qToBigEndian<quint16>(value, ptr);
                } else if (format.sampleSize() == 16 && format.sampleType() == QAudioFormat::SignedInt) {
                    qint16 value = static_cast<qint16>(x * 32767);
                    if (format.byteOrder() == QAudioFormat::LittleEndian)
                        qToLittleEndian<qint16>(value, ptr);
                    else
                        qToBigEndian<qint16>(value, ptr);
                }
                Sleeper::msleep(drehzahl);
                  }
    
                ptr += channelBytes;
                length -= channelBytes;
            }
            ++sampleIndex;
        }
    }
    

  • Lifetime Qt Champion

    Hi,

    The rpmChangedslot as written does nothing.

    Since you know the exact length of what you want to produce here, why not generate the full audio sample and then play it ?


  • Moderators

    @Leopold Instead of using a thread and a loop you could simply use a QTimer.



  • @Leopold said in audiooutput:

       }
            Sleeper::msleep(drehzahl);
              }
    

    the rpmChanged sets the variable "drehzahl" and so i want to change the length of the pauses.


  • Qt Champions 2017

    @Leopold

    If you sleep in the main thread of an event-driven program, then you most likely don't get the result you expect.

    Better use a QTimer as @jsulm suggested.



  • You are right,
    i have set a qtimer in genarateData now , but now the app does not start at all.
    And yes qtimer wouldbe much easier.I would like to build a metronom out of this example.But like i said i do not completely understand the code.There is no comment to the code.Where can i place the loop and the timer.If i have an example for one interrupt i think i can extent to what I want.Or does anybody know the code for a programmable metronom?


  • Moderators

    @Leopold You don't need any loop. Just set time out interval in QTimer correctly (to achieve needed frequency).



  • @jsulm ,
    hi, i do not think that I can solve it over the frequency.In the end state , i want to regulate the length of the pause and have an additional pause after 17 tones.Then I want the ability to set the anount of tones ( x instead of 17) and then regulate to which channel these tones will be output.
    for3 tones: tone,pause,tone,pause,tone,pause,pause and the same loop again.
    volume slider for volume,
    rpmslider for length of timer timer.start(rpmslider->volume(),this)
    tickslider for the amount of tones(x)



  • Nobody here who can explain the app?


  • Lifetime Qt Champion

    There are several possibilities. You can use a QTimer for the interval between two tones, increment a counter each time you play it up to 17 (or in your case the variable you'll use to be able to set the number you want). As for the tone itself, like I suggested before you can build a QByteArray containing the audio data you need to send and the send it to the output.

    As for channel selection, what do you have in mind ?



  • "As for channel selection, what do you have in mind ?"
    On one channel i want the sequenz with a doble pause after 17 tones and on the second channel (stereo) i want the sequenz with only tones and pauses.



  • @SGaist said in audiooutput:

    You can use a QTimer for the interval between two tones,

    this is what I want to to but i can not figure out where to set the loop. When I try to debug the programm it runs for ever in background but never reaches the return app.exec in main.


  • Lifetime Qt Champion

    The you have to build your stereo data accordingly.

    Start your QTimer when you want to start sending data or rather after you sent your first data to QAudioOutput.

    app.exec() will return either when you close the last window of your application or call QApplication::quit from e.g. a menu action.



  • now I had some time to play with this topic again:
    I'm still wondering where to set my loop.I did it here```

    void AudioTest::createAudioOutput()
    {
    delete m_audioOutput;
    m_audioOutput = 0;
    m_audioOutput = new QAudioOutput(m_device, m_format, this);
    m_generator->start();
    m_audioOutput->start(m_generator);
    for (int i=0;i<17;i++)
    {
    m_audioOutput->stop();
    connect(m_pushTimer, SIGNAL(timeout()), this, SLOT(update()));
    m_pushTimer->start(1000);

      m_audioOutput->start(m_generator);
    }
    
    qreal initialVolume = QAudio::convertVolume(m_audioOutput->volume(),
                                                QAudio::LinearVolumeScale,
                                                QAudio::LogarithmicVolumeScale);
    m_volumeSlider->setValue(qRound(initialVolume * 100));
    

    }
    I can compile but when it comes to running, i get a sigsev error from system.


  • Lifetime Qt Champion

    With that loop you are connecting the timeout signal 17 time, why ?

    You should also post your backtrace.



  • @SGaist said in audiooutput:

    With that loop you are connecting the timeout signal 17 time, why ?

    still the old problem, I want the rattling noise,then I'll continue to attapt the programm to my needs. I do not know where to place the loop.Could you have a look to the example programm and give me a hint?


  • Qt Champions 2017

    @Leopold why do you need a loop? please explain.

    you already have a timer and this timer call its SLOT every second. just do what you want there. if you want to stop, stop the timer.

    regards



  • @aha_1980
    have you read the complete thread?
    can you help, give me a hint!


  • Lifetime Qt Champion

    Did you try my suggestion of pre-generating the complete audio sequence ?



  • no, if i generate a wav file, I can not change sequenzes while running.I could play wav.files with other means.There are complete programs for metronoms they are too big and nearly not changeable.There must be a possibility to change this small program to my needs.When I had a first look to it i thought its easy but now its a challenge. I have set the loop to different places but always get a sigsev error when app starts.


  • Lifetime Qt Champion

    I didn't write about any file. I suggested that you create an array of data containing your sequence. Array that you'd update following the parameters you change.



  • I will think about that.Having sliders for changing tune, sequenze (loop) and duration of the gaps would have been more comfortable.


  • Lifetime Qt Champion

    When changing any of these parameters, you have to modify the generated data that you send to the audio output. So I don't see the problem there.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.