尝试使用 SDL 播放 WAV 但出现嗡嗡声
Trying to play a WAV with SDL but getting buzzing noise
我正在编写这个简单的程序来学习如何使用 SDL 处理音频。该程序打开一个 window,其中有一个按钮,上面写着开始,当您按下按钮时,它应该播放鼓样本的 WAV。没有错误,程序也没有崩溃,只是它没有播放鼓声,而是发出奇怪的嗡嗡声,直到您退出程序才停止。我认为这与音频回调函数有关,但我对此很陌生,所以我不确定它到底是如何工作的。
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
#include <SDL2/SDL_audio.h>
TTF_Font* font;
SDL_Color white = {255, 255, 255};
SDL_AudioSpec frmt;
bool run = true;
bool playing = false;
struct sample
{
Uint8 *data;
Uint32 dpos;
Uint32 dlen;
} sound;
bool buttonPress(int x, int y, SDL_Rect r)
{
if (x < (r.x + r.w) && x > r.x)
{
if (y < (r.y + r.h) && y > r.y)
{
return true;
}
}
return false;
}
void mixing(void *unused, Uint8 *stream, int len)
{
Uint32 amount;
if (playing)
{
amount = sound.dlen - sound.dpos;
if ( amount > len ) {
amount = len;
}
SDL_MixAudio(stream, &sound.data[sound.dpos], amount, SDL_MIX_MAXVOLUME);
sound.dpos += amount;
}
}
int main(int argc, char *argv[])
{
SDL_Init(SDL_INIT_EVERYTHING);
TTF_Init();
frmt.channels = 1;
frmt.format = AUDIO_S16;
frmt.freq = 22050;
frmt.samples = 512;
frmt.userdata = NULL;
frmt.callback = mixing;
int mX, mY;
Uint32 fpsTimer = SDL_GetTicks();
font = TTF_OpenFont("octaFont.TTF", 20);
SDL_Window* window = SDL_CreateWindow("Test", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 400, 200, 0);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
SDL_Surface* surface = TTF_RenderText_Solid(font, "Go!", white);
SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);
SDL_Rect button;
button.w = 50;
button.h = 35;
button.x = 10;
button.y = 10;
SDL_Rect bg;
bg.w = 400;
bg.h = 200;
bg.x = 0;
bg.y = 0;
SDL_Event e;
if (SDL_OpenAudio(&frmt, NULL) < 0)
{
fprintf(stderr, "Unable to open audio: %s\n", SDL_GetError());
return 1;
}
SDL_PauseAudio(0);
SDL_AudioSpec wave;
SDL_AudioCVT cvt;
Uint8 *data;
Uint32 dlen;
if (SDL_LoadWAV("sound.wav", &wave, &data, &dlen) == NULL)
{
fprintf(stderr, "Unable to load wave: %s\n", SDL_GetError());
return 1;
}
SDL_BuildAudioCVT(&cvt, wave.format, wave.channels, wave.freq, AUDIO_S16, 1, 22050);
cvt.buf = malloc(dlen*cvt.len_mult);
memcpy(cvt.buf, data, dlen);
cvt.len = dlen;
SDL_ConvertAudio(&cvt);
SDL_FreeWAV(data);
SDL_LockAudio();
free(sound.data);
sound.data = cvt.buf;
sound.dlen = cvt.len_cvt;
sound.dpos = 0;
SDL_UnlockAudio();
while (run)
{
while (SDL_PollEvent(&e))
{
switch (e.type)
{
case SDL_QUIT:
run = false;
break;
case SDL_KEYDOWN:
switch (e.key.keysym.sym)
{
case SDLK_SPACE:
playing = false;
break;
default:
break;
}
break;
case SDL_MOUSEBUTTONDOWN:
SDL_GetMouseState(&mX, &mY);
if (buttonPress(mX, mY, button))
{
playing = true;
}
break;
default:
break;
}
}
if (SDL_GetTicks() - fpsTimer >= 16)
{
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderFillRect(renderer, &bg);
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderDrawRect(renderer, &button);
SDL_RenderCopy(renderer, texture, NULL, &button);
SDL_RenderPresent(renderer);
fpsTimer = SDL_GetTicks();
}
}
SDL_CloseAudio();
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
TTF_Quit();
SDL_Quit();
return 0;
}
问题可能在于您正在使用 SDL_MixAudio
。
您的代码混入了 .wav
文件中的数据,但混入了什么?
stream
在调用SDL_MixAudio
之前是什么?
我得到同样的嗡嗡声,但是当我使用 memset
将 stream
缓冲区清零时 在 调用 SDL_MixAudio
之前,我得到来自 .wav
文件的正确声音。
我不确定,但我相信在对您的 mixing
函数的第二次和后续调用中,来自 prior 回调的数据仍在stream
缓冲区。
旁注:当.wav
数据播放完毕后,我们可以重置sound.dpos
重新播放文件。
这是重构后的代码:
void
mixing(void *unused, Uint8 *stream, int len)
{
Uint32 amount;
// NOTE/DEBUG: force sound on
#if 1
playing = 1;
#endif
// NOTE/FIX: zero out stream data so we don't mix in random data (from the
// prior round)
#if 1
memset(stream,0,len);
#endif
if (playing) {
amount = sound.dlen - sound.dpos;
if (amount > len) {
amount = len;
}
#if 1
SDL_MixAudio(stream, &sound.data[sound.dpos], amount, SDL_MIX_MAXVOLUME);
#else
memcpy(stream,&sound.data[sound.dpos],amount);
#endif
sound.dpos += amount;
// NOTE/FIX(?) -- start wav at beginning after all data has been output
#if 1
if (sound.dpos >= sound.dlen)
sound.dpos = 0;
#endif
}
}
我正在编写这个简单的程序来学习如何使用 SDL 处理音频。该程序打开一个 window,其中有一个按钮,上面写着开始,当您按下按钮时,它应该播放鼓样本的 WAV。没有错误,程序也没有崩溃,只是它没有播放鼓声,而是发出奇怪的嗡嗡声,直到您退出程序才停止。我认为这与音频回调函数有关,但我对此很陌生,所以我不确定它到底是如何工作的。
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
#include <SDL2/SDL_audio.h>
TTF_Font* font;
SDL_Color white = {255, 255, 255};
SDL_AudioSpec frmt;
bool run = true;
bool playing = false;
struct sample
{
Uint8 *data;
Uint32 dpos;
Uint32 dlen;
} sound;
bool buttonPress(int x, int y, SDL_Rect r)
{
if (x < (r.x + r.w) && x > r.x)
{
if (y < (r.y + r.h) && y > r.y)
{
return true;
}
}
return false;
}
void mixing(void *unused, Uint8 *stream, int len)
{
Uint32 amount;
if (playing)
{
amount = sound.dlen - sound.dpos;
if ( amount > len ) {
amount = len;
}
SDL_MixAudio(stream, &sound.data[sound.dpos], amount, SDL_MIX_MAXVOLUME);
sound.dpos += amount;
}
}
int main(int argc, char *argv[])
{
SDL_Init(SDL_INIT_EVERYTHING);
TTF_Init();
frmt.channels = 1;
frmt.format = AUDIO_S16;
frmt.freq = 22050;
frmt.samples = 512;
frmt.userdata = NULL;
frmt.callback = mixing;
int mX, mY;
Uint32 fpsTimer = SDL_GetTicks();
font = TTF_OpenFont("octaFont.TTF", 20);
SDL_Window* window = SDL_CreateWindow("Test", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 400, 200, 0);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
SDL_Surface* surface = TTF_RenderText_Solid(font, "Go!", white);
SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);
SDL_Rect button;
button.w = 50;
button.h = 35;
button.x = 10;
button.y = 10;
SDL_Rect bg;
bg.w = 400;
bg.h = 200;
bg.x = 0;
bg.y = 0;
SDL_Event e;
if (SDL_OpenAudio(&frmt, NULL) < 0)
{
fprintf(stderr, "Unable to open audio: %s\n", SDL_GetError());
return 1;
}
SDL_PauseAudio(0);
SDL_AudioSpec wave;
SDL_AudioCVT cvt;
Uint8 *data;
Uint32 dlen;
if (SDL_LoadWAV("sound.wav", &wave, &data, &dlen) == NULL)
{
fprintf(stderr, "Unable to load wave: %s\n", SDL_GetError());
return 1;
}
SDL_BuildAudioCVT(&cvt, wave.format, wave.channels, wave.freq, AUDIO_S16, 1, 22050);
cvt.buf = malloc(dlen*cvt.len_mult);
memcpy(cvt.buf, data, dlen);
cvt.len = dlen;
SDL_ConvertAudio(&cvt);
SDL_FreeWAV(data);
SDL_LockAudio();
free(sound.data);
sound.data = cvt.buf;
sound.dlen = cvt.len_cvt;
sound.dpos = 0;
SDL_UnlockAudio();
while (run)
{
while (SDL_PollEvent(&e))
{
switch (e.type)
{
case SDL_QUIT:
run = false;
break;
case SDL_KEYDOWN:
switch (e.key.keysym.sym)
{
case SDLK_SPACE:
playing = false;
break;
default:
break;
}
break;
case SDL_MOUSEBUTTONDOWN:
SDL_GetMouseState(&mX, &mY);
if (buttonPress(mX, mY, button))
{
playing = true;
}
break;
default:
break;
}
}
if (SDL_GetTicks() - fpsTimer >= 16)
{
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderFillRect(renderer, &bg);
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderDrawRect(renderer, &button);
SDL_RenderCopy(renderer, texture, NULL, &button);
SDL_RenderPresent(renderer);
fpsTimer = SDL_GetTicks();
}
}
SDL_CloseAudio();
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
TTF_Quit();
SDL_Quit();
return 0;
}
问题可能在于您正在使用 SDL_MixAudio
。
您的代码混入了 .wav
文件中的数据,但混入了什么?
stream
在调用SDL_MixAudio
之前是什么?
我得到同样的嗡嗡声,但是当我使用 memset
将 stream
缓冲区清零时 在 调用 SDL_MixAudio
之前,我得到来自 .wav
文件的正确声音。
我不确定,但我相信在对您的 mixing
函数的第二次和后续调用中,来自 prior 回调的数据仍在stream
缓冲区。
旁注:当.wav
数据播放完毕后,我们可以重置sound.dpos
重新播放文件。
这是重构后的代码:
void
mixing(void *unused, Uint8 *stream, int len)
{
Uint32 amount;
// NOTE/DEBUG: force sound on
#if 1
playing = 1;
#endif
// NOTE/FIX: zero out stream data so we don't mix in random data (from the
// prior round)
#if 1
memset(stream,0,len);
#endif
if (playing) {
amount = sound.dlen - sound.dpos;
if (amount > len) {
amount = len;
}
#if 1
SDL_MixAudio(stream, &sound.data[sound.dpos], amount, SDL_MIX_MAXVOLUME);
#else
memcpy(stream,&sound.data[sound.dpos],amount);
#endif
sound.dpos += amount;
// NOTE/FIX(?) -- start wav at beginning after all data has been output
#if 1
if (sound.dpos >= sound.dlen)
sound.dpos = 0;
#endif
}
}