2017-12-11 23 views
0

Ich habe eine klavierähnliche Anwendung, und wenn ich die Klaviertaste drücke, spielt sie einen Ton. In meiner App habe ich meinen eigenen Sinusgenerator geschrieben. App ist in Qt geschrieben. Ich denke, dass dieses Problem mit PortAudio ist, aber ich kann keine Lösung dafür finden.PortAudio: kurzes Rauschen am Anfang und am Ende des Sounds

ich für Sie aufgezeichnet haben, wie mein Problem klingt: https://vocaroo.com/i/s1yiWjaJffTU

Und hier ist mein Generator Klasse:

soundEngine.h

#ifndef SOUNDENGINE_H 
#define SOUNDENGINE_H 

#include <QThread> 
#include <math.h> 
#include "portaudio.h" 

#define SAMPLE_RATE (44100) 
#define FRAMES_PER_BUFFER (64) 
#define FREQUENCY 220 

#ifndef M_PI 
#define M_PI (3.14159265) 
#endif 

#define TABLE_SIZE (200) 

typedef struct 
{ 
    float sine[TABLE_SIZE]; 
    int phase; 
} 
paTestData; 

class SoundEngine : public QThread 
{ 
    Q_OBJECT 
public: 
    bool turnOFF; 
    void run(); 
    static int patestCallback(const void *inputBuffer, void *outputBuffer,unsigned long framesPerBuffer,const PaStreamCallbackTimeInfo* timeInfo,PaStreamCallbackFlags statusFlags,void *userData); 
    void generateSine(); 
    void removeSine(); 
private: 
    paTestData data; 
    PaStream *stream; 
    PaError err; 
    bool isPressed; 
}; 

#endif // SOUNDENGINE_H 

soundEngine.cpp

#include "soundengine.h" 
#include <QDebug> 

void SoundEngine::run() 
{ 
    PaStreamParameters outputParameters; 
    int i; 
    double t; 
    turnOFF = false; 
    isPressed = false; 

    static unsigned long n=0; 
    for(i=0; i<TABLE_SIZE; i++, n++) 
    { 
     t = (double)i/(double)SAMPLE_RATE; 
     data.sine[i] = 0; 
     //data.sine[i] = 0.3*sin(2 * M_PI * FREQUENCY * t); 
     /*data.sine[i] *= 1.0/2; 
     data.sine[i] += 0.5*sin(2 * M_PI * (FREQUENCY+110) * t); 
     data.sine[i] *= 2.0/3; 
     data.sine[i] += (1.0/3)*sin(2 * M_PI * (FREQUENCY+60) * t); 
     data.sine[i] *= 3.0/4; 
     data.sine[i] += (1.0/4)*sin(2 * M_PI * (FREQUENCY+160) * t);*/ 
    } 
    data.phase = 0; 

    err = Pa_Initialize(); 
    if(err != paNoError) qDebug()<<"Błąd przy inicjalizacji strumienia:"<<Pa_GetErrorText(err); 

    outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */ 
    if (outputParameters.device == paNoDevice) qDebug()<<"Błąd: Brak domyślnego urządzenia wyjścia!"; 

    outputParameters.channelCount = 2;  /* stereo output */ 
    outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */ 
    outputParameters.suggestedLatency = Pa_GetDeviceInfo(outputParameters.device)->defaultLowOutputLatency; 
    outputParameters.hostApiSpecificStreamInfo = NULL; 

    err = Pa_OpenStream(
       &stream, 
       NULL, /* no input */ 
       &outputParameters, 
       SAMPLE_RATE, 
       FRAMES_PER_BUFFER, 
       paClipOff,  /*paNoFlag we won't output out of range samples so don't bother clipping them */ 
       patestCallback, 
       &data); 
    if(err != paNoError) qDebug()<<"Błąd przy otwieraniu strumienia:"<<Pa_GetErrorText(err); 
    //err = Pa_StartStream(stream); 
    if(err != paNoError) qDebug()<<"Błąd przy starcie strumienia:"<<Pa_GetErrorText(err); 

    while (turnOFF == false) { 
     Pa_Sleep(500); 
    } 

    //err = Pa_StopStream(stream); 
    if(err != paNoError) qDebug()<<"Błąd przy zatrzymywaniu strumienia:"<<Pa_GetErrorText(err); 
    err = Pa_CloseStream(stream); 
    if(err != paNoError) qDebug()<<"Błąd przy zamykaniu strumienia:"<<Pa_GetErrorText(err); 
    Pa_Terminate(); 
} 

int SoundEngine::patestCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, void *userData) 
{ 
    paTestData *callData = (paTestData*)userData; 
    float *out = (float*)outputBuffer; 
    float sample; 
    unsigned long i; 

    (void) timeInfo; /* Prevent unused variable warnings. */ 
    (void) statusFlags; 
    (void) inputBuffer; 

    for(i=0; i<framesPerBuffer; i++) 
    { 
     sample = callData->sine[callData->phase++]; 
     *out++ = sample; /* left */ 
     *out++ = sample; /* right */ 
     if(callData->phase >= TABLE_SIZE) callData->phase -= TABLE_SIZE; 
    } 

    return paContinue; 
} 

void SoundEngine::generateSine() 
{ 
    if(isPressed == false) 
    { 
     for(int i=0; i<TABLE_SIZE; i++) 
     { 
      data.sine[i] += 0.3*sin(2 * M_PI * 440 * ((double)i/(double)SAMPLE_RATE)); 
     } 
     isPressed = true; 
     err = Pa_StartStream(stream); 
    } 
} 

void SoundEngine::removeSine() 
{ 
    err = Pa_StopStream(stream); 
    for(int i=0; i<TABLE_SIZE; i++) 
    { 
     data.sine[i] -= 0.3*sin(2 * M_PI * 440 * ((double)i/(double)SAMPLE_RATE)); 
    } 
    isPressed = false; 

} 

Wenn ich die Taste drücke, Funktion

void SoundEngine::generateSine() 

läuft - es erzeugt Sound. Wenn ich die Taste loslasse, entfernt die Methode

den Ton.

Antwort

1

MODERATOR ACHTUNG: Diese Frage scheint mehr zu dsp.stackexchange gehören als dieses Forum.

Es ist nichts falsch mit Ihrem Sound oder PortAudio. Der Klang, den Sie am Ende hören, ist nur das Ergebnis, wenn der Ton abrupt gestoppt wird. Sehen Sie sich das folgende Bild eines Klangs an, der über die gesamte Dauer eine konstante Amplitude aufweist. Dieser Ton wird am Ende einen hörbaren Knall haben.

Constant amplitude throughout the sound file

Umgekehrt, wenn man die Amplitude durch Modifizierung der Wellenform der Hüllkurve (der gleiche Ton wie in Bild # 1), so dass es ähnelt den Ton in Bild # 2, dämpfen wir keine abrupte Änderung hören (s) im Klang am Ende.

enter image description here

Zum Schluss, wenn Ihr Ziel ist, die Pops vollständig zu eliminieren, die Sie hören, fade out (oder Einblenden) Ihren Sound (s).

+1

Da es nicht wirklich die Wiedergabe von Audio ist, sondern eine einfache Sinuswellengenerierung, kann man einfach nicht sofort aufhören zu stoppen, sondern es zu stoppen, nächstes Mal, wenn die Amplitude Null ist. – dtech

+1

Das hilft nicht, da es einen sehr kurzen Zeitabstand zwischen einem Spitzenwert und einer Null gibt (tatsächlich gibt es 3 Nullen für jeden Zyklus), so dass Sie am Ende immer noch einen Pop hören. Die Lösung ändert die Umhüllung, wie ich erklärte. –

+1

Ja, Sie haben recht, ich dachte aus irgendeinem Grund viel tiefer als hörbare Frequenzen. Das Beenden eines Zyklus in solch hohen Frequenzen wird nicht mit dem abrupten Amplitudenabfall fertig werden. – dtech

Verwandte Themen