2012-04-11 6 views
6

Mam problemy ze zrozumieniem, jak działa część audio biblioteki sdl teraz, wiem, że po jej inicjalizacji, musisz określić częstotliwość i funkcję >> callback < < , które według mnie są następnie wywoływane automatycznie przy danej częstotliwości. Czy ktokolwiek, kto pracował z biblioteką sdl, napisał prosty przykład, który użyłby sdl_audio do wygenerowania fali prostokątnej 440 Hz (ponieważ jest to najprostszy przebieg) przy częstotliwości próbkowania 44000 Hz?Generator prostych fal dźwiękowych z SDL w C++

+0

Jest to całkiem ładny przykład, imo: http://www.libsdl.org/intro.en/usingsound.html – jrok

+0

@jrok poprawić swój komentarz i sprawiają, że jest to odpowiedź. Miłe odniesienie. – karlphillip

+0

@karlphillip Tam, mam nadzieję, że to się liczy jako poprawa;) – jrok

Odpowiedz

13

The Introduction to SDL ma schludny przykład użycia biblioteki SDL dźwięk, który powinien na początek: http://www.libsdl.org/intro.en/usingsound.html

EDIT: Oto program roboczy, który ma co prosiłeś. Zmodyfikowałem trochę kod tutaj: http://www.dgames.org/beep-sound-with-sdl/

#include <SDL/SDL.h> 
#include <SDL/SDL_audio.h> 
#include <queue> 
#include <cmath> 

const int AMPLITUDE = 28000; 
const int FREQUENCY = 44100; 

struct BeepObject 
{ 
    double freq; 
    int samplesLeft; 
}; 

class Beeper 
{ 
private: 
    double v; 
    std::queue<BeepObject> beeps; 
public: 
    Beeper(); 
    ~Beeper(); 
    void beep(double freq, int duration); 
    void generateSamples(Sint16 *stream, int length); 
    void wait(); 
}; 

void audio_callback(void*, Uint8*, int); 

Beeper::Beeper() 
{ 
    SDL_AudioSpec desiredSpec; 

    desiredSpec.freq = FREQUENCY; 
    desiredSpec.format = AUDIO_S16SYS; 
    desiredSpec.channels = 1; 
    desiredSpec.samples = 2048; 
    desiredSpec.callback = audio_callback; 
    desiredSpec.userdata = this; 

    SDL_AudioSpec obtainedSpec; 

    // you might want to look for errors here 
    SDL_OpenAudio(&desiredSpec, &obtainedSpec); 

    // start play audio 
    SDL_PauseAudio(0); 
} 

Beeper::~Beeper() 
{ 
    SDL_CloseAudio(); 
} 

void Beeper::generateSamples(Sint16 *stream, int length) 
{ 
    int i = 0; 
    while (i < length) { 

     if (beeps.empty()) { 
      while (i < length) { 
       stream[i] = 0; 
       i++; 
      } 
      return; 
     } 
     BeepObject& bo = beeps.front(); 

     int samplesToDo = std::min(i + bo.samplesLeft, length); 
     bo.samplesLeft -= samplesToDo - i; 

     while (i < samplesToDo) { 
      stream[i] = AMPLITUDE * std::sin(v * 2 * M_PI/FREQUENCY); 
      i++; 
      v += bo.freq; 
     } 

     if (bo.samplesLeft == 0) { 
      beeps.pop(); 
     } 
    } 
} 

void Beeper::beep(double freq, int duration) 
{ 
    BeepObject bo; 
    bo.freq = freq; 
    bo.samplesLeft = duration * FREQUENCY/1000; 

    SDL_LockAudio(); 
    beeps.push(bo); 
    SDL_UnlockAudio(); 
} 

void Beeper::wait() 
{ 
    int size; 
    do { 
     SDL_Delay(20); 
     SDL_LockAudio(); 
     size = beeps.size(); 
     SDL_UnlockAudio(); 
    } while (size > 0); 

} 

