c++ - 在C++上使用QueueAudio时声音播放不起作用

标签 c++ audio sdl-2

我正在尝试通过使用C++上的音频队列来使用SDL2播放正弦波声音。为此,我创建了一个“扬声器”类,该类具有一个pushBeep函数,每次需要发出蜂鸣声时都会调用该函数。我已经成功创建了AudioDevice,并且当我对设备执行QueueAudio时也成功了(我已经在调试器上检查了),但是似乎听不到任何声音。

我尝试以多种方式更改生成样本的方式,也正如我之前所说,我检查了设备是否已正确打开,并且QueueAudio返回0表示成功。

这是类

Speaker::Speaker()
{
    SDL_AudioSpec ds;
    ds.freq = Speaker::SPEAKER_FREQUENCY;
    ds.format = AUDIO_F32;
    ds.channels = 1;
    ds.samples = 4096;
    ds.callback = NULL;
    ds.userdata = this;

    SDL_AudioSpec os;
    this->dev = SDL_OpenAudioDevice(NULL, 0, &ds, &os, NULL);

    std::cout << "DEVICE: " << this->dev << std::endl;
    SDL_PauseAudioDevice(this->dev, 0);
}

Speaker::~Speaker()
{
    SDL_CloseAudioDevice(this->dev);
}

void Speaker::pushBeep(double freq, int duration) {
    int nSamples = duration * Speaker::SPEAKER_FREQUENCY / 1000;
    float* samples = new float[nSamples];
    double v = 0.0;
    for (int idx = 0; idx < nSamples; idx++) {
        //float value = (float)Speaker::SPEAKER_AMPLITUDE * std::sin(v * 2 * M_PI / Speaker::SPEAKER_FREQUENCY);
        float value = 440.0;
        samples[idx] = value;
        v += freq;
    }
    int a = SDL_QueueAudio(this->dev, (void*)samples, nSamples * sizeof(float));
    std::cout << a << std::endl;
    delete[] samples;
    samples = NULL;
}

这就是我所说的

Speaker s;
s.pushBeep(440.0, 1000);

当我尝试使用正弦波生成代码(注释)时,它给了我“精度 double float ”错误。当我使用固定值(未注释)时,它没有给出错误,但仍然无法正常工作。

我希望程序输出声音。

最佳答案

您缺少了几件事,或者也许您没有添加到代码段中。您没有指定音频回调,所以当您调用SDL_QueueAudio();时,我不知道该如何处理数据。并且您没有在延迟中调用SDL_PauseAudioDevice()。

#include <math.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_audio.h>
#include <iostream>

namespace AudioGen
{
const int AMPLITUDE = 1;
const int SAMPLE_RATE = 44000;

// Globals
float *in_buffer;
SDL_atomic_t callback_sample_pos;
SDL_Event event;
SDL_bool running = SDL_TRUE;

/**
 * Structure for holding audio metadata such as frequency
 */
struct AudioData
{
     int sampleNum;
     float frequency;
};

void audio_callback(void *user_data, Uint8 *raw_buffer, int bytes)
{
    float *buffer = (float*)raw_buffer;
    AudioData &audio_data(*static_cast<AudioData*>(user_data));
    int nSamples = bytes / 4; // For F32
    std::cout << nSamples << std::endl;
    for(int i = 0; i < nSamples; i++, audio_data.sampleNum++)
    {
        double time = (double)audio_data.sampleNum / (double)SAMPLE_RATE;
        buffer[i] = (float)(AMPLITUDE * sin(2.0f * M_PI * audio_data.frequency * time));
    }
}

int buffer_length;
void callback(void *user_data, Uint8 *raw_buffer, int bytes)
{
    float *buffer = (float*)raw_buffer;
    int nSamples = bytes/4;
    auto local_sample_pos = SDL_AtomicGet(&callback_sample_pos);
    for(int i = 0; i < nSamples; ++i)
    {
        // Stop running audio if all samples are finished playing
        if(buffer_length == local_sample_pos)
        {
            running = SDL_FALSE;
            break;
        }
        buffer[i] = in_buffer[local_sample_pos];
        ++local_sample_pos;
    }
    SDL_AtomicSet(&callback_sample_pos, local_sample_pos);
}

class Speaker
{
    public:
        Speaker()
        {
            SDL_Init(SDL_INIT_AUDIO);
            SDL_AudioSpec ds;
            ds.freq = SAMPLE_RATE;
            ds.format = AUDIO_F32;
            ds.channels = 1;
            ds.samples = 4096;
            ds.callback = callback;
            ds.userdata = &ad; // metadata for frequency

            SDL_AudioSpec os;
            dev = SDL_OpenAudioDevice(NULL, 0, &ds, &os, SDL_AUDIO_ALLOW_FORMAT_CHANGE);
        }

        ~Speaker()
        {
            SDL_CloseAudioDevice(dev);
            SDL_Quit();
        }
        void pushBeep(float frequency, int duration)
        {
            ad.frequency = frequency; // set the frequency for the beep
            SDL_PauseAudioDevice(dev, 0);
            SDL_Delay(duration); // wait while sound is playing
            SDL_PauseAudioDevice(dev, 1);
        }

        void pushBeep2(float frequency, int duration )
        {
            int nSamples = duration * SAMPLE_RATE / 1000;
            in_buffer = new float[nSamples];
            buffer_length = nSamples;
            for (int idx = 0; idx < nSamples; idx++) {
                double time = (double)idx / (double)SAMPLE_RATE;
                in_buffer[idx] = (float)(AMPLITUDE * std::sin(2.0f * M_PI * frequency * time));
            }
            SDL_QueueAudio(dev, in_buffer, nSamples * sizeof(float));
            SDL_PauseAudioDevice(dev, 0);
            while(running){
                while(SDL_PollEvent(&event)!=0);
            }
            delete[] in_buffer;
        }

    private:
        SDL_AudioDeviceID dev;
        AudioData ad;
        int sampleNum = 0;
};
} // End of namespace AudioGen

int main(int argc, char *argv[])
{
    AudioGen::Speaker speaker;
    //speaker.pushBeep(440, 1000);
    speaker.pushBeep2(440.0f, 1000);
    return 0;
}

关于c++ - 在C++上使用QueueAudio时声音播放不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57451187/

相关文章:

c++ - 重载构造函数中的成员初始化

java - 无法在我的网站中播放 .m4a 或 .3gpp 音频文件

iphone - AVAudioPlayer 帮助 : Playing multiple sounds simultaneously, 一次停止它们,并解决自动引用计数

static-linking - 跨平台静态链接 SDL2

audio - 如何修复SDL混合器 “Unsupported block alignment”错误?

c++ - 用 MKL 减去两个矩阵

c++ - 将静态方法作为参数传递,不需要地址运算符?

c++ - 当编译器从代码中取出所有空格和注释时,GCC 如何知道错误发生在哪一行?

ios - 在 iOS 中选择内置麦克风和耳机

c++ - 为什么转换 SDL Surface 在 Surface 从文件加载时有效,但在 SDL Surface 从字体文件生成时无效