C++ - Воспроизведение тона, сгенерированного из синусоидальной волны

Привет всем, я сейчас пытаюсь понять, как воспроизвести тон, который я сгенерировал, используя синусоидальную волну.

Вот мой код:

#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.

Я просто хочу простое воспроизведение тона, который я создал. У кого-нибудь есть что-нибудь, на что они могут мне указать?

Огромное спасибо!!!


person Moonlight293    schedule 29.03.2011    source источник


Ответы (3)


Я написал пример именно для этого. Отлично работает с OpenAL под MacOSX и воспроизводит плавные синусы. Посмотрите здесь: 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.

person zerm    schedule 29.03.2011
comment
Спасибо!! Это именно то, что мне было нужно :) - person Moonlight293; 30.03.2011
comment
Просто быстрый вопрос - для чего 32760 при изготовлении образцов? Огромное спасибо! - person Moonlight293; 06.04.2011
comment
@ Moonlight293: аудиоформат MONO16, т. е. 16 бит на сэмпл. сгенерированный синус является числом с плавающей запятой, таким образом, от -1 до 1. Чтобы отобразить его на 16 бит, то есть от -32767 до 32768, я умножаю это число. Чуть меньше просто для..хм..лени - person zerm; 06.04.2011
comment
У меня работает #include <AL/alut.h> вместо #include <OpenAL/al.h>. возможно ваш код устарел, - person Minimus Heximus; 08.09.2015
comment
также вместо функции sleep вы должны использовать alutSleep. sleep может не работать в некоторых ОС. - person Minimus Heximus; 08.09.2015
comment
и кажется, вы должны delete samples;. - person Minimus Heximus; 08.09.2015
comment
Также вы не удаляете буфер и ресурсы. Интересно, были ли upvoters знакомы с openal. - person Minimus Heximus; 10.09.2015

Вам нужно будет пройти через ОС, чтобы воспроизвести звуки. Это не так просто, как вы думаете. В OSX вам нужно будет пройти через CoreAudio.

Лучшим подходом было бы использование библиотеки-оболочки, такой как PortAudio (http://www.portaudio.com/), которая сделает ваш код более переносимым и избавит вас от некоторых шаблонов, необходимых для извлечения звука из вашей программы.

person Jean-Marc Pelletier    schedule 29.03.2011
comment
Это почти сработало, пока я не получил кучу ошибок связывания! Но я думаю, что это сделал мой собственный навык программирования, так что этот вариант тоже сработал. - person Moonlight293; 30.03.2011

Попробуйте это (эта программа использует концепцию преобразования Z, полный пример, который генерирует тоны DTMF с использованием ALSA И коммутилируемые на 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;
}
person Elvis Rock Code    schedule 23.09.2014
comment
Я тестировал никаких звуков. - person Minimus Heximus; 08.09.2015
comment
Эта версия просто генерирует значения, для полного DTMF перейдите по ссылке в описании. - person Elvis Rock Code; 21.09.2015