gpt4 book ai didi

c++ - 使用 SDL2 播放正弦声波 - 噪音/抓取问题

转载 作者:搜寻专家 更新时间:2023-10-31 01:38:07 34 4
gpt4 key购买 nike

我的目标是创建一个 SDL 窗口,绘制不同的波形并播放该波的不确定声音。通过按下特定的键,可以修改波的幅度、频率或波形等参数。

问题在于,即使是绘制时看起来不错的简单正弦波,听起来也很嘈杂。我不明白为什么。

代码:

#include "Graph.h"
#include <thread>
#include <iostream>
#include <sstream>
#include <string>


int main(int argc, char* argv[]){

Graph* g = new Graph();

int i;
std::cin >> i;
return 0;
}

int graphThreadFunc(void *pointer){
Graph* grid = (Graph*)pointer;
grid->init();

return 0;
}



// SDL calls this function whenever it wants its buffer to be filled with samples
void SDLAudioCallback(void *data, Uint8 *buffer, int length){
uint8_t *stream = (uint8_t*)buffer;

Graph* graph = (Graph*)data;


for (int i = 0; i <= length; i++){

if (graph->voice.audioLength <= 0)
stream[i] = graph->getSpec()->silence; // 128 is silence in a uint8 stream
else
{
stream[i] = graph->voice.getSample();
graph->voice.audioPosition++;


// Fill the graphBuffer with the first 1000 bytes of the wave for plotting
if (graph->graphPointer < 999)
graph->graphBuffer[graph->graphPointer++] = stream[i];

}


}
}


Graph::Graph()
{
// spawn thread
SDL_Thread *refresh_thread = SDL_CreateThread(graphThreadFunc, NULL, this);
}

SDL_AudioSpec* Graph::getSpec(){
return &this->spec;
}


void Graph::init()
{
// Init SDL & SDL_ttf
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER);
SDL_zero(desiredDeviceSpec);

desiredDeviceSpec.freq = 44100; // Sample Rate
desiredDeviceSpec.format = AUDIO_U8; // Unsigned 8-Bit Samples
desiredDeviceSpec.channels = 1; // Mono
desiredDeviceSpec.samples = 2048; // The size of the Audio Buffer (in number of samples, eg: 2048 * 1 Byte (AUDIO_U8)
desiredDeviceSpec.callback = SDLAudioCallback;
desiredDeviceSpec.userdata = this;


dev = SDL_OpenAudioDevice(NULL, 0, &desiredDeviceSpec, &spec, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE);
if (dev == 0) {
printf("\nFailed to open audio: %s\n", SDL_GetError());
}
else {
SDL_PauseAudioDevice(dev, 1); /* pause! */
SDL_PauseAudio(1);
}

// Create an application window with the following settings:
window = SDL_CreateWindow(
WINDOW_TITLE.c_str(), // window title
SDL_WINDOWPOS_UNDEFINED, // initial x position
SDL_WINDOWPOS_UNDEFINED, // initial y position
WINDOW_WIDTH, // width, in pixels
WINDOW_HEIGHT, // height, in pixels
SDL_WINDOW_SHOWN // flags - see below
);

// Check if the window was successfully created
if (window == NULL) {
// In case the window could not be created...
printf("Could not create window: %s\n", SDL_GetError());
return;
}
else{
voice.waveForm = Graph::Voice::WaveForm::SINE;
voice.amp = 120;
voice.frequency = 440;
SDL_PauseAudioDevice(dev, 1); // play
graphPointer = 0;

voice.audioLength = 44100;
voice.audioPosition = 0;

SDL_PauseAudioDevice(dev, 0); // play
SDL_Delay(200);

drawGraph();


mainLoop();
return;
}
}

