我正在尝试在SDL2中播放纯正弦波,但是我发现似乎无法获得完全纯净的音调。它听起来很接近真实的正弦波,但是后面有一个轻微的次级频率,听起来更接近方波。我已经记录了声音,并验证了在两个不同系统上通过两组扬声器播放时的确不正确(与纯正弦波相比)
在这一点上,我已经尝试了很多事情,包括从堆栈溢出中实现多个正弦波,并尝试改编Handmade Hero中的代码。但是每次都会出现同样的问题。我的怀疑是位精度有问题,某个地方的转换不正确,或者与SDL音频工作的特定方式有关,我无法正确导航
这是我目前正在使用的主要音频回调函数,以及最近一次尝试将正弦波写入缓冲区的操作:
#define Pi32 3.14159265359f
#define Tau32 (2.0f * Pi32)
void
AudioCallback(void* UserData, u8* Stream, int Length)
{
audio_user_data* AudioUserData = (audio_user_data*)UserData;
static u32 Count = 0;
u16* SampleBuffer = (u16*)Stream;
int SamplesToWrite = Length / AudioUserData->BytesPerSample;
for(int SampleIndex = 0; SampleIndex < SamplesToWrite; SampleIndex++)
{
u16 ToneValue = round((AudioUserData->ToneVolume * sin(Tau32 * (f32)Count / (f32)AudioUserData->WavePeriod)));
*SampleBuffer++ = ToneValue;
*SampleBuffer++ = ToneValue;
++Count;
}
}
如果有帮助,我很乐意提供更多背景信息
编辑-其他上下文:
#include "x:\SDL2-2.0.10\include\SDL.h"
#define Pi32 3.14159265359f
#define Tau32 (2.0f * Pi32)
#define INITIAL_SCREEN_WIDTH (8*80)
#define INITIAL_SCREEN_HEIGHT (8*60)
typedef struct audio_user_data audio_user_data;
struct audio_user_data
{
int SamplesPerSecond;
int BytesPerSample;
int SampleIndex;
int ToneHz;
int ToneVolume;
int WavePeriod;
u32 FileLength;
u16* BufferLocation;
};
void
AudioCallback(void* UserData, u8* Stream, int Length)
{
audio_user_data* AudioUserData = (audio_user_data*)UserData;
static u32 Count = 0;
u16* SampleBuffer = (u16*)Stream;
int SamplesToWrite = Length / AudioUserData->BytesPerSample;
for(int SampleIndex = 0; SampleIndex < SamplesToWrite; SampleIndex++)
{
u16 ToneValue = (0.5f + (AudioUserData->ToneVolume * sin(Tau32 * Count / AudioUserData->WavePeriod)));
*SampleBuffer++ = ToneValue;
*SampleBuffer++ = ToneValue;
++Count;
}
}
int
main(int argc, char* argv[])
{
SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO);
SDL_Window* Window = SDL_CreateWindow("Spell Checker", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, INITIAL_SCREEN_WIDTH*2, INITIAL_SCREEN_HEIGHT*2, 0);
SDL_Renderer* Renderer = SDL_CreateRenderer(Window, 0, SDL_RENDERER_SOFTWARE);
SDL_PixelFormat* Format = SDL_AllocFormat(SDL_PIXELFORMAT_RGB888);
SDL_Texture* Screen = SDL_CreateTexture(Renderer, Format->format, SDL_TEXTUREACCESS_STREAMING, INITIAL_SCREEN_WIDTH, INITIAL_SCREEN_HEIGHT);
audio_user_data AudioUserData = {0};
AudioUserData.SamplesPerSecond = 44100;
AudioUserData.BytesPerSample = 2 * sizeof(int16);
AudioUserData.SampleIndex = 0;
AudioUserData.ToneVolume = 3000;
AudioUserData.ToneHz = 440;
AudioUserData.WavePeriod = AudioUserData.SamplesPerSecond / AudioUserData.ToneHz;
SDL_AudioSpec Want, Have;
SDL_AudioDeviceID AudioDeviceID;
Want.freq = AudioUserData.SamplesPerSecond;
Want.format = AUDIO_S16;
Want.channels = 2;
Want.samples = 4096;
Want.callback = &AudioCallback;
Want.userdata = &AudioUserData;
AudioDeviceID = SDL_OpenAudioDevice(0, 0, &Want, &Have, 0);
SDL_PauseAudioDevice(AudioDeviceID, 0); // Start playing
u32* PixelMap = calloc(INITIAL_SCREEN_WIDTH * INITIAL_SCREEN_HEIGHT, sizeof(PixelMap));
int PixelMapLocation = 0;
int Running = 1;
while(Running)
{
SDL_Event Event;
while(SDL_PollEvent(&Event))
{
if(Event.type == SDL_QUIT)
{
Running = 0;
break;
}
}
// Test colors
PixelMapLocation = 0;
for(int Row = 0; Row < INITIAL_SCREEN_WIDTH; ++Row)
{
for(int Col = 0; Col < INITIAL_SCREEN_HEIGHT; ++Col)
{
PixelMap[PixelMapLocation++] = 0xFF00FF;
}
}
for(int Row = 0; Row < INITIAL_SCREEN_WIDTH; ++Row)
{
for(int Col = 0; Col < INITIAL_SCREEN_HEIGHT; ++Col)
{
PixelMap[PixelMapLocation++] = 0x00FFFF;
}
}
SDL_UpdateTexture(Screen, 0, PixelMap, INITIAL_SCREEN_WIDTH * sizeof(PixelMap));
SDL_RenderClear(Renderer);
SDL_RenderCopy(Renderer, Screen, 0, 0);
SDL_RenderPresent(Renderer);
}
return(0);
}
EDIT2: 我录制了我在这里听到的音频(可能需要调高音量才能听到问题): https://www.youtube.com/watch?v=-V2IMhK2Zis&feature=youtu.be
我还运行了一个时序测试,并在每次AudioCallback函数运行时将其取回: https://imgur.com/a/9pqCte0
EDIT3: 示波器读数-
(我看不到明显的差异,但是也许其他人可以看到吗?)编辑:哦,等等,在示波器的左侧,两个波形之间有明显的差异(尽管它们没有出现在主要阅读)。试图找出问题所在–由于我尝试了几种不同的算法,目前我仍不确定
EDIT4: 这是一张想要/必须显示在调用SDL_OpenAudioDevice之后的所有内容(大小除外)都相同的图片:
EDIT5: 问题(某种)已经解决!将AudioUserData.SamplesPerSecond设置为48000会产生纯正弦的正弦波。但是问题仍然存在:为什么它只能在48000下工作?