void audio_callback(void *_beeper, Uint8 *_stream, int _length) 
{ 
    Sint16 *stream = (Sint16*) _stream; 
    int length = _length/2; 
    Beeper* beeper = (Beeper*) _beeper; 

    beeper->generateSamples(stream, length); 
} 

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

    int duration = 1000; 
    double Hz = 440; 

    Beeper b; 
    b.beep(Hz, duration); 
    b.wait(); 

    return 0; 
} 

Powodzenia.

+0

dzięki, ale wciąż nie mogę tego zrozumieć. Jestem absolutnie początkujący w tej bibliotece. Zanim zadałem pytanie tutaj, szukałem, czy ktoś zadał to samo pytanie, ale wszystkie znalazłem tylko części kodu. Jestem pewien, że program, który robi to, o co prosiłem, byłby naprawdę krótki. –

+0

@Vlad Zaktualizowano odpowiedź. – jrok

+0

Dzięki za to! w międzyczasie próbowałem coś napisać i dostałem to: http: //docpaste.com/show.php? id = 231. Fala kwadratowa jest słyszalna, ale ma na sobie dużo hałasu. Nie jest to cichy hałas, prawie pokrywa cały dźwięk. jaki może być problem? –

2

2.0.2 Przykład C

albumu: https://codereview.stackexchange.com/questions/41086/play-some-sine-waves-with-sdl2

#include <stdio.h> 
#include <stdlib.h> 
#include <math.h> 
#include <SDL2/SDL.h> 

const double ChromaticRatio = 1.059463094359295264562; 
const double Tao = 6.283185307179586476925; 

Uint32 sampleRate = 48000; 
Uint32 frameRate = 60; 
Uint32 floatStreamLength = 1024; 
Uint32 samplesPerFrame; 
Uint32 msPerFrame; 
double practicallySilent = 0.001; 

Uint32 audioBufferLength = 48000; 
float *audioBuffer; 

SDL_atomic_t audioCallbackLeftOff; 
Sint32 audioMainLeftOff; 
Uint8 audioMainAccumulator; 

SDL_AudioDeviceID AudioDevice; 
SDL_AudioSpec audioSpec; 

SDL_Event event; 
SDL_bool running = SDL_TRUE; 

typedef struct { 
    float *waveform; 
    Uint32 waveformLength; 
    double volume; 
    double pan; 
    double frequency; 
    double phase; 
} voice; 

void speak(voice *v) { 
    float sample; 
    Uint32 sourceIndex; 
    double phaseIncrement = v->frequency/sampleRate; 
    Uint32 i; 
    if (v->volume > practicallySilent) { 
     for (i = 0; (i + 1) < samplesPerFrame; i += 2) { 
      v->phase += phaseIncrement; 
      if (v->phase > 1) 
       v->phase -= 1; 

      sourceIndex = v->phase*v->waveformLength; 
      sample = v->waveform[sourceIndex]*v->volume; 

      audioBuffer[audioMainLeftOff+i] += sample*(1-v->pan); 
      audioBuffer[audioMainLeftOff+i+1] += sample*v->pan; 
     } 
    } 
    else { 
     for (i=0; i<samplesPerFrame; i+=1) 
      audioBuffer[audioMainLeftOff+i] = 0; 
    } 
    audioMainAccumulator++; 
} 

double getFrequency(double pitch) { 
    return pow(ChromaticRatio, pitch-57)*440; 
} 

int getWaveformLength(double pitch) { 
    return sampleRate/getFrequency(pitch)+0.5f; 
} 

void buildSineWave(float *data, Uint32 length) { 
    Uint32 i; 
    for (i=0; i < length; i++) 
     data[i] = sin(i*(Tao/length)); 
} 

void logSpec(SDL_AudioSpec *as) { 
    printf(
     " freq______%5d\n" 
     " format____%5d\n" 
     " channels__%5d\n" 
     " silence___%5d\n" 
     " samples___%5d\n" 
     " size______%5d\n\n", 
     (int) as->freq, 
     (int) as->format, 
     (int) as->channels, 
     (int) as->silence, 
     (int) as->samples, 
     (int) as->size 
    ); 
} 

