【问题标题】:How to produce sound in C on Linux?如何在 Linux 上用 C 语言产生声音?
【发布时间】:2014-12-22 21:52:48
【问题描述】:

我需要一种在 Linux 上的 C 程序中播放某些音符的方法。 使用 Windows 时,可以#include <dos.h> 和使用直截了当的函数,如sound(note/frequency)delay(time in ms) 和自我解释nosound()。 Linux上有什么并行的吗? 谢谢

【问题讨论】:

  • ALSA tutorial required的可能重复
  • 链接的副本并没有真正回答问题。它只是链接到一堆教程。
  • 您可能对libao documentation 感兴趣。这将允许您播放 PCM 音频数据。如果你想要蜂鸣器般的声音就好了......
  • libsdl 也许?

标签: c linux audio


【解决方案1】:

我喜欢上面关于 libao 的提示 - 我刚刚试了一下,效果很好。这是使用 OpenAL 合成 PCM 格式的原始音频缓冲区然后渲染为音频的类似复杂程度

// sudo apt-get install libopenal-dev

// gcc -o openal_play_monday   openal_play_monday.c  -lopenal -lm

#include <stdio.h>
#include <stdlib.h>    // gives malloc
#include <math.h>


#ifdef __APPLE__
#include <OpenAL/al.h>
#include <OpenAL/alc.h>
#elif __linux
#include <AL/al.h>
#include <AL/alc.h>
#include <unistd.h>
#endif

ALCdevice  * openal_output_device;
ALCcontext * openal_output_context;

ALuint internal_buffer;
ALuint streaming_source[1];

int al_check_error(const char * given_label) {

    ALenum al_error;
    al_error = alGetError();

    if(AL_NO_ERROR != al_error) {

        printf("ERROR - %s  (%s)\n", alGetString(al_error), given_label);
        return al_error;
    }
    return 0;
}

void MM_init_al() {

    const char * defname = alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);

    openal_output_device  = alcOpenDevice(defname);
    openal_output_context = alcCreateContext(openal_output_device, NULL);
    alcMakeContextCurrent(openal_output_context);

    // setup buffer and source

    alGenBuffers(1, & internal_buffer);
    al_check_error("failed call to alGenBuffers");
}

void MM_exit_al() {

    ALenum errorCode = 0;

    // Stop the sources
    alSourceStopv(1, & streaming_source[0]);        //      streaming_source
    int ii;
    for (ii = 0; ii < 1; ++ii) {
        alSourcei(streaming_source[ii], AL_BUFFER, 0);
    }
    // Clean-up
    alDeleteSources(1, &streaming_source[0]);
    alDeleteBuffers(16, &streaming_source[0]);
    errorCode = alGetError();
    alcMakeContextCurrent(NULL);
    errorCode = alGetError();
    alcDestroyContext(openal_output_context);
    alcCloseDevice(openal_output_device);
}

void MM_render_one_buffer() {

    /* Fill buffer with Sine-Wave */
    // float freq = 440.f;
    float freq = 100.f;
    float incr_freq = 0.1f;

    int seconds = 4;
    // unsigned sample_rate = 22050;
    unsigned sample_rate = 44100;
    double my_pi = 3.14159;
    size_t buf_size = seconds * sample_rate;

    // allocate PCM audio buffer        
    short * samples = malloc(sizeof(short) * buf_size);

   printf("\nhere is freq %f\n", freq);
    int i=0;
    for(; i<buf_size; ++i) {
        samples[i] = 32760 * sin( (2.f * my_pi * freq)/sample_rate * i );

        freq += incr_freq;  //  change freq just to make things interesting

        if (100.0 > freq || freq > 5000.0) {

            incr_freq *= -1.0f;  // toggle direction of freq increment
        }
    }

    /* upload buffer to OpenAL */
    alBufferData( internal_buffer, AL_FORMAT_MONO16, samples, buf_size, sample_rate);
    al_check_error("populating alBufferData");

    free(samples);

    /* Set-up sound source and play buffer */
    // ALuint src = 0;
    // alGenSources(1, &src);
    // alSourcei(src, AL_BUFFER, internal_buffer);
    alGenSources(1, & streaming_source[0]);
    alSourcei(streaming_source[0], AL_BUFFER, internal_buffer);
    // alSourcePlay(src);
    alSourcePlay(streaming_source[0]);

    // ---------------------

    ALenum current_playing_state;
    alGetSourcei(streaming_source[0], AL_SOURCE_STATE, & current_playing_state);
    al_check_error("alGetSourcei AL_SOURCE_STATE");

    while (AL_PLAYING == current_playing_state) {

        printf("still playing ... so sleep\n");

        sleep(1);   // should use a thread sleep NOT sleep() for a more responsive finish

        alGetSourcei(streaming_source[0], AL_SOURCE_STATE, & current_playing_state);
        al_check_error("alGetSourcei AL_SOURCE_STATE");
    }

    printf("end of playing\n");

    /* Dealloc OpenAL */
    MM_exit_al();

}   //  MM_render_one_buffer

int main() {

    MM_init_al();

    MM_render_one_buffer();
}

如果您想进一步了解 OpenAL ... 看看这个

https://github.com/scottstensland/render-audio-openal

开箱即用的 OpenAL 可以很好地播放 PCM 音频的缓冲区……但是它留下了播放流的能力作为练习。在那个 github 存储库中,我使用 OpenAL 编写了一个音频服务器,它实现了播放流音频......享受

【讨论】:

  • alDeleteBuffers(16, &amp;streaming_source[0]); 行中的16 是什么?
  • 你想用缓冲区删除器删除源吗?
  • 请注意,新版本的 OpenAL 是专有的。
  • @martinkunev not true 请参阅stackoverflow.com/a/11200103/147175 中提到的开源 OpenAL github 存储库,即github.com/kcat/openal-soft
  • @ScottStensland github 存储库是从上一个开放版本(更名为 OpenAL Soft)分叉而来的。所以我说的是真的,只是不完整。
【解决方案2】:

Windows 使用它自己的唯一健全架构,因此您可以访问sound() 例程。

根据安装的软件包,不同的 linux 机器可能需要不同的方法。 也许实用程序beep(来自this question on stackexchange)可以引导您走向正确的方向

【讨论】:

  • 很好地调用了哔声实用程序。我从很久以前就记得它,但这实际上是一个好点 - 看看其他实用程序。我确实想知道有多少人仍然拥有 PC 扬声器 - 甚至知道它们。当箱子停止供应时,我感到很困惑,您不得不单独购买一个,但它确实存在。
【解决方案3】:

一种方式

包括 #include&lt;conio.h&gt; 并在 main() 或您要使用的地方调用 print("\a")

printf("\a");

第二种方式

包括头文件

#include <windows.h>

和调用函数 Beep(500, 500);

Beep(freq, dur); 其中 freq = 蜂鸣频率,它是 int,dutation 也是 int

【讨论】:

  • 好吧。但问题是问题是关于 Linux 的。 Windows 方式不可移植。您的答案中第二个头文件的名称说明了一切。但是,是的,您说得对,这是在您所说的系统中解决问题的一种方法。
猜你喜欢
  • 2012-04-21
  • 2022-01-21
  • 2011-12-01
  • 2015-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-11
  • 2013-08-09
相关资源
最近更新 更多