ALSA : Sound aus einem Buffer über Timer-timeout ausgeben

Dein Thema passt einfach in kein Forum? Dann probiers mal hier.
Antworten
Martin_1961
Beiträge: 22
Registriert: 1. Juni 2011 13:23

ALSA : Sound aus einem Buffer über Timer-timeout ausgeben

Beitrag von Martin_1961 »

Hallo,
ich habe ein Audiobuffer, die ich in Timeout-event von einem Timer ausgeben will. siehe Code.

Es funktioniert auch alles prima. ABER.

wenn ich PlayAudioBuffer verwende, höre ich nur einmal den Buffer.
wenn ich PlayAudioBuffer2 verwende, höre ich den Buffer und zusätzlich rauschen und klicken und....
hat jemand eine Idee, wie man den Buffer abspielen kann, ohne jedes mal preapare aufrufen zu müssen ?


project

Code: Alles auswählen

#-------------------------------------------------
#
# Project created by QtCreator 2011-11-28T12:25:37
#  
#-------------------------------------------------

QT       += core

QT       -= gui

TARGET = Audio-Console-Alsa-01
CONFIG   += console
CONFIG   -= app_bundle
LIBS += -lasound

TEMPLATE = app


SOURCES += main.cpp
main.cpp

Code: Alles auswählen


#include <QtGui/QApplication>
#include "mainwindow.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    return a.exec();
}

audio.h

Code: Alles auswählen

#ifndef AUDIO_H
#define AUDIO_H
#include <alsa/asoundlib.h>

#include <QObject>

class audio : public QObject
{
    Q_OBJECT
public:
    explicit audio(QObject *parent = 0);
    int i;
    int err;
    short buf[128];
    snd_pcm_t *playback_handle;
    snd_pcm_hw_params_t *hw_params;

    int Open_audio(uint rate);
    void closeAudio(){snd_pcm_close (playback_handle);}
    int n;
signals:


public slots:

    void playAudioBuffer(short*buf);//,snd_pcm_t *playback_handle);
    void playAudioBuffer2(short*buf);//,snd_pcm_t *playback_handle);

};

#endif // AUDIO_H

audio.cpp

Code: Alles auswählen

#include "audio.h"
#include <QDebug>
//--------------------------------------------------------------------------------------
audio::audio(QObject *parent) :QObject(parent)
{n = 0;}


//--------------------------------------------------------------------------------------
void audio::playAudioBuffer(short*buf)//,snd_pcm_t *playback_handle)
{
    int err;
   if ((err = snd_pcm_writei (playback_handle, buf, 128)) != 128) {
       fprintf (stderr, "write to audio interface failed (%s)\n",snd_strerror (err));
                    Q_ASSERT(false);
    }
  qDebug()<<n++;
}
//--------------------------------------------------------------------------------------
void audio::playAudioBuffer2(short*buf)//,snd_pcm_t *playback_handle)
{
    int err;
    if ((err = snd_pcm_prepare (playback_handle)) < 0) {
            fprintf (stderr, "cannot prepare audio interface for use (%s)\n",
                     snd_strerror (err));
            Q_ASSERT(false);
    }
            if ((err = snd_pcm_writei (playback_handle, buf, 128)) != 128) {
                    fprintf (stderr, "write to audio interface failed (%s)\n",
                             snd_strerror (err));
                    Q_ASSERT(false);
            }

}