void logVoice(voice *v) { 
    printf(
     " waveformLength__%d\n" 
     " volume__________%f\n" 
     " pan_____________%f\n" 
     " frequency_______%f\n" 
     " phase___________%f\n", 
     v->waveformLength, 
     v->volume, 
     v->pan, 
     v->frequency, 
     v->phase 
    ); 
} 

void logWavedata(float *floatStream, Uint32 floatStreamLength, Uint32 increment) { 
    printf("\n\nwaveform data:\n\n"); 
    Uint32 i=0; 
    for (i = 0; i < floatStreamLength; i += increment) 
     printf("%4d:%2.16f\n", i, floatStream[i]); 
    printf("\n\n"); 
} 

void audioCallback(void *unused, Uint8 *byteStream, int byteStreamLength) { 
    float* floatStream = (float*) byteStream; 
    Sint32 localAudioCallbackLeftOff = SDL_AtomicGet(&audioCallbackLeftOff); 
    Uint32 i; 
    for (i = 0; i < floatStreamLength; i++) { 
     floatStream[i] = audioBuffer[localAudioCallbackLeftOff]; 
     localAudioCallbackLeftOff++; 
     if (localAudioCallbackLeftOff == audioBufferLength) 
      localAudioCallbackLeftOff = 0; 
    } 
    SDL_AtomicSet(&audioCallbackLeftOff, localAudioCallbackLeftOff); 
} 

int init(void) { 
    SDL_Init(SDL_INIT_AUDIO | SDL_INIT_TIMER); 
    SDL_AudioSpec want; 
    SDL_zero(want); 

    want.freq = sampleRate; 
    want.format = AUDIO_F32; 
    want.channels = 2; 
    want.samples = floatStreamLength; 
    want.callback = audioCallback; 

    AudioDevice = SDL_OpenAudioDevice(NULL, 0, &want, &audioSpec, SDL_AUDIO_ALLOW_FORMAT_CHANGE); 
    if (AudioDevice == 0) { 
     printf("\nFailed to open audio: %s\n", SDL_GetError()); 
     return 1; 
    } 

    printf("want:\n"); 
    logSpec(&want); 
    printf("audioSpec:\n"); 
    logSpec(&audioSpec); 

    if (audioSpec.format != want.format) { 
     printf("\nCouldn't get Float32 audio format.\n"); 
     return 2; 
    } 

    sampleRate = audioSpec.freq; 
    floatStreamLength = audioSpec.size/4; 
    samplesPerFrame = sampleRate/frameRate; 
    msPerFrame = 1000/frameRate; 
    audioMainLeftOff = samplesPerFrame * 8; 
    SDL_AtomicSet(&audioCallbackLeftOff, 0); 

    if (audioBufferLength % samplesPerFrame) 
     audioBufferLength += samplesPerFrame - (audioBufferLength % samplesPerFrame); 
    audioBuffer = malloc(sizeof(float) * audioBufferLength); 

    return 0; 
} 

int onExit(void) { 
    SDL_CloseAudioDevice(AudioDevice); 
    SDL_Quit(); 
    return 0; 
} 

