Трудности с получением чисто синусоидальной волны (в настоящее время она имеет тонкую частоту) - PullRequest
0 голосов
/ 05 октября 2019

Я пытаюсь воспроизвести чистую синусоидальную волну в 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);
}

РЕДАКТИРОВАТЬ2: Я записал звук, который я слышу здесь (возможно, необходимо увеличить громкость, чтобы услышать проблему): https://www.youtube.com/watch?v=-V2IMhK2Zis&feature=youtu.be

Я также провел проверку синхронизации и получал ее обратно для каждого прогона функции AudioCallback: https://imgur.com/a/9pqCte0

EDIT3: показания осциллографа -

Моя синусоида: Impure sine wave

Чистая синусоида: Pure sine wave

(Я не вижу заметной разницы, но, может быть, кто-то другой может?) Редактировать:Ой, подождите, на левой стороне осциллографае, есть четкие различия между двумя сигналами (хотя они не отображаются в основном показании). Попытка выяснить, в чем проблема - на данный момент я все еще не уверен, так как я попробовал несколько различных алгоритмов

РЕДАКТИРОВАТЬ4: Вот изображение Хотите / Должен показать, что все (кроме размера) являетсято же самое после вызова SDL_OpenAudioDevice:

Want vs Have

EDIT5: Проблема (вроде) решена! Установка AudioUserData.SamplesPerSecond в значение 48000 привела к чистой синусоиде. Но вопрос все еще стоит: почему он работает только на 48000 ??

...