C++ - Play back a tone generated from a sinusoidal wave

前端 未结 3 1027
梦毁少年i
梦毁少年i 2021-01-01 01:37

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 

        
相关标签:
3条回答
  • 2021-01-01 02:10

    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.

    0 讨论(0)
  • 2021-01-01 02:12

    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

    0 讨论(0)
  • 2021-01-01 02:27

    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;
    }
    
    0 讨论(0)
提交回复
热议问题