int main(int argc, char *argv[]) { 
    float syncCompensationFactor = 0.0016; 
    Sint32 mainAudioLead; 
    Uint32 i; 

    voice testVoiceA; 
    voice testVoiceB; 
    voice testVoiceC; 
    testVoiceA.volume = 1; 
    testVoiceB.volume = 1; 
    testVoiceC.volume = 1; 
    testVoiceA.pan = 0.5; 
    testVoiceB.pan = 0; 
    testVoiceC.pan = 1; 
    testVoiceA.phase = 0; 
    testVoiceB.phase = 0; 
    testVoiceC.phase = 0; 
    testVoiceA.frequency = getFrequency(45); 
    testVoiceB.frequency = getFrequency(49); 
    testVoiceC.frequency = getFrequency(52); 
    Uint16 C0waveformLength = getWaveformLength(0); 
    testVoiceA.waveformLength = C0waveformLength; 
    testVoiceB.waveformLength = C0waveformLength; 
    testVoiceC.waveformLength = C0waveformLength; 
    float sineWave[C0waveformLength]; 
    buildSineWave(sineWave, C0waveformLength); 
    testVoiceA.waveform = sineWave; 
    testVoiceB.waveform = sineWave; 
    testVoiceC.waveform = sineWave; 

    if (init()) 
     return 1; 

    SDL_Delay(42); 
    SDL_PauseAudioDevice(AudioDevice, 0); 
    while (running) { 
     while (SDL_PollEvent(&event) != 0) { 
      if (event.type == SDL_QUIT) { 
       running = SDL_FALSE; 
      } 
     } 
     for (i = 0; i < samplesPerFrame; i++) 
      audioBuffer[audioMainLeftOff+i] = 0; 
     speak(&testVoiceA); 
     speak(&testVoiceB); 
     speak(&testVoiceC); 
     if (audioMainAccumulator > 1) { 
      for (i=0; i<samplesPerFrame; i++) { 
       audioBuffer[audioMainLeftOff+i] /= audioMainAccumulator; 
      } 
     } 
     audioMainAccumulator = 0; 
     audioMainLeftOff += samplesPerFrame; 
     if (audioMainLeftOff == audioBufferLength) 
      audioMainLeftOff = 0; 
     mainAudioLead = audioMainLeftOff - SDL_AtomicGet(&audioCallbackLeftOff); 
     if (mainAudioLead < 0) 
      mainAudioLead += audioBufferLength; 
     if (mainAudioLead < floatStreamLength) 
      printf("An audio collision may have occured!\n"); 
     SDL_Delay(mainAudioLead * syncCompensationFactor); 
    } 
    onExit(); 
    return 0; 
} 

Testowane Ubuntu 15.10.

powinien być łatwy do przekształcić prosty fortepian z: https://github.com/cirosantilli/cpp-cheat/blob/f734a2e76fbcfc67f707ae06be7a2a2ef5db47d1/c/interactive/audio_gen.c#L44

do manipulacji wav, sprawdź również oficjalne przykłady:

0

gotowane -down wariant sygnału dźwiękowego-przykład, zredukowany do absolutnego minimum (z obsługą błędów).

#include <math.h> 
#include <SDL.h> 
#include <SDL_audio.h> 

const int AMPLITUDE = 28000; 
const int SAMPLE_RATE = 44100; 

void audio_callback(void *user_data, Uint8 *raw_buffer, int bytes) 
{ 
    Sint16 *buffer = (Sint16*)raw_buffer; 
    int length = bytes/2; // 2 bytes per sample for AUDIO_S16SYS 
    int &sample_nr(*(int*)user_data); 

    for(int i = 0; i < length; i++, sample_nr++) 
    { 
     double time = (double)sample_nr/(double)SAMPLE_RATE; 
     buffer[i] = (Sint16)(AMPLITUDE * sin(2.0f * M_PI * 441.0f * time)); // render 441 HZ sine wave 
    } 
} 

int main(int argc, char *argv[]) 
{ 
    if(SDL_Init(SDL_INIT_AUDIO) != 0) SDL_Log("Failed to initialize SDL: %s", SDL_GetError()); 

    int sample_nr = 0; 

    SDL_AudioSpec want; 
    want.freq = SAMPLE_RATE; // number of samples per second 
    want.format = AUDIO_S16SYS; // sample type (here: signed short i.e. 16 bit) 
    want.channels = 1; // only one channel 
    want.samples = 2048; // buffer-size 
    want.callback = audio_callback; // function SDL calls periodically to refill the buffer 
    want.userdata = &sample_nr; // counter, keeping track of current sample number 

    SDL_AudioSpec have; 
    if(SDL_OpenAudio(&want, &have) != 0) SDL_LogError(SDL_LOG_CATEGORY_AUDIO, "Failed to open audio: %s", SDL_GetError()); 
    if(want.format != have.format) SDL_LogError(SDL_LOG_CATEGORY_AUDIO, "Failed to get the desired AudioSpec"); 

    SDL_PauseAudio(0); // start playing sound 
    SDL_Delay(1000); // wait while sound is playing 
    SDL_PauseAudio(1); // stop playing sound 

    SDL_CloseAudio(); 

    return 0; 
}