C++ - 播放正弦波产生的音调

发布于 2024-10-28 00:38:52 字数 868 浏览 5 评论 0原文

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

这是我的代码:

#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 上的任何位置。

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

谢谢各位!!!

Hey everyone, I'm currently trying to figure out how to play back a tone I have generated using a sinusoidal wave.

Here's my code:

#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;
}

Obviously it doesn't do anything at the moment, since I have no idea how to play the buffer.
I don't want to generate a wav file, nor do I want to load one in. I just want to play back the buffer I have generated.

I am currently working on Mac OS X, and have tried using OpenAL methods - however I have found that alut and alu are not part of it anymore and if I try to use it then it turns out that it's all depredated anyway.
I have also tried to include QAudioOutput, but for some reason it does not appear to be anywhere on my Mac.

I just want a simple playback of the tone I've created. Does anyone have anything they can point me to?

Thanks heaps!!!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

花心好男孩 2024-11-04 00:38:53

我为此专门写了一个例子。在 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 中找到正弦播放示例

I've written an example exactly for this. Runs fine with OpenAL under MacOSX and plays smooth sines. Take a look here:
http://ioctl.eu/blog/2011/03/16/openal-sine-synth/

Code is quite short, i guess i can add it here as well for sake of completeness:

#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;
}

Update: I've found OpenAL a bit too limiting for my needs, like I have some problems with low-latency playback as this appears to be not the primary domain of OpenAL. Instead, I've found the very convincing PortAudio: http://www.portaudio.com/
It supports all major platforms (Mac,Win,Unix/ALSA) and looks very good. There is an example for sine playback which is far more sophisticated, yet quite simple. Just download the latest release and find the sine-playback sample at test/patest_sine.c

浅紫色的梦幻 2024-11-04 00:38:53

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

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

You will need to go through the OS to play back sounds. It's not as straightforward as you would think. In OSX, you will need to go through CoreAudio.

A better approach would be to use a wrapper library like PortAudio (http://www.portaudio.com/) which will make your code more portable and save you some of the boilerplate needed to get sound out of your program.

辞别 2024-11-04 00:38:53

试试这个(这个程序使用 Z 变换概念,一个使用 ALSA 生成 dtmf 音调的完整示例并且可以在 LINUX 上编译此处)‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌:

/*
 *  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;
}

Try this (this program uses Z transform concept, a complete example that generates dtmf tones using ALSA and compilable on LINUX are available 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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文