void Graph::mainLoop()
{
while (thread_exit == 0){
SDL_Event event;
bool hasChanged = false;

while (SDL_PollEvent(&event)) {
switch (event.type)
{
case SDL_KEYDOWN:
{
hasChanged = true;

if (event.key.keysym.scancode == SDL_SCANCODE_SPACE){
//pause_thread = !pause_thread;
switch (voice.waveForm){
case Voice::SINE:
{
voice.waveForm = Graph::Voice::WaveForm::TRIANGLE;
break;
}
case Voice::TRIANGLE:
{
voice.waveForm = Graph::Voice::WaveForm::RECT;
break;
}
case Voice::RECT:
{
voice.waveForm = Graph::Voice::WaveForm::SAWTOOTH;
break;
}
case Voice::SAWTOOTH:
{
voice.waveForm = Graph::Voice::WaveForm::SINE;
break;
}
default:
break;
}
}
else if (event.key.keysym.scancode == SDL_SCANCODE_ESCAPE){
exit();
}
else if (event.key.keysym.scancode == SDL_SCANCODE_RETURN){

}
else if (event.key.keysym.scancode == SDL_SCANCODE_LEFT){
voice.frequency -= 2;
}
else if (event.key.keysym.scancode == SDL_SCANCODE_RIGHT){
voice.frequency += 2;
}
else if (event.key.keysym.scancode == SDL_SCANCODE_UP){
voice.amp += 2;
}
else if (event.key.keysym.scancode == SDL_SCANCODE_DOWN){
voice.amp -= 2;
}
else{

}

break;
}

case SDL_QUIT:
{
exit();
return;
break;
}
default: /* unhandled event */
break;
}
}

if (!pause_thread && hasChanged)
{

//SDL_PauseAudioDevice(dev, 1); // play
graphPointer = 0;

voice.audioLength = 44100;
voice.audioPosition = 0;

SDL_PauseAudioDevice(dev, 0); // play
SDL_Delay(200);

drawGraph();
}


//voice.waveForm = Voice::WaveForm::TRIANGLE;

//SDL_Delay(n); // delay the program to prevent the voice to be overridden before it has been played to the end
//SDL_PauseAudioDevice(dev, 1); // pause

SDL_Delay(REFRESH_INTERVAL);
//SDL_PauseAudioDevice(dev, 1); // pause
}


return;
}

void Graph::drawGraph()
{

SDL_Renderer *renderer = SDL_GetRenderer(window);
if (renderer == nullptr)
renderer = SDL_CreateRenderer(window, 0, SDL_RENDERER_ACCELERATED);

// Set background color
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);

// Clear winow
SDL_RenderClear(renderer);


SDL_SetRenderDrawColor(renderer, 22, 22, 22, 255);
for (int x = 0; x < WINDOW_WIDTH; x++){
uint8_t y = graphBuffer[x];
SDL_RenderDrawPoint(renderer, x, WINDOW_HEIGHT - y);
}


SDL_RenderPresent(renderer);


return;
}

void Graph::exit(){
thread_exit = 1;
// Close and destroy the window
SDL_DestroyWindow(window);
// Clean up
SDL_Quit();
}


uint8_t Graph::Voice::getSample(){
switch (waveForm){
case SINE:
{
float sineStep = 2 * M_PI * audioPosition * frequency / 44100;
return (amp * sin(sineStep)) + 128;
break;
}
case RECT:
break;

case SAWTOOTH:
break;

case TRIANGLE:
break;

default:
return 0;
}
}

和头文件:

#ifndef GRAPH_H
#define GRAPH_H
#include "SDL.h"
#include "SDL_audio.h"
#include <stdio.h>
#include <cmath>
#include <string>
#include <stack>

/* Constants */
const int REFRESH_INTERVAL = 50; // mseconds
const int WINDOW_WIDTH = 1000;
const int WINDOW_HEIGHT = 255;
const std::string WINDOW_TITLE = "Wave Graph";

class Graph
{
private:
SDL_Window *window; // Declare a pointer

// SDL audio stuff
SDL_AudioSpec desiredDeviceSpec;
SDL_AudioSpec spec;
SDL_AudioDeviceID dev;

int thread_exit = 0;
bool pause_thread = false;

public:
Graph();
void init();
void mainLoop();
void drawGraph();

void exit();
SDL_AudioSpec* getSpec();

struct Voice{
int frequency; // the frequency of the voice
int amp; // the amplitude of the voice

int audioLength; // number of samples to be played, eg: 1.2 seconds * 44100 samples per second
int audioPosition = 0; // counter

enum WaveForm{
SINE = 0, RECT = 1, SAWTOOTH = 2, TRIANGLE = 3
} waveForm;


uint8_t getSample();
} voice;
int graphPointer = 0;
uint8_t graphBuffer[1000];


};


#endif

最佳答案

你的 SDLAudioCallback()buffer 的末尾写一个额外的字节:

void SDLAudioCallback(void *data, Uint8 *buffer, int length)
{
...
for (int i = 0; i <= length; i++)
// ^^ huh?
{
...
}
}

改变 <=只是<修复了我系统上的噼啪声。

通常 C 风格的“字节指针 + 长度”API 期望左闭右开区间:[0, length) .即,您可以访问 buffer[length - 1]但不是 buffer[length] .

关于c++ - 使用 SDL2 播放正弦声波 - 噪音/抓取问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33274511/

34 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com