2011-10-06 72 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

我一直在尋找這樣的東西永遠。謝謝! –