//--------------------------------------------------------------------------------------
int audio::Open_audio(uint rate)
{
    if ((err = snd_pcm_open (&playback_handle, "default", SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
        fprintf (stderr, "cannot open audio device  (%s)\n",snd_strerror (err));
        Q_ASSERT(false);
    }

    if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) {
        fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n",snd_strerror (err));
        Q_ASSERT(false);
    }

    if ((err = snd_pcm_hw_params_any (playback_handle, hw_params)) < 0) {
        fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n",snd_strerror (err));
        Q_ASSERT(false);
    }

    if ((err = snd_pcm_hw_params_set_access (playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
        fprintf (stderr, "cannot set access type (%s)\n",snd_strerror (err));
        Q_ASSERT(false);
    }

    if ((err = snd_pcm_hw_params_set_format (playback_handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) {
        fprintf (stderr, "cannot set sample format (%s)\n",snd_strerror (err));
        Q_ASSERT(false);
    }

    if ((err = snd_pcm_hw_params_set_rate_near (playback_handle, hw_params, &rate, 0)) < 0) {
        fprintf (stderr, "cannot set sample rate (%s)\n",snd_strerror (err));
        Q_ASSERT(false);
    }

    if ((err = snd_pcm_hw_params_set_channels (playback_handle, hw_params, 2)) < 0) {
        fprintf (stderr, "cannot set channel count (%s)\n",snd_strerror (err));
        Q_ASSERT(false);
    }

    if ((err = snd_pcm_hw_params (playback_handle, hw_params)) < 0) {
        fprintf (stderr, "cannot set parameters (%s)\n",snd_strerror (err));
        Q_ASSERT(false);
    }

    snd_pcm_hw_params_free (hw_params);

    if ((err = snd_pcm_prepare (playback_handle)) < 0) {
        fprintf (stderr, "cannot prepare audio interface for use (%s)\n",snd_strerror (err));
        Q_ASSERT(false);
    }

}

mainform.h

Code: Alles auswählen

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "audio.h"
#include <QMainWindow>

#include <QtGui>

namespace Ui {
    class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();
audio *myAudio;
QTimer *timer;
private:
    Ui::MainWindow *ui;
    QPushButton *button;

private slots:
    void timerTimeout();
    void StartStopTimer2();
signals:


};
mainwindow.cpp

Code: Alles auswählen

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QtGui>

int i = 0;

short *AudioBuffer;

MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent), ui(new Ui::MainWindow)
{
    ui->setupUi(this);

     myAudio = new audio(this);
     myAudio->Open_audio(8000);
     timer = new QTimer(this);
     timer->start(20);
     AudioBuffer= new short[128];
     memset(AudioBuffer,0xAA,128*sizeof(short));
     for(int i = 0;i<128;i++){
         //AudioBuffer[i] = 2048;//(short) (i * sin(i) * 100);
     }

     connect(timer,SIGNAL(timeout()),this,SLOT(timerTimeout()));
     button = new QPushButton("Timer 1", this);
     connect(button,SIGNAL(clicked()),this,SLOT(StartStopTimer2()));
}

MainWindow::~MainWindow()
{
    myAudio->closeAudio();
    delete[]AudioBuffer;
    delete ui;
}
void MainWindow::timerTimeout()
{
    myAudio->playAudioBuffer(AudioBuffer);
    qDebug()<<"timer : "<<i++;
}

void MainWindow::StartStopTimer2()
{
    if(timer->isActive()){
        timer->stop();
        button->setText("Timer 0");
    }
    else{
        timer->start(20);
        button->setText("Timer 1");
    }
}

#endif // MAINWINDOW_H
OS Ubuntu 11.04
Compiler QT 4.7.4
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Re: ALSA : Sound aus einem Buffer über Timer-timeout ausgebe

Beitrag von solarix »

Im Grunde ist ja ein Qt-Forum. ALSA-Fragen sind also nicht unbedingt unsere Spezialität :wink:

Da du die Frage hier stellst gehe ich davon aus, dass sonstige ALSA-Beispiele funktionieren. Nur in deinem Qt-Beispiel nicht...?

Ich habe keine Erfahrung in ALSA, aber wenn ich mit dieses Beispiel anschauen:

Code: Alles auswählen

    // http://equalarea.com/paul/alsa-audio.html#playex
    if ((err = snd_pcm_open (&playback_handle, argv[1], SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
      ...
    for (i = 0; i < 10; ++i) {
      if ((err = snd_pcm_writei (playback_handle, buf, 128)) != 128) {
        fprintf (stderr, "write to audio interface failed (%s)\n",
           snd_strerror (err));
        exit (1);
      }
    }
dann sieht das für mich nach einem Problem (für dich) aus. Offenbar ist "..writei(..)" blockierend (bis das Sample fertig abgespielt wurde). Für eine unterbrechungsfreie Wiedergabe wird daher PAUSENLOS (ohne irgend einen "sleep") geloopt. Für eine eventgetriebene GUI ist das so inkompatibel (die GUI braucht "Pausen" in der Eventloop, um die Events abzuarbeiten). Was das nun genau für ein Ergebnis mit dem 20ms-QTimer gibt.. keine Ahnung.

Lange Rede kurzer Sinn: für mich sieht das aus, als ob du dafür Threads brauchst...

[EDIT]
Eine kurze Suchanfrage bei Google ergab: http://www.linuxjournal.com/node/7391/print
[...] a program might be designed to carry audio data in one thread while another thread updates the program's GUI, and neither thread impacts the performance of the other [...]
Der Artikel ist von 2004.. falls sich seither nichts geändert hat, scheint meine Vermutung zu stimmen..

[EDIT2]
Und überleg dir eine Strategie bei der Namensgebung.. dein Code mit der zufälligen Gross/Kleinschreibung kann kein Mensch lesen.. :wink:
Und verzichte auf globale Variabeln..
Martin_1961
Beiträge: 22
Registriert: 1. Juni 2011 13:23

Re: ALSA : Sound aus einem Buffer über Timer-timeout ausgebe

Beitrag von Martin_1961 »

Danke Solarix.

Das Problem ist so spezifisch, dass es nicht möglich ist hier zu beschreiben. Du hast recht, Ich muss mich noch mehr in ALSA- Struktur einlesen.
habe hier versucht ein einfaches Lauffähiges Test-Programm zusammenzustellen.
Antworten