【问题标题】:C++ - Play back a tone generated from a sinusoidal waveC ++ - 播放从正弦波产生的音调
【发布时间】:2011-07-25 01:14:21
【问题描述】:

大家好,我目前正试图弄清楚如何播放我使用正弦波生成的音调。

这是我的代码:

#include <iostream>
#include <OpenAL/al.h>
#include <OpenAL/alc.h>
#include <Math.h>

using namespace std;

int main (int argc, char * const argv[]) {

    int number = 0;
    int i, size;
    double const Pi=4*atan(1); 
    cout << "Enter number of seconds:" << endl;
    scanf("%d", &number);
    size = 44100*number;
    unsigned char buffer [size]; //buffer array

    for(i = 0; i < size; i++){
        buffer[i] = (char)sin((2*Pi*440)/(44100*i))*127;
    }

    return 0;
}

显然它目前什么也没做,因为我不知道如何播放缓冲区。 我不想生成一个wav文件,也不想加载一个。我只想播放我生成的缓冲区。

我目前正在使用 Mac OS X,并尝试使用 OpenAL 方法 - 但是我发现 alut 和 alu 不再是其中的一部分,如果我尝试使用它,那么事实证明它无论如何都已被废弃。 我也尝试包含 QAudioOutput,但由于某种原因,它似乎不在我的 Mac 上的任何位置。

我只想简单地播放我创建的音调。有没有人有什么可以指点我的?

谢谢大家!!!

