2011-10-06 146 views
9

如何在C/C++中生成特定频率的声音?我运行Ubuntu 10.04并使用gcc。 TurboC for Windows上有一个void sound(int frequency)函数。有没有相当于gcc的?在ubuntu中使用gcc生成特定频率的声音?

+0

'sox'应该寻找一个字,因为它是在Linux上发出声音的方式。来自Wikipedia:“在类Unix系统中,SoX(作为播放命令)通常作为系统音频文件播放器提供。” – heltonbiker

+0

由于这种东西远远超出了当前的ISO C/C++标准范围,因此投票结束为工具rec,所以归结为“哪个库可以使用”。 SDL版本:http://stackoverflow.com/questions/10110905/simple-wave-generator-with-sdl-in-c –

回答

11

下面是利用PortAudio库生成给定频率的方形音频波的代码。 在Linux上编译时使用gcc buzzer.c -o buzzer -lportaudio。对于Windows也应该编译好。我不知道sound(int frequency)的行为如何,但下面应该能够模拟旧式蜂鸣器的任何用法。您可能需要一个portaudio-devel(或Ubuntu,portaudio-dev?的等效包),并且对于Pulse Audio,您可能需要一些更新版本的PortAudio,它位于您的回购站中。编译它不是一个问题。您可以根据WTFPL许可证的条款使用以下代码。 :-)(它是从一个PortAudio例如衍生)

#include <stdio.h> 
#include <math.h> 
#include "portaudio.h" 
#include <stdint.h> 
#include <unistd.h> // for usleep() 

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

typedef struct 
{ 
    uint32_t total_count; 
    uint32_t up_count; 

    uint32_t counter; 
    uint32_t prev_freq; 
    uint32_t freq; 
} paTestData; 

//volatile int freq = 0; 

/* This routine will be called by the PortAudio engine when audio is needed. 
** It may called at interrupt level on some machines so don't do anything 
** that could mess up the system like calling malloc() or free(). 
*/ 
static int patestCallback(const void *inputBuffer, void *outputBuffer, 
          unsigned long framesPerBuffer, 
          const PaStreamCallbackTimeInfo* timeInfo, 
          PaStreamCallbackFlags statusFlags, 
          void *userData) 
{ 
    paTestData *data = (paTestData*)userData; 
    uint8_t *out = (uint8_t*)outputBuffer; 
    unsigned long i; 
    uint32_t freq = data->freq; 

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

    for(i=0; i<framesPerBuffer; i++) 
    { 
     if(data->up_count > 0 && data->total_count == data->up_count) { 
      *out++ = 0x00; 
      continue; 
     } 
     data->total_count++; 

     if(freq != data->prev_freq) { 
      data->counter = 0; 
     } 

     if(freq) { 
      int overflow_max = SAMPLE_RATE/freq; 
      uint32_t data_cnt = data->counter % overflow_max; 
      if(data_cnt > overflow_max/2) 
       *out++ = 0xff; 
      else { 
       *out++ = 0x00; 
      } 
      data->counter++; 
     } 
     else { 
      data->counter = 0; 
      *out++ = 0; 
     } 
     data->prev_freq = freq; 
    } 

    return paContinue; 
} 

static PaStream *stream; 
static paTestData data; 


void buzzer_set_freq(int frequency) 
{ 
    data.up_count = 0; // do not stop! 
    data.freq = frequency; 
} 

void buzzer_beep(int frequency, int msecs) 
{ 
    data.total_count = 0; 
    data.up_count = SAMPLE_RATE * msecs/1000; 
    data.freq = frequency; 
} 

int buzzer_start(void) 
{ 
    PaStreamParameters outputParameters; 

    PaError err; 
    int i; 

    err = Pa_Initialize(); 
    if(err != paNoError) goto error; 

    outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */ 
    outputParameters.channelCount = 1;  /* stereo output */ 
    outputParameters.sampleFormat = paUInt8; /* 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,  /* we won't output out of range samples so don't bother clipping them */ 
     patestCallback, 
     &data); 
    if(err != paNoError) goto error; 

    err = Pa_StartStream(stream); 
    if(err != paNoError) goto error; 

    return err; 
error: 
    Pa_Terminate(); 
    fprintf(stderr, "An error occured while using the portaudio stream\n"); 
    fprintf(stderr, "Error number: %d\n", err); 
    fprintf(stderr, "Error message: %s\n", Pa_GetErrorText(err)); 
    return err; 

} 

int buzzer_stop() 
{ 
    PaError err = 0; 
    err = Pa_StopStream(stream); 
    if(err != paNoError) goto error; 

    err = Pa_CloseStream(stream); 
    if(err != paNoError) goto error; 

    Pa_Terminate(); 

    return err; 
error: 
    Pa_Terminate(); 
    fprintf(stderr, "An error occured while using the portaudio stream\n"); 
    fprintf(stderr, "Error number: %d\n", err); 
    fprintf(stderr, "Error message: %s\n", Pa_GetErrorText(err)); 
    return err; 
} 
void msleep(int d){ 
    usleep(d*1000); 
} 
int main(void) 
{ 

    // notes frequency chart: http://www.phy.mtu.edu/~suits/notefreqs.html 

    buzzer_start(); 
    buzzer_set_freq(261); 
    msleep(250); 
    buzzer_set_freq(293); 
    msleep(250); 
    buzzer_set_freq(329); 
    msleep(250); 
    buzzer_set_freq(349); 
    msleep(250); 
    buzzer_set_freq(392); 
    msleep(250); 
    buzzer_set_freq(440); 
    msleep(250); 
    buzzer_set_freq(494); 
    msleep(250); 
    buzzer_beep(523, 200); 
    msleep(250); 

    buzzer_stop(); 

    return 0; 
} 
+0

LOL在许可证。这是我第一次看到它。顺便说一句,很好的例子(有点长) –

+0

无论多久,它是准备使用,并马上工作无所谓 - 无需修复 – NickSoft

+0

我一直在寻找这样的东西永远。谢谢! –