【问题讨论】:

    标签: c++ audio generator wave trigonometry


    【解决方案1】:

    您需要通过操作系统才能播放声音。它并不像你想象的那么简单。在 OSX 中,您需要通过 CoreAudio。

    更好的方法是使用像 PortAudio (http://www.portaudio.com/) 这样的包装库,这将使您的代码更具可移植性,并为您节省一些从程序中获取声音所需的样板文件。

    【讨论】:

    • 这几乎奏效了,直到我遇到一堆链接错误!但我认为这是我自己的编程技能,所以这个选项也很有效。
    【解决方案2】:

    我已经为此编写了一个示例。在 MacOSX 下使用 OpenAL 运行良好并播放平滑的正弦波。看看这里: http://ioctl.eu/blog/2011/03/16/openal-sine-synth/

    代码很短,为了完整起见,我想我也可以在这里添加:

    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <iostream>
    #include <OpenAL/al.h>
    #include <OpenAL/alc.h>
    
    #define CASE_RETURN(err) case (err): return "##err"
    const char* al_err_str(ALenum err) {
        switch(err) {
            CASE_RETURN(AL_NO_ERROR);
            CASE_RETURN(AL_INVALID_NAME);
            CASE_RETURN(AL_INVALID_ENUM);
            CASE_RETURN(AL_INVALID_VALUE);
            CASE_RETURN(AL_INVALID_OPERATION);
            CASE_RETURN(AL_OUT_OF_MEMORY);
        }
        return "unknown";
    }
    #undef CASE_RETURN
    
    #define __al_check_error(file,line) \
        do { \
            ALenum err = alGetError(); \
            for(; err!=AL_NO_ERROR; err=alGetError()) { \
                std::cerr << "AL Error " << al_err_str(err) << " at " << file << ":" << line << std::endl; \
            } \
        }while(0)
    
    #define al_check_error() \
        __al_check_error(__FILE__, __LINE__)
    
    
    void init_al() {
        ALCdevice *dev = NULL;
        ALCcontext *ctx = NULL;
    
        const char *defname = alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
        std::cout << "Default device: " << defname << std::endl;
    
        dev = alcOpenDevice(defname);
        ctx = alcCreateContext(dev, NULL);
        alcMakeContextCurrent(ctx);
    }
    
    void exit_al() {
        ALCdevice *dev = NULL;
        ALCcontext *ctx = NULL;
        ctx = alcGetCurrentContext();
        dev = alcGetContextsDevice(ctx);
    
        alcMakeContextCurrent(NULL);
        alcDestroyContext(ctx);
        alcCloseDevice(dev);
    }
    
    int main(int argc, char* argv[]) {
        /* initialize OpenAL */
        init_al();
    
        /* Create buffer to store samples */
        ALuint buf;
        alGenBuffers(1, &buf);
        al_check_error();
    
        /* Fill buffer with Sine-Wave */
        float freq = 440.f;
        int seconds = 4;
        unsigned sample_rate = 22050;
        size_t buf_size = seconds * sample_rate;
    
        short *samples;
        samples = new short[buf_size];
        for(int i=0; i<buf_size; ++i) {
            samples[i] = 32760 * sin( (2.f*float(M_PI)*freq)/sample_rate * i );
        }
    
        /* Download buffer to OpenAL */
        alBufferData(buf, AL_FORMAT_MONO16, samples, buf_size, sample_rate);
        al_check_error();
    
    
        /* Set-up sound source and play buffer */
        ALuint src = 0;
        alGenSources(1, &src);
        alSourcei(src, AL_BUFFER, buf);
        alSourcePlay(src);
    
        /* While sound is playing, sleep */
        al_check_error();
        sleep(seconds);
    
        /* Dealloc OpenAL */
        exit_al();
        al_check_error();
        return 0;
    }
    

    更新:我发现 OpenAL 对我的需求有点限制,比如我在低延迟播放方面遇到了一些问题,因为这似乎不是 OpenAL 的主要域。相反,我发现了非常有说服力的 PortAudio:http://www.portaudio.com/ 它支持所有主要平台(Mac、Win、Unix/ALSA)并且看起来非常好。有一个正弦播放的例子,它要复杂得多,但也很简单。只需下载最新版本并在 test/patest_sine.c 中找到正弦播放示例

    【讨论】:

    • 谢谢!!这正是我需要的:)
    • 只是一个简单的问题 - 制作样品时 32760 是做什么用的?谢谢大家!
    • @Moonlight293:音频格式为 MONO16,即每个样本 16 位。生成的正弦是浮点数,因此从 -1 到 1。要将其映射到 16 位,即从 -32767 到 32768,我乘以该数字。少一点只是为了..嗯..懒惰
    • 对我来说 #include &lt;AL/alut.h&gt; 可以代替 #include &lt;OpenAL/al.h&gt;。可能你的代码已经过时了,
    • 你也应该使用alutSleep而不是sleep函数。 sleep 可能不适用于某些操作系统。
    【解决方案3】:

    试试这个(这个程序使用Z transform concept,一个使用ALSA生成dtmf音调的完整示例,可以在LINUX上编译here)‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌:

    /*
     *  Cosine Samples Generator
     *
     *  Autor: Volnei Klehm
     *  Data: 04/01/2014
     */
    
    #include <math.h>
    #include <stdio.h>
    
    #define S_FREQ 8000 /*Sample frequency, should be greater thar 2*sineFrequency
              If using audio output it has to be the same saple frequency 
              Used there*/
    
    const float frequency_in_Hertz = 697; /*set output frequency*/
    const float generatorContant1 = cosf(2*M_PI*(frequency_in_Hertz/S_FREQ));
    const float generatorContant2 = sinf(2*M_PI*(frequency_in_Hertz/S_FREQ));
    
    
    float GenerateSignal(){
      static float Register[2]={1,0};
      static float FeedBack;
    
      FeedBack=2*generatorContant1*Register[0]-Register[1];
      Register[1]=Register[0];  
      Register[0]=FeedBack;
    
      return (generatorContant2*Register[1]);
    }
    
    
    int main(void) {
      /*generate 300 samples*/
      for (int NumberOfSamples = 300; NumberOfSamples > 0; NumberOfSamples--) 
        printf("\n%f", GenerateSignal());
      return 0;
    }
    

    【讨论】:

    • 我测试没有发出声音。
    • 这个版本只生成值,完整的 DTMF 请点击描述上的链接。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-28
    • 2013-01-06
    • 2020-05-03
    • 2013-04-22
    • 1970-01-01
    相关资源
    最近